Phase 12.7: Nyash文法革命とANCP 90%圧縮技法の発見 - 文法改革完了とFunctionBox実装

This commit is contained in:
Moe Charm
2025-09-03 20:03:45 +09:00
parent 6d79d7d3ac
commit 7455c9ec97
69 changed files with 3817 additions and 62 deletions

View File

@ -243,7 +243,7 @@ impl NyashInterpreter {
}
/// 🔥 厳密変数設定: 明示的宣言のみ許可 - Everything is Box哲学
pub(super) fn set_variable(&mut self, name: &str, value: Box<dyn NyashBox>) -> Result<(), RuntimeError> {
pub(crate) fn set_variable(&mut self, name: &str, value: Box<dyn NyashBox>) -> Result<(), RuntimeError> {
let shared_value = Arc::from(value); // Convert Box to Arc
// 1. outbox変数が存在する場合は更新
@ -278,7 +278,7 @@ impl NyashInterpreter {
}
/// local変数を宣言関数内でのみ有効
pub(super) fn declare_local_variable(&mut self, name: &str, value: Box<dyn NyashBox>) {
pub(crate) fn declare_local_variable(&mut self, name: &str, value: Box<dyn NyashBox>) {
// Pass-by-share for plugin handle types; by-value (clone) semantics can be applied at call sites
#[allow(unused_mut)]
let mut store_value = value;
@ -292,7 +292,7 @@ impl NyashInterpreter {
}
/// outbox変数を宣言static関数内で所有権移転
pub(super) fn declare_outbox_variable(&mut self, name: &str, value: Box<dyn NyashBox>) {
pub(crate) fn declare_outbox_variable(&mut self, name: &str, value: Box<dyn NyashBox>) {
#[allow(unused_mut)]
let mut store_value = value;
#[cfg(all(feature = "plugins", not(target_arch = "wasm32")))]

View File

@ -13,15 +13,113 @@ mod access;
mod builtins;
use super::*;
use std::sync::Arc;
// Direct implementation approach to avoid import issues
// TODO: Fix NullBox import issue later
// use crate::NullBox;
impl NyashInterpreter {
/// Build closure environment by capturing 'me' and free variables by value (P1)
fn build_closure_env(&mut self, params: &Vec<String>, body: &Vec<ASTNode>) -> Result<crate::boxes::function_box::ClosureEnv, RuntimeError> {
use std::collections::{HashSet, VecDeque};
let mut env = crate::boxes::function_box::ClosureEnv::new();
// Capture 'me' if bound
if let Ok(mev) = self.resolve_variable("me") { env.me_value = Some(Arc::downgrade(&mev)); }
// Collect free variables
let mut used: HashSet<String> = HashSet::new();
let mut locals: HashSet<String> = HashSet::new();
// params are considered local
for p in params { locals.insert(p.clone()); }
// BFS walk statements
fn collect(node: &ASTNode, used: &mut HashSet<String>, locals: &mut HashSet<String>) {
match node {
ASTNode::Variable { name, .. } => {
if !locals.contains(name) && name != "me" && name != "this" { used.insert(name.clone()); }
}
ASTNode::Local { variables, .. } => { for v in variables { locals.insert(v.clone()); } }
ASTNode::Assignment { target, value, .. } => { collect(target, used, locals); collect(value, used, locals); }
ASTNode::BinaryOp { left, right, .. } => { collect(left, used, locals); collect(right, used, locals); }
ASTNode::UnaryOp { operand, .. } => { collect(operand, used, locals); }
ASTNode::MethodCall { object, arguments, .. } => { collect(object, used, locals); for a in arguments { collect(a, used, locals);} }
ASTNode::FunctionCall { arguments, .. } => { for a in arguments { collect(a, used, locals);} }
ASTNode::Call { callee, arguments, .. } => { collect(callee, used, locals); for a in arguments { collect(a, used, locals);} }
ASTNode::FieldAccess { object, .. } => { collect(object, used, locals); }
ASTNode::New { arguments, .. } => { for a in arguments { collect(a, used, locals);} }
ASTNode::If { condition, then_body, else_body, .. } => {
collect(condition, used, locals);
for st in then_body { collect(st, used, locals); }
if let Some(eb) = else_body { for st in eb { collect(st, used, locals); } }
}
ASTNode::Loop { condition, body, .. } => { collect(condition, used, locals); for st in body { collect(st, used, locals);} }
ASTNode::TryCatch { try_body, catch_clauses, finally_body, .. } => {
for st in try_body { collect(st, used, locals); }
for c in catch_clauses { for st in &c.body { collect(st, used, locals); } }
if let Some(fb) = finally_body { for st in fb { collect(st, used, locals); } }
}
ASTNode::Throw { expression, .. } => { collect(expression, used, locals); }
ASTNode::Print { expression, .. } => { collect(expression, used, locals); }
ASTNode::Return { value, .. } => { if let Some(v) = value { collect(v, used, locals); } }
ASTNode::AwaitExpression { expression, .. } => { collect(expression, used, locals); }
ASTNode::PeekExpr { scrutinee, arms, else_expr, .. } => {
collect(scrutinee, used, locals);
for (_, e) in arms { collect(e, used, locals); }
collect(else_expr, used, locals);
}
ASTNode::Program { statements, .. } => { for st in statements { collect(st, used, locals); } }
ASTNode::FunctionDeclaration { params, body, .. } => {
let mut inner = locals.clone();
for p in params { inner.insert(p.clone()); }
for st in body { collect(st, used, &mut inner); }
}
_ => {}
}
}
for st in body { collect(st, &mut used, &mut locals); }
// Materialize captures: local by-ref via RefCellBox, others by-value
for name in used.into_iter() {
if let Some(local_arc) = self.local_vars.get(&name) {
let lb: &dyn NyashBox = &**local_arc;
// If already RefCellBox, reuse inner; else wrap and replace local binding
if let Some(rc) = lb.as_any().downcast_ref::<crate::boxes::ref_cell_box::RefCellBox>() {
env.captures.insert(name.clone(), rc.share_box());
} else {
// wrap existing into RefCell and replace local binding
let wrapped = crate::boxes::ref_cell_box::RefCellBox::new(lb.clone_box());
self.local_vars.insert(name.clone(), wrapped.clone_arc());
env.captures.insert(name, wrapped.share_box());
}
} else {
// non-local (global/static): by-value capture
if let Ok(v) = self.resolve_variable(&name) { env.captures.insert(name, v.clone_or_share()); }
}
}
Ok(env)
}
/// 式を実行 - Expression evaluation engine
pub(super) fn execute_expression(&mut self, expression: &ASTNode) -> Result<Box<dyn NyashBox>, RuntimeError> {
match expression {
// P1: allow block (Program) as expression; value = last statement's value
ASTNode::Program { statements, .. } => {
let mut result: Box<dyn NyashBox> = Box::new(VoidBox::new());
let last = statements.len().saturating_sub(1);
for (i, st) in statements.iter().enumerate() {
let prev = self.discard_context;
self.discard_context = i != last;
result = self.execute_statement(st)?;
self.discard_context = prev;
match &self.control_flow {
ControlFlow::Break => { return Err(RuntimeError::BreakOutsideLoop); }
ControlFlow::Continue => { return Err(RuntimeError::BreakOutsideLoop); }
ControlFlow::Return(_) => { return Err(RuntimeError::ReturnOutsideFunction); }
ControlFlow::Throw(_) => { return Err(RuntimeError::UncaughtException); }
ControlFlow::None => {}
}
}
Ok(result)
}
ASTNode::Literal { value, .. } => {
Ok(value.to_nyash_box())
}
@ -125,10 +223,84 @@ impl NyashInterpreter {
ASTNode::FunctionCall { name, arguments, .. } => {
self.execute_function_call(name, arguments)
}
ASTNode::Call { callee, arguments, .. } => {
// callee を評価して FunctionBox なら本体を実行
let callee_val = self.execute_expression(callee)?;
if let Some(fun) = callee_val.as_any().downcast_ref::<crate::boxes::function_box::FunctionBox>() {
// 引数評価
let mut arg_values: Vec<Box<dyn NyashBox>> = Vec::new();
for a in arguments { arg_values.push(self.execute_expression(a)?); }
if arg_values.len() != fun.params.len() {
return Err(RuntimeError::InvalidOperation { message: format!("Function expects {} args, got {}", fun.params.len(), arg_values.len()) });
}
// スコープ保存
let saved_locals = self.save_local_vars();
self.local_vars.clear();
// キャプチャ注入by-value
for (k, v) in fun.env.captures.iter() { self.declare_local_variable(k, v.clone_or_share()); }
if let Some(me_w) = &fun.env.me_value {
if let Some(me_arc) = me_w.upgrade() {
self.declare_local_variable("me", (*me_arc).clone_or_share());
} else {
self.declare_local_variable("me", Box::new(crate::boxes::null_box::NullBox::new()));
}
}
for (p, v) in fun.params.iter().zip(arg_values.iter()) {
self.declare_local_variable(p, v.clone_or_share());
}
// 実行
crate::runtime::global_hooks::push_task_scope();
let mut result: Box<dyn NyashBox> = Box::new(VoidBox::new());
for st in &fun.body {
result = self.execute_statement(st)?;
if let super::ControlFlow::Return(rv) = &self.control_flow {
result = rv.clone_box();
self.control_flow = super::ControlFlow::None;
break;
}
}
crate::runtime::global_hooks::pop_task_scope();
self.restore_local_vars(saved_locals);
Ok(result)
} else if let ASTNode::Lambda { params, body, .. } = callee.as_ref() {
// 直書きLambdaは従来通り実行後方互換
let mut arg_values: Vec<Box<dyn NyashBox>> = Vec::new();
for a in arguments { arg_values.push(self.execute_expression(a)?); }
if arg_values.len() != params.len() {
return Err(RuntimeError::InvalidOperation { message: format!("Lambda expects {} args, got {}", params.len(), arg_values.len()) });
}
let saved_locals = self.save_local_vars();
self.local_vars.clear();
for (p, v) in params.iter().zip(arg_values.iter()) { self.declare_local_variable(p, v.clone_or_share()); }
crate::runtime::global_hooks::push_task_scope();
let mut result: Box<dyn NyashBox> = Box::new(VoidBox::new());
for st in body { result = self.execute_statement(st)?; if let super::ControlFlow::Return(rv) = &self.control_flow { result = rv.clone_box(); self.control_flow = super::ControlFlow::None; break; } }
crate::runtime::global_hooks::pop_task_scope();
self.restore_local_vars(saved_locals);
Ok(result)
} else {
Err(RuntimeError::InvalidOperation { message: "Callee is not callable".to_string() })
}
}
ASTNode::Arrow { sender, receiver, .. } => {
self.execute_arrow(sender, receiver)
}
ASTNode::QMarkPropagate { expression, .. } => {
let v = self.execute_expression(expression)?;
if let Some(res) = v.as_any().downcast_ref::<crate::boxes::result::NyashResultBox>() {
// ok -> unwrap, err -> early return (propagate)
if matches!(res, crate::boxes::result::NyashResultBox::Ok(_)) {
return Ok(res.get_value());
} else {
// Early return the Result itself
self.control_flow = super::ControlFlow::Return(v.clone_box());
return Ok(Box::new(crate::box_trait::VoidBox::new()));
}
}
// Not a Result: pass-through
Ok(v)
}
ASTNode::PeekExpr { scrutinee, arms, else_expr, .. } => {
let val = self.execute_expression(scrutinee)?;
let sval = val.to_string_box().value;
@ -147,6 +319,11 @@ impl NyashInterpreter {
}
self.execute_expression(else_expr)
}
ASTNode::Lambda { params, body, .. } => {
// 値としての関数ボックスを生成ClosureEnv: me/by-val captures
let env = self.build_closure_env(&params, body)?;
Ok(Box::new(crate::boxes::function_box::FunctionBox::with_env(params.clone(), body.clone(), env)))
}
ASTNode::Include { filename, .. } => {
// include式: 最初のstatic boxを返す

View File

@ -11,6 +11,7 @@ use super::super::*;
use crate::boxes::ResultBox;
use crate::box_trait::{StringBox, NyashBox};
use crate::boxes::FileBox;
use crate::boxes::ref_cell_box::RefCellBox;
// use crate::bid::plugin_box::PluginFileBox; // legacy - FileBox専用
impl NyashInterpreter {
@ -108,6 +109,26 @@ impl NyashInterpreter {
}
}
/// RefCellBox のメソッド: get()/set(value)
pub(in crate::interpreter) fn execute_refcell_method(&mut self, cell: &RefCellBox, method: &str, arguments: &[ASTNode])
-> Result<Box<dyn NyashBox>, RuntimeError> {
match method {
"get" => {
if !arguments.is_empty() {
return Err(RuntimeError::InvalidOperation { message: format!("get() expects 0 arguments, got {}", arguments.len()) });
}
Ok(cell.borrow())
}
"set" => {
if arguments.len() != 1 { return Err(RuntimeError::InvalidOperation { message: format!("set() expects 1 argument, got {}", arguments.len()) }); }
let v = self.execute_expression(&arguments[0])?;
cell.replace(v);
Ok(Box::new(crate::box_trait::VoidBox::new()))
}
_ => Err(RuntimeError::InvalidOperation { message: format!("Unknown method '{}' for RefCellBox", method) })
}
}
/* legacy - PluginFileBox専用
/// 汎用プラグインメソッド呼び出し実行 (BID-FFI system)
/// Handles generic plugin method calls via dynamic method discovery

View File

@ -5,6 +5,7 @@ use crate::box_trait::{NyashBox, StringBox, IntegerBox, BoolBox, BoxCore};
use crate::boxes::{ArrayBox, FloatBox, BufferBox, ResultBox, FutureBox, JSONBox, HttpClientBox, StreamBox, RegexBox, MathBox};
use crate::boxes::{null_box, time_box, map_box, random_box, sound_box, debug_box, console_box};
use crate::boxes::{gc_config_box::GcConfigBox, debug_config_box::DebugConfigBox};
use crate::boxes::ref_cell_box::RefCellBox as RcCell;
use crate::boxes::file;
use crate::channel_box::ChannelBox;
use super::{NyashInterpreter, RuntimeError};
@ -118,6 +119,10 @@ impl NyashInterpreter {
if let Some(b) = obj.as_any().downcast_ref::<DebugConfigBox>() {
return Some(self.execute_debug_config_method(b, method, arguments));
}
// RefCellBox (by-ref proxy)
if let Some(b) = obj.as_any().downcast_ref::<RcCell>() {
return Some(self.execute_refcell_method(b, method, arguments));
}
None
}

View File

@ -7,6 +7,7 @@
*/
use super::*;
use crate::boxes::ref_cell_box::RefCellBox;
use super::BuiltinStdlib;
use std::sync::Arc;
@ -46,7 +47,7 @@ impl NyashInterpreter {
}
}
/// 文を実行 - Core statement execution engine
pub(super) fn execute_statement(&mut self, statement: &ASTNode) -> Result<Box<dyn NyashBox>, RuntimeError> {
pub(crate) fn execute_statement(&mut self, statement: &ASTNode) -> Result<Box<dyn NyashBox>, RuntimeError> {
match statement {
ASTNode::Assignment { target, value, .. } => {
self.execute_assignment(target, value)
@ -340,6 +341,13 @@ impl NyashInterpreter {
val.clone_box()
}
};
// セル反映: 既存が RefCellBox なら中身のみ置換
if let Ok(existing) = self.resolve_variable(name) {
if let Some(rc) = existing.as_any().downcast_ref::<RefCellBox>() {
rc.replace(assigned);
return Ok(val);
}
}
self.set_variable(name, assigned)?;
Ok(val)
}
@ -399,6 +407,13 @@ impl NyashInterpreter {
#[cfg(any(not(feature = "plugins"), target_arch = "wasm32"))]
{ val.clone_box() }
};
// セル反映: 既存フィールドが RefCellBox なら中身を置換
if let Some(cur) = instance.get_field(field) {
if let Some(rc) = cur.as_any().downcast_ref::<RefCellBox>() {
rc.replace(stored);
return Ok(val);
}
}
instance.set_field(field, Arc::from(stored))
.map_err(|e| RuntimeError::InvalidOperation { message: e })?;
Ok(val)
@ -433,6 +448,13 @@ impl NyashInterpreter {
#[cfg(any(not(feature = "plugins"), target_arch = "wasm32"))]
{ val.clone_box() }
};
// セル反映: 既存フィールドが RefCellBox なら中身を置換
if let Some(cur) = instance.get_field(field) {
if let Some(rc) = cur.as_any().downcast_ref::<RefCellBox>() {
rc.replace(stored);
return Ok(val);
}
}
instance.set_field(field, Arc::from(stored))
.map_err(|e| RuntimeError::InvalidOperation { message: e })?;
Ok(val)