2025-08-26 19:13:57 +09:00
|
|
|
|
//! Evaluation entry points: execute program and nodes
|
|
|
|
|
|
|
|
|
|
|
|
use crate::ast::ASTNode;
|
2025-09-16 03:54:44 +09:00
|
|
|
|
use crate::box_trait::{NyashBox, VoidBox};
|
2025-08-26 19:13:57 +09:00
|
|
|
|
use super::{NyashInterpreter, RuntimeError, ControlFlow};
|
|
|
|
|
|
|
|
|
|
|
|
impl NyashInterpreter {
|
|
|
|
|
|
/// ASTを実行
|
|
|
|
|
|
pub fn execute(&mut self, ast: ASTNode) -> Result<Box<dyn NyashBox>, RuntimeError> {
|
|
|
|
|
|
super::core::debug_log("=== NYASH EXECUTION START ===");
|
|
|
|
|
|
let result = self.execute_node(&ast);
|
|
|
|
|
|
if let Err(ref e) = result {
|
|
|
|
|
|
eprintln!("❌ Interpreter error: {}", e);
|
|
|
|
|
|
}
|
|
|
|
|
|
super::core::debug_log("=== NYASH EXECUTION END ===");
|
|
|
|
|
|
result
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// ノードを実行
|
|
|
|
|
|
fn execute_node(&mut self, node: &ASTNode) -> Result<Box<dyn NyashBox>, RuntimeError> {
|
|
|
|
|
|
match node {
|
|
|
|
|
|
ASTNode::Program { statements, .. } => {
|
|
|
|
|
|
let mut result: Box<dyn NyashBox> = Box::new(VoidBox::new());
|
|
|
|
|
|
|
|
|
|
|
|
let last = statements.len().saturating_sub(1);
|
|
|
|
|
|
for (i, statement) in statements.iter().enumerate() {
|
|
|
|
|
|
let prev = self.discard_context;
|
|
|
|
|
|
self.discard_context = i != last; // 最終文以外は値が破棄される
|
|
|
|
|
|
result = self.execute_statement(statement)?;
|
|
|
|
|
|
self.discard_context = prev;
|
|
|
|
|
|
|
|
|
|
|
|
// 制御フローチェック
|
|
|
|
|
|
match &self.control_flow {
|
|
|
|
|
|
ControlFlow::Break => {
|
|
|
|
|
|
return Err(RuntimeError::BreakOutsideLoop);
|
|
|
|
|
|
}
|
grammar(P0): add peek expression, continue statement, and field type annotations acceptance; add sample apps and interpreter path\n\n- tokenizer: add keywords (peek, continue), tokens (=> as FatArrow, :: as DoubleColon), keep >> as Arrow\n- parser: implement peek as expression (literal patterns only, else required), add continue; accept field 'name: Type' (discard type P0)\n- interpreter: evaluate PeekExpr; add Continue control flow handling\n- apps: add peek-demo, loop-continue-demo, adjust field-decl demo; use ConsoleBox instead of env.console for interpreter backend\n- docs: CURRENT_TASK updated earlier for Phase 12.7 P0\n\nNOTE: peek arms currently single-expression (no block expr yet); VM/MIR path does not lower PeekExpr yet; use --backend interpreter for demos
2025-09-03 15:26:15 +09:00
|
|
|
|
ControlFlow::Continue => {
|
|
|
|
|
|
return Err(RuntimeError::BreakOutsideLoop);
|
|
|
|
|
|
}
|
2025-08-26 19:13:57 +09:00
|
|
|
|
ControlFlow::Return(_) => {
|
|
|
|
|
|
return Err(RuntimeError::ReturnOutsideFunction);
|
|
|
|
|
|
}
|
|
|
|
|
|
ControlFlow::Throw(_) => {
|
|
|
|
|
|
return Err(RuntimeError::UncaughtException);
|
|
|
|
|
|
}
|
|
|
|
|
|
ControlFlow::None => {}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 🎯 Static Box Main パターン - main()メソッドの自動実行
|
|
|
|
|
|
let has_main_method = {
|
|
|
|
|
|
if let Ok(definitions) = self.shared.static_box_definitions.read() {
|
|
|
|
|
|
if let Some(main_definition) = definitions.get("Main") {
|
|
|
|
|
|
main_definition.methods.contains_key("main")
|
|
|
|
|
|
} else {
|
|
|
|
|
|
false
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
false
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
if has_main_method {
|
|
|
|
|
|
// Main static boxを初期化
|
|
|
|
|
|
self.ensure_static_box_initialized("Main")?;
|
|
|
|
|
|
|
2025-09-17 01:55:08 +09:00
|
|
|
|
// Main.main(args?) を呼び出し(引数が1つならデフォルトで args を注入)
|
2025-09-02 09:26:09 +09:00
|
|
|
|
let mut default_args: Vec<ASTNode> = Vec::new();
|
|
|
|
|
|
if let Ok(defs) = self.shared.static_box_definitions.read() {
|
|
|
|
|
|
if let Some(main_def) = defs.get("Main") {
|
|
|
|
|
|
if let Some(m) = main_def.methods.get("main") {
|
|
|
|
|
|
if let ASTNode::FunctionDeclaration { params, .. } = m {
|
|
|
|
|
|
if params.len() == 1 {
|
2025-09-17 01:55:08 +09:00
|
|
|
|
// Try to read script args from env (JSON array); fallback to empty ArrayBox
|
|
|
|
|
|
if let Ok(json) = std::env::var("NYASH_SCRIPT_ARGS_JSON") {
|
|
|
|
|
|
if let Ok(vals) = serde_json::from_str::<Vec<String>>(&json) {
|
|
|
|
|
|
let mut str_nodes: Vec<ASTNode> = Vec::with_capacity(vals.len());
|
|
|
|
|
|
for s in vals {
|
|
|
|
|
|
str_nodes.push(ASTNode::Literal { value: crate::ast::LiteralValue::String(s), span: crate::ast::Span::unknown() });
|
|
|
|
|
|
}
|
|
|
|
|
|
default_args.push(ASTNode::MethodCall {
|
|
|
|
|
|
object: Box::new(ASTNode::Variable { name: "ArrayBox".to_string(), span: crate::ast::Span::unknown() }),
|
|
|
|
|
|
method: "of".to_string(),
|
|
|
|
|
|
arguments: str_nodes,
|
|
|
|
|
|
span: crate::ast::Span::unknown(),
|
|
|
|
|
|
});
|
|
|
|
|
|
} else {
|
|
|
|
|
|
default_args.push(ASTNode::New { class: "ArrayBox".to_string(), arguments: vec![], type_arguments: vec![], span: crate::ast::Span::unknown() });
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
default_args.push(ASTNode::New { class: "ArrayBox".to_string(), arguments: vec![], type_arguments: vec![], span: crate::ast::Span::unknown() });
|
|
|
|
|
|
}
|
2025-09-02 09:26:09 +09:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-08-26 19:13:57 +09:00
|
|
|
|
let main_call_ast = ASTNode::MethodCall {
|
|
|
|
|
|
object: Box::new(ASTNode::FieldAccess {
|
2025-09-02 09:26:09 +09:00
|
|
|
|
object: Box::new(ASTNode::Variable { name: "statics".to_string(), span: crate::ast::Span::unknown() }),
|
2025-08-26 19:13:57 +09:00
|
|
|
|
field: "Main".to_string(),
|
|
|
|
|
|
span: crate::ast::Span::unknown(),
|
|
|
|
|
|
}),
|
|
|
|
|
|
method: "main".to_string(),
|
2025-09-02 09:26:09 +09:00
|
|
|
|
arguments: default_args,
|
2025-08-26 19:13:57 +09:00
|
|
|
|
span: crate::ast::Span::unknown(),
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// main()の戻り値を最終結果として使用
|
|
|
|
|
|
result = self.execute_statement(&main_call_ast)?;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Ok(result)
|
|
|
|
|
|
}
|
|
|
|
|
|
_ => self.execute_statement(node),
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|