Phase 12.7: Nyash文法革命とANCP 90%圧縮技法の発見 - 文法改革完了とFunctionBox実装
This commit is contained in:
23
src/tests/mir_peek_lower.rs
Normal file
23
src/tests/mir_peek_lower.rs
Normal file
@ -0,0 +1,23 @@
|
||||
use crate::mir::{MirCompiler, MirPrinter};
|
||||
use crate::ast::{ASTNode, LiteralValue, Span};
|
||||
|
||||
#[test]
|
||||
fn mir_lowering_of_peek_expr() {
|
||||
// Build AST: peek 2 { 1 => 10, 2 => 20, else => 30 }
|
||||
let ast = ASTNode::PeekExpr {
|
||||
scrutinee: Box::new(ASTNode::Literal { value: LiteralValue::Integer(2), span: Span::unknown() }),
|
||||
arms: vec![
|
||||
(LiteralValue::Integer(1), ASTNode::Literal { value: LiteralValue::Integer(10), span: Span::unknown() }),
|
||||
(LiteralValue::Integer(2), ASTNode::Literal { value: LiteralValue::Integer(20), span: Span::unknown() }),
|
||||
],
|
||||
else_expr: Box::new(ASTNode::Literal { value: LiteralValue::Integer(30), span: Span::unknown() }),
|
||||
span: Span::unknown(),
|
||||
};
|
||||
|
||||
let mut compiler = MirCompiler::new();
|
||||
let res = compiler.compile(ast).expect("compile ok");
|
||||
let dump = MirPrinter::new().print_module(&res.module);
|
||||
assert!(dump.contains("br "), "expected branches in MIR:\n{}", dump);
|
||||
assert!(dump.contains("phi"), "expected phi merge in MIR:\n{}", dump);
|
||||
}
|
||||
|
||||
20
src/tests/mir_qmark_lower.rs
Normal file
20
src/tests/mir_qmark_lower.rs
Normal file
@ -0,0 +1,20 @@
|
||||
use crate::mir::{MirCompiler, MirPrinter};
|
||||
use crate::ast::{ASTNode, Span};
|
||||
|
||||
#[test]
|
||||
fn mir_lowering_of_qmark_propagate() {
|
||||
// Build AST: (new StringBox("ok"))?
|
||||
let ast = ASTNode::QMarkPropagate {
|
||||
expression: Box::new(ASTNode::New { class: "StringBox".to_string(), arguments: vec![
|
||||
ASTNode::Literal { value: crate::ast::LiteralValue::String("ok".to_string()), span: Span::unknown() }
|
||||
], type_arguments: vec![], span: Span::unknown() }),
|
||||
span: Span::unknown(),
|
||||
};
|
||||
let mut c = MirCompiler::new();
|
||||
let out = c.compile(ast).expect("compile ok");
|
||||
let dump = MirPrinter::new().print_module(&out.module);
|
||||
assert!(dump.contains("plugin_invoke"), "expected plugin_invoke isOk/getValue in MIR:\n{}", dump);
|
||||
assert!(dump.contains("br "), "expected branch in MIR:\n{}", dump);
|
||||
assert!(dump.contains("ret "), "expected return on error path in MIR:\n{}", dump);
|
||||
}
|
||||
|
||||
17
src/tests/parser_lambda.rs
Normal file
17
src/tests/parser_lambda.rs
Normal file
@ -0,0 +1,17 @@
|
||||
use crate::parser::NyashParser;
|
||||
use crate::ast::ASTNode;
|
||||
|
||||
#[test]
|
||||
fn parse_lambda_fn_block() {
|
||||
let src = "local f = fn() { return 1 }";
|
||||
let ast = NyashParser::parse_from_string(src).expect("parse ok");
|
||||
fn has_lambda(n: &ASTNode) -> bool {
|
||||
match n {
|
||||
ASTNode::Lambda { .. } => true,
|
||||
ASTNode::Program { statements, .. } => statements.iter().any(has_lambda),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
assert!(has_lambda(&ast));
|
||||
}
|
||||
|
||||
17
src/tests/parser_lambda_call.rs
Normal file
17
src/tests/parser_lambda_call.rs
Normal file
@ -0,0 +1,17 @@
|
||||
use crate::parser::NyashParser;
|
||||
use crate::ast::ASTNode;
|
||||
|
||||
#[test]
|
||||
fn parse_immediate_lambda_call() {
|
||||
let src = "(fn(x){ x }) (1)";
|
||||
let ast = NyashParser::parse_from_string(src).expect("parse ok");
|
||||
fn has_call(n: &ASTNode) -> bool {
|
||||
match n {
|
||||
ASTNode::Call { .. } => true,
|
||||
ASTNode::Program { statements, .. } => statements.iter().any(has_call),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
assert!(has_call(&ast));
|
||||
}
|
||||
|
||||
17
src/tests/parser_parent_colon.rs
Normal file
17
src/tests/parser_parent_colon.rs
Normal file
@ -0,0 +1,17 @@
|
||||
use crate::parser::NyashParser;
|
||||
use crate::ast::ASTNode;
|
||||
|
||||
#[test]
|
||||
fn parse_parent_colon_syntax() {
|
||||
let src = "Parent::birth()";
|
||||
let ast = NyashParser::parse_from_string(src).expect("parse ok");
|
||||
fn is_fromcall(n: &ASTNode) -> bool {
|
||||
match n {
|
||||
ASTNode::FromCall { parent, method, .. } => parent == "Parent" && method == "birth",
|
||||
ASTNode::Program { statements, .. } => statements.iter().any(is_fromcall),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
assert!(is_fromcall(&ast));
|
||||
}
|
||||
|
||||
29
src/tests/parser_peek_block.rs
Normal file
29
src/tests/parser_peek_block.rs
Normal file
@ -0,0 +1,29 @@
|
||||
use crate::parser::NyashParser;
|
||||
|
||||
#[test]
|
||||
fn parse_peek_with_block_arm() {
|
||||
let src = r#"
|
||||
local x = 2
|
||||
local y = peek x {
|
||||
1 => { local a = 10 a }
|
||||
2 => { 20 }
|
||||
else => { 30 }
|
||||
}
|
||||
"#;
|
||||
let ast = NyashParser::parse_from_string(src).expect("parse ok");
|
||||
// Quick structural check: ensure AST contains PeekExpr and Program nodes inside arms
|
||||
fn find_peek(ast: &crate::ast::ASTNode) -> bool {
|
||||
match ast {
|
||||
crate::ast::ASTNode::PeekExpr { arms, else_expr, .. } => {
|
||||
// Expect at least one Program arm
|
||||
let has_block = arms.iter().any(|(_, e)| matches!(e, crate::ast::ASTNode::Program { .. }));
|
||||
let else_is_block = matches!(**else_expr, crate::ast::ASTNode::Program { .. });
|
||||
has_block && else_is_block
|
||||
}
|
||||
crate::ast::ASTNode::Program { statements, .. } => statements.iter().any(find_peek),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
assert!(find_peek(&ast), "expected peek with block arms in AST");
|
||||
}
|
||||
|
||||
68
src/tests/refcell_assignment_test.rs
Normal file
68
src/tests/refcell_assignment_test.rs
Normal file
@ -0,0 +1,68 @@
|
||||
use crate::interpreter::NyashInterpreter;
|
||||
use crate::ast::{ASTNode, LiteralValue};
|
||||
use crate::box_trait::{NyashBox, IntegerBox};
|
||||
|
||||
#[test]
|
||||
fn assign_updates_refcell_variable_inner() {
|
||||
let mut interp = NyashInterpreter::new();
|
||||
// x = RefCell(1)
|
||||
let rc = crate::boxes::ref_cell_box::RefCellBox::new(Box::new(IntegerBox::new(1)));
|
||||
interp.declare_local_variable("x", Box::new(rc));
|
||||
|
||||
// Execute: x = 42
|
||||
let target = ASTNode::Variable { name: "x".to_string(), span: crate::ast::Span::unknown() };
|
||||
let value = ASTNode::Literal { value: LiteralValue::Integer(42), span: crate::ast::Span::unknown() };
|
||||
let _ = interp.execute_assignment(&target, &value).expect("assign ok");
|
||||
|
||||
// Verify x is still RefCell and inner == 42
|
||||
let xv = interp.resolve_variable("x").expect("x exists");
|
||||
let rc = xv.as_any().downcast_ref::<crate::boxes::ref_cell_box::RefCellBox>().expect("x is RefCellBox");
|
||||
let inner = rc.borrow();
|
||||
let ib = inner.as_any().downcast_ref::<IntegerBox>().expect("inner integer");
|
||||
assert_eq!(ib.value, 42);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn assign_updates_refcell_field_inner() {
|
||||
let mut interp = NyashInterpreter::new();
|
||||
// obj with field v = RefCell(5)
|
||||
let inst = crate::instance_v2::InstanceBox::from_declaration("Test".to_string(), vec!["v".to_string()], std::collections::HashMap::new());
|
||||
let rc = crate::boxes::ref_cell_box::RefCellBox::new(Box::new(IntegerBox::new(5)));
|
||||
let _ = inst.set_field("v", std::sync::Arc::from(Box::new(rc) as Box<dyn NyashBox>));
|
||||
// bind obj into local
|
||||
interp.declare_local_variable("obj", Box::new(inst.clone()));
|
||||
|
||||
// Execute: obj.v = 7
|
||||
let target = ASTNode::FieldAccess { object: Box::new(ASTNode::Variable { name: "obj".to_string(), span: crate::ast::Span::unknown() }), field: "v".to_string(), span: crate::ast::Span::unknown() };
|
||||
let value = ASTNode::Literal { value: LiteralValue::Integer(7), span: crate::ast::Span::unknown() };
|
||||
let _ = interp.execute_assignment(&target, &value).expect("assign ok");
|
||||
|
||||
// Verify obj.v inner == 7
|
||||
let sv = inst.get_field("v").expect("field exists");
|
||||
let rc = sv.as_any().downcast_ref::<crate::boxes::ref_cell_box::RefCellBox>().expect("v is RefCellBox");
|
||||
let inner = rc.borrow();
|
||||
let ib = inner.as_any().downcast_ref::<IntegerBox>().expect("inner integer");
|
||||
assert_eq!(ib.value, 7);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn closure_reads_updated_refcell_capture() {
|
||||
let mut interp = NyashInterpreter::new();
|
||||
// local x = 10
|
||||
interp.declare_local_variable("x", Box::new(IntegerBox::new(10)));
|
||||
// Build lambda: () { x }
|
||||
let lam = ASTNode::Lambda { params: vec![], body: vec![
|
||||
ASTNode::Return { value: Some(Box::new(ASTNode::Variable { name: "x".to_string(), span: crate::ast::Span::unknown() })), span: crate::ast::Span::unknown() }
|
||||
], span: crate::ast::Span::unknown() };
|
||||
// Evaluate lambda to FunctionBox
|
||||
let f = interp.execute_expression(&lam).expect("lambda eval");
|
||||
// x = 20 (should update RefCell capture)
|
||||
let target = ASTNode::Variable { name: "x".to_string(), span: crate::ast::Span::unknown() };
|
||||
let value = ASTNode::Literal { value: LiteralValue::Integer(20), span: crate::ast::Span::unknown() };
|
||||
let _ = interp.execute_assignment(&target, &value).expect("assign ok");
|
||||
// Call f()
|
||||
let call = ASTNode::Call { callee: Box::new(lam.clone()), arguments: vec![], span: crate::ast::Span::unknown() };
|
||||
let out = interp.execute_expression(&call).expect("call ok");
|
||||
let ib = out.as_any().downcast_ref::<IntegerBox>().expect("integer ret");
|
||||
assert_eq!(ib.value, 20);
|
||||
}
|
||||
Reference in New Issue
Block a user