🎉 feat: MIRパラメータ解決完全修正 + VM E2Eテスト成功!
Phase 9.78b関連修正:
- MirBuilder::lower_method_as_function でValueIdリセット実装
- me → %0, 引数 → %1... の正しいマッピング
- build_me_expression() で変数テーブル優先解決
- VM E2Eテスト test_vm_user_box_birth_and_method 成功
- new Person("Alice").greet() → "Hello, Alice"
ドキュメント:
- mir-unified-reference.md を正式MIRドキュメントとして配置
- 現在の35命令実装状態を正確に記載
- RefGet/RefSet仕様含む
ChatGPT5によるMIRビルダー修正で、VMバックエンドでのユーザー定義Box完全動作!
This commit is contained in:
@ -1049,6 +1049,13 @@ impl Default for VM {
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::mir::{MirModule, MirFunction, FunctionSignature, MirType, EffectMask, BasicBlock};
|
||||
use crate::NyashParser;
|
||||
use crate::runtime::NyashRuntime;
|
||||
use crate::core::model::BoxDeclaration as CoreBoxDecl;
|
||||
use crate::interpreter::SharedState;
|
||||
use crate::box_factory::user_defined::UserDefinedBoxFactory;
|
||||
use std::sync::Arc;
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[test]
|
||||
fn test_basic_vm_execution() {
|
||||
@ -1089,4 +1096,79 @@ mod tests {
|
||||
let value = vm.get_value(ValueId(3)).unwrap();
|
||||
assert_eq!(value.as_integer().unwrap(), 42);
|
||||
}
|
||||
|
||||
fn collect_box_declarations(ast: &crate::ast::ASTNode, runtime: &NyashRuntime) {
|
||||
fn walk(node: &crate::ast::ASTNode, runtime: &NyashRuntime) {
|
||||
match node {
|
||||
crate::ast::ASTNode::Program { statements, .. } => {
|
||||
for st in statements { walk(st, runtime); }
|
||||
}
|
||||
crate::ast::ASTNode::BoxDeclaration { name, fields, methods, constructors, init_fields, weak_fields, is_interface, extends, implements, type_parameters, .. } => {
|
||||
let decl = CoreBoxDecl {
|
||||
name: name.clone(),
|
||||
fields: fields.clone(),
|
||||
methods: methods.clone(),
|
||||
constructors: constructors.clone(),
|
||||
init_fields: init_fields.clone(),
|
||||
weak_fields: weak_fields.clone(),
|
||||
is_interface: *is_interface,
|
||||
extends: extends.clone(),
|
||||
implements: implements.clone(),
|
||||
type_parameters: type_parameters.clone(),
|
||||
};
|
||||
if let Ok(mut map) = runtime.box_declarations.write() {
|
||||
map.insert(name.clone(), decl);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
walk(ast, runtime);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_vm_user_box_birth_and_method() {
|
||||
let code = r#"
|
||||
box Person {
|
||||
init { name }
|
||||
birth(n) {
|
||||
me.name = n
|
||||
}
|
||||
greet() {
|
||||
return "Hello, " + me.name
|
||||
}
|
||||
}
|
||||
|
||||
return new Person("Alice").greet()
|
||||
"#;
|
||||
|
||||
// Parse to AST
|
||||
let ast = NyashParser::parse_from_string(code).expect("parse failed");
|
||||
|
||||
// Prepare runtime with user-defined declarations and factory
|
||||
let runtime = {
|
||||
let rt = NyashRuntime::new();
|
||||
collect_box_declarations(&ast, &rt);
|
||||
let mut shared = SharedState::new();
|
||||
shared.box_declarations = rt.box_declarations.clone();
|
||||
let udf = Arc::new(UserDefinedBoxFactory::new(shared));
|
||||
if let Ok(mut reg) = rt.box_registry.lock() { reg.register(udf); }
|
||||
rt
|
||||
};
|
||||
|
||||
// Compile to MIR
|
||||
let mut compiler = crate::mir::MirCompiler::new();
|
||||
let compile_result = compiler.compile(ast).expect("mir compile failed");
|
||||
|
||||
// Debug: Print MIR
|
||||
println!("=== MIR Output ===");
|
||||
let mut printer = crate::mir::MirPrinter::verbose();
|
||||
println!("{}", printer.print_module(&compile_result.module));
|
||||
println!("==================");
|
||||
|
||||
// Execute with VM
|
||||
let mut vm = VM::with_runtime(runtime);
|
||||
let result = vm.execute_module(&compile_result.module).expect("vm exec failed");
|
||||
assert_eq!(result.to_string_box().value, "Hello, Alice");
|
||||
}
|
||||
}
|
||||
|
||||
@ -80,6 +80,9 @@ impl MirBuilder {
|
||||
let saved_function = self.current_function.take();
|
||||
let saved_block = self.current_block.take();
|
||||
let saved_var_map = std::mem::take(&mut self.variable_map);
|
||||
let saved_value_gen = self.value_gen.clone();
|
||||
// Reset value id generator so that params start from %0, %1, ...
|
||||
self.value_gen.reset();
|
||||
|
||||
// Switch context to new function
|
||||
self.current_function = Some(function);
|
||||
@ -88,11 +91,11 @@ impl MirBuilder {
|
||||
|
||||
// Create parameter value ids and bind variable names
|
||||
if let Some(ref mut f) = self.current_function {
|
||||
// 'me' parameter
|
||||
// 'me' parameter will be %0
|
||||
let me_id = self.value_gen.next();
|
||||
f.params.push(me_id);
|
||||
self.variable_map.insert("me".to_string(), me_id);
|
||||
// user parameters
|
||||
// user parameters continue as %1..N
|
||||
for p in ¶ms {
|
||||
let pid = self.value_gen.next();
|
||||
f.params.push(pid);
|
||||
@ -125,6 +128,7 @@ impl MirBuilder {
|
||||
self.current_function = saved_function;
|
||||
self.current_block = saved_block;
|
||||
self.variable_map = saved_var_map;
|
||||
self.value_gen = saved_value_gen;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -905,17 +909,17 @@ impl MirBuilder {
|
||||
|
||||
/// Build me expression: me
|
||||
fn build_me_expression(&mut self) -> Result<ValueId, String> {
|
||||
// For now, return a reference to the current instance
|
||||
// In a full implementation, this would resolve to the actual instance reference
|
||||
// If lowering a method/birth function, "me" should be a parameter
|
||||
if let Some(id) = self.variable_map.get("me").cloned() {
|
||||
return Ok(id);
|
||||
}
|
||||
|
||||
// Fallback: use a symbolic constant (legacy behavior)
|
||||
let me_value = self.value_gen.next();
|
||||
|
||||
// For simplicity, emit a constant representing "me"
|
||||
// In practice, this should resolve to the current instance context
|
||||
self.emit_instruction(MirInstruction::Const {
|
||||
dst: me_value,
|
||||
value: ConstValue::String("__me__".to_string()),
|
||||
})?;
|
||||
|
||||
Ok(me_value)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user