🎉 Phase 11.8/12.7: MIR Core-13 完全実装 + 糖衣構文ドキュメント更新
主要な変更: - MIR Core-13命令セット確定(Load/Store削除の革命的設計) - Const, BinOp, Compare(値・計算) - Jump, Branch, Return, Phi(制御) - Call, BoxCall, ExternCall(呼び出し) - TypeOp, Safepoint, Barrier(メタ) - Phase 12.7糖衣構文ドキュメント整理(超圧縮重視、可逆変換保証) - MIRビルダーのモジュール分割完了 - vtableテストスイート拡充 - AI協調開発ツール追加(並列リファクタリング支援) 詳細: - src/mir/instruction_introspection.rs: core13_instruction_names()追加 - MIRビルダー分割: decls.rs, exprs_*.rs, fields.rs - plugin_loader_v2: errors.rs, host_bridge.rs分離 - 論文用データ: mir13-final.md作成 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
56
src/tests/core13_smoke_array.rs
Normal file
56
src/tests/core13_smoke_array.rs
Normal file
@ -0,0 +1,56 @@
|
||||
#[test]
|
||||
fn core13_array_boxcall_push_len_get() {
|
||||
use crate::backend::vm::VM;
|
||||
use crate::mir::{MirModule, MirFunction, FunctionSignature, MirInstruction, EffectMask, BasicBlockId, ConstValue, MirType};
|
||||
|
||||
// Build: a = new ArrayBox(); a.push(7); r = a.len() + a.get(0); return r
|
||||
let sig = FunctionSignature { name: "main".into(), params: vec![], return_type: MirType::Integer, effects: EffectMask::PURE };
|
||||
let mut f = MirFunction::new(sig, BasicBlockId::new(0));
|
||||
let bb = f.entry_block;
|
||||
let a = f.next_value_id();
|
||||
f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::NewBox { dst: a, box_type: "ArrayBox".into(), args: vec![] });
|
||||
// push(7)
|
||||
let seven = f.next_value_id(); f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::Const { dst: seven, value: ConstValue::Integer(7) });
|
||||
f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::BoxCall { dst: None, box_val: a, method: "push".into(), args: vec![seven], method_id: None, effects: EffectMask::PURE });
|
||||
// len()
|
||||
let ln = f.next_value_id();
|
||||
f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::BoxCall { dst: Some(ln), box_val: a, method: "len".into(), args: vec![], method_id: None, effects: EffectMask::PURE });
|
||||
// get(0)
|
||||
let zero = f.next_value_id(); f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::Const { dst: zero, value: ConstValue::Integer(0) });
|
||||
let g0 = f.next_value_id();
|
||||
f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::BoxCall { dst: Some(g0), box_val: a, method: "get".into(), args: vec![zero], method_id: None, effects: EffectMask::PURE });
|
||||
// sum
|
||||
let sum = f.next_value_id(); f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::BinOp { dst: sum, op: crate::mir::BinaryOp::Add, lhs: ln, rhs: g0 });
|
||||
f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::Return { value: Some(sum) });
|
||||
|
||||
let mut m = MirModule::new("core13_array_push_len_get".into()); m.add_function(f);
|
||||
let mut vm = VM::new();
|
||||
let out = vm.execute_module(&m).expect("vm exec");
|
||||
assert_eq!(out.to_string_box().value, "8");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn core13_array_boxcall_set_get() {
|
||||
use crate::backend::vm::VM;
|
||||
use crate::mir::{MirModule, MirFunction, FunctionSignature, MirInstruction, EffectMask, BasicBlockId, ConstValue, MirType};
|
||||
|
||||
// Build: a = new ArrayBox(); a.set(0, 5); return a.get(0)
|
||||
let sig = FunctionSignature { name: "main".into(), params: vec![], return_type: MirType::Integer, effects: EffectMask::PURE };
|
||||
let mut f = MirFunction::new(sig, BasicBlockId::new(0));
|
||||
let bb = f.entry_block;
|
||||
let a = f.next_value_id();
|
||||
f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::NewBox { dst: a, box_type: "ArrayBox".into(), args: vec![] });
|
||||
let zero = f.next_value_id(); f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::Const { dst: zero, value: ConstValue::Integer(0) });
|
||||
let five = f.next_value_id(); f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::Const { dst: five, value: ConstValue::Integer(5) });
|
||||
f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::BoxCall { dst: None, box_val: a, method: "set".into(), args: vec![zero, five], method_id: None, effects: EffectMask::PURE });
|
||||
let outv = f.next_value_id();
|
||||
let zero2 = f.next_value_id(); f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::Const { dst: zero2, value: ConstValue::Integer(0) });
|
||||
f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::BoxCall { dst: Some(outv), box_val: a, method: "get".into(), args: vec![zero2], method_id: None, effects: EffectMask::PURE });
|
||||
f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::Return { value: Some(outv) });
|
||||
|
||||
let mut m = MirModule::new("core13_array_set_get".into()); m.add_function(f);
|
||||
let mut vm = VM::new();
|
||||
let out = vm.execute_module(&m).expect("vm exec");
|
||||
assert_eq!(out.to_string_box().value, "5");
|
||||
}
|
||||
|
||||
42
src/tests/core13_smoke_jit.rs
Normal file
42
src/tests/core13_smoke_jit.rs
Normal file
@ -0,0 +1,42 @@
|
||||
#[cfg(feature = "cranelift-jit")]
|
||||
#[test]
|
||||
fn core13_jit_array_push_len_get() {
|
||||
use crate::mir::{MirModule, MirFunction, FunctionSignature, MirInstruction, EffectMask, BasicBlockId, ConstValue, MirType};
|
||||
// Build: a = new ArrayBox(); a.push(3); ret a.len()+a.get(0)
|
||||
let sig = FunctionSignature { name: "main".into(), params: vec![], return_type: MirType::Integer, effects: EffectMask::PURE };
|
||||
let mut f = MirFunction::new(sig, BasicBlockId::new(0));
|
||||
let bb = f.entry_block;
|
||||
let a = f.next_value_id();
|
||||
f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::NewBox { dst: a, box_type: "ArrayBox".into(), args: vec![] });
|
||||
let three = f.next_value_id(); f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::Const { dst: three, value: ConstValue::Integer(3) });
|
||||
f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::BoxCall { dst: None, box_val: a, method: "push".into(), args: vec![three], method_id: None, effects: EffectMask::PURE });
|
||||
let ln = f.next_value_id(); f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::BoxCall { dst: Some(ln), box_val: a, method: "len".into(), args: vec![], method_id: None, effects: EffectMask::PURE });
|
||||
let zero = f.next_value_id(); f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::Const { dst: zero, value: ConstValue::Integer(0) });
|
||||
let g0 = f.next_value_id(); f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::BoxCall { dst: Some(g0), box_val: a, method: "get".into(), args: vec![zero], method_id: None, effects: EffectMask::PURE });
|
||||
let sum = f.next_value_id(); f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::BinOp { dst: sum, op: crate::mir::BinaryOp::Add, lhs: ln, rhs: g0 });
|
||||
f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::Return { value: Some(sum) });
|
||||
let mut m = MirModule::new("core13_jit_array_push_len_get".into()); m.add_function(f);
|
||||
let jit_out = crate::backend::cranelift_compile_and_execute(&m, "core13_jit_array").expect("JIT exec");
|
||||
assert_eq!(jit_out.to_string_box().value, "4");
|
||||
}
|
||||
|
||||
#[cfg(feature = "cranelift-jit")]
|
||||
#[test]
|
||||
fn core13_jit_array_set_get() {
|
||||
use crate::mir::{MirModule, MirFunction, FunctionSignature, MirInstruction, EffectMask, BasicBlockId, ConstValue, MirType};
|
||||
// Build: a = new ArrayBox(); a.set(0, 9); ret a.get(0)
|
||||
let sig = FunctionSignature { name: "main".into(), params: vec![], return_type: MirType::Integer, effects: EffectMask::PURE };
|
||||
let mut f = MirFunction::new(sig, BasicBlockId::new(0));
|
||||
let bb = f.entry_block;
|
||||
let a = f.next_value_id(); f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::NewBox { dst: a, box_type: "ArrayBox".into(), args: vec![] });
|
||||
let zero = f.next_value_id(); f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::Const { dst: zero, value: ConstValue::Integer(0) });
|
||||
let nine = f.next_value_id(); f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::Const { dst: nine, value: ConstValue::Integer(9) });
|
||||
f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::BoxCall { dst: None, box_val: a, method: "set".into(), args: vec![zero, nine], method_id: None, effects: EffectMask::PURE });
|
||||
let z2 = f.next_value_id(); f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::Const { dst: z2, value: ConstValue::Integer(0) });
|
||||
let outv = f.next_value_id(); f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::BoxCall { dst: Some(outv), box_val: a, method: "get".into(), args: vec![z2], method_id: None, effects: EffectMask::PURE });
|
||||
f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::Return { value: Some(outv) });
|
||||
let mut m = MirModule::new("core13_jit_array_set_get".into()); m.add_function(f);
|
||||
let jit_out = crate::backend::cranelift_compile_and_execute(&m, "core13_jit_array2").expect("JIT exec");
|
||||
assert_eq!(jit_out.to_string_box().value, "9");
|
||||
}
|
||||
|
||||
27
src/tests/core13_smoke_jit_map.rs
Normal file
27
src/tests/core13_smoke_jit_map.rs
Normal file
@ -0,0 +1,27 @@
|
||||
#[cfg(feature = "cranelift-jit")]
|
||||
#[test]
|
||||
fn core13_jit_map_set_get_size() {
|
||||
use crate::mir::{MirModule, MirFunction, FunctionSignature, MirInstruction, EffectMask, BasicBlockId, ConstValue, MirType};
|
||||
// Build: m = new MapBox(); m.set("k", 11); r = m.size()+m.get("k"); return r
|
||||
let sig = FunctionSignature { name: "main".into(), params: vec![], return_type: MirType::Integer, effects: EffectMask::PURE };
|
||||
let mut f = MirFunction::new(sig, BasicBlockId::new(0));
|
||||
let bb = f.entry_block;
|
||||
let m = f.next_value_id();
|
||||
f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::NewBox { dst: m, box_type: "MapBox".into(), args: vec![] });
|
||||
// set("k", 11)
|
||||
let k = f.next_value_id(); f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::Const { dst: k, value: ConstValue::String("k".into()) });
|
||||
let v = f.next_value_id(); f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::Const { dst: v, value: ConstValue::Integer(11) });
|
||||
f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::BoxCall { dst: None, box_val: m, method: "set".into(), args: vec![k, v], method_id: None, effects: EffectMask::PURE });
|
||||
// size()
|
||||
let sz = f.next_value_id(); f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::BoxCall { dst: Some(sz), box_val: m, method: "size".into(), args: vec![], method_id: None, effects: EffectMask::PURE });
|
||||
// get("k")
|
||||
let k2 = f.next_value_id(); f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::Const { dst: k2, value: ConstValue::String("k".into()) });
|
||||
let gk = f.next_value_id(); f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::BoxCall { dst: Some(gk), box_val: m, method: "get".into(), args: vec![k2], method_id: None, effects: EffectMask::PURE });
|
||||
// sum
|
||||
let sum = f.next_value_id(); f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::BinOp { dst: sum, op: crate::mir::BinaryOp::Add, lhs: sz, rhs: gk });
|
||||
f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::Return { value: Some(sum) });
|
||||
let mut module = MirModule::new("core13_jit_map_set_get_size".into()); module.add_function(f);
|
||||
let out = crate::backend::cranelift_compile_and_execute(&module, "core13_jit_map").expect("JIT exec");
|
||||
assert_eq!(out.to_string_box().value, "12");
|
||||
}
|
||||
|
||||
@ -6,6 +6,13 @@ pub mod identical_exec_string;
|
||||
pub mod identical_exec_instance;
|
||||
pub mod vtable_array_string;
|
||||
pub mod vtable_strict;
|
||||
pub mod vtable_array_ext;
|
||||
pub mod vtable_array_p2;
|
||||
pub mod vtable_array_p1;
|
||||
pub mod vtable_string;
|
||||
pub mod vtable_console;
|
||||
pub mod vtable_map_ext;
|
||||
pub mod vtable_string_p1;
|
||||
pub mod host_reverse_slot;
|
||||
pub mod nyash_abi_basic;
|
||||
pub mod typebox_tlv_diff;
|
||||
|
||||
61
src/tests/vtable_array_ext.rs
Normal file
61
src/tests/vtable_array_ext.rs
Normal file
@ -0,0 +1,61 @@
|
||||
#[test]
|
||||
fn vtable_array_push_get_len_pop_clear() {
|
||||
use crate::backend::vm::VM;
|
||||
use crate::mir::{MirModule, MirFunction, FunctionSignature, MirInstruction, EffectMask, BasicBlockId, ConstValue, MirType};
|
||||
std::env::set_var("NYASH_ABI_VTABLE", "1");
|
||||
|
||||
// Case 1: push("x"); get(0)
|
||||
let sig = FunctionSignature { name: "main".into(), params: vec![], return_type: MirType::String, effects: EffectMask::PURE };
|
||||
let mut f = MirFunction::new(sig, BasicBlockId::new(0));
|
||||
let bb = f.entry_block;
|
||||
let arr = f.next_value_id();
|
||||
f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::NewBox { dst: arr, box_type: "ArrayBox".into(), args: vec![] });
|
||||
let sval = f.next_value_id();
|
||||
f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::Const { dst: sval, value: ConstValue::String("x".into()) });
|
||||
f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::BoxCall { dst: None, box_val: arr, method: "push".into(), args: vec![sval], method_id: None, effects: EffectMask::PURE });
|
||||
let idx0 = f.next_value_id();
|
||||
f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::Const { dst: idx0, value: ConstValue::Integer(0) });
|
||||
let got = f.next_value_id();
|
||||
f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::BoxCall { dst: Some(got), box_val: arr, method: "get".into(), args: vec![idx0], method_id: None, effects: EffectMask::PURE });
|
||||
f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::Return { value: Some(got) });
|
||||
let mut m = MirModule::new("arr_push_get".into()); m.add_function(f);
|
||||
let mut vm = VM::new();
|
||||
let out = vm.execute_module(&m).expect("vm exec");
|
||||
assert_eq!(out.to_string_box().value, "x");
|
||||
|
||||
// Case 2: push("y"); pop() -> "y"
|
||||
let sig2 = FunctionSignature { name: "main".into(), params: vec![], return_type: MirType::String, effects: EffectMask::PURE };
|
||||
let mut f2 = MirFunction::new(sig2, BasicBlockId::new(0));
|
||||
let bb2 = f2.entry_block;
|
||||
let a2 = f2.next_value_id();
|
||||
f2.get_block_mut(bb2).unwrap().add_instruction(MirInstruction::NewBox { dst: a2, box_type: "ArrayBox".into(), args: vec![] });
|
||||
let y = f2.next_value_id();
|
||||
f2.get_block_mut(bb2).unwrap().add_instruction(MirInstruction::Const { dst: y, value: ConstValue::String("y".into()) });
|
||||
f2.get_block_mut(bb2).unwrap().add_instruction(MirInstruction::BoxCall { dst: None, box_val: a2, method: "push".into(), args: vec![y], method_id: None, effects: EffectMask::PURE });
|
||||
let popped = f2.next_value_id();
|
||||
f2.get_block_mut(bb2).unwrap().add_instruction(MirInstruction::BoxCall { dst: Some(popped), box_val: a2, method: "pop".into(), args: vec![], method_id: None, effects: EffectMask::PURE });
|
||||
f2.get_block_mut(bb2).unwrap().add_instruction(MirInstruction::Return { value: Some(popped) });
|
||||
let mut m2 = MirModule::new("arr_pop".into()); m2.add_function(f2);
|
||||
let mut vm2 = VM::new();
|
||||
let out2 = vm2.execute_module(&m2).expect("vm exec");
|
||||
assert_eq!(out2.to_string_box().value, "y");
|
||||
|
||||
// Case 3: push("z"); clear(); len() -> 0
|
||||
let sig3 = FunctionSignature { name: "main".into(), params: vec![], return_type: MirType::Integer, effects: EffectMask::PURE };
|
||||
let mut f3 = MirFunction::new(sig3, BasicBlockId::new(0));
|
||||
let bb3 = f3.entry_block;
|
||||
let a3 = f3.next_value_id();
|
||||
f3.get_block_mut(bb3).unwrap().add_instruction(MirInstruction::NewBox { dst: a3, box_type: "ArrayBox".into(), args: vec![] });
|
||||
let z = f3.next_value_id();
|
||||
f3.get_block_mut(bb3).unwrap().add_instruction(MirInstruction::Const { dst: z, value: ConstValue::String("z".into()) });
|
||||
f3.get_block_mut(bb3).unwrap().add_instruction(MirInstruction::BoxCall { dst: None, box_val: a3, method: "push".into(), args: vec![z], method_id: None, effects: EffectMask::PURE });
|
||||
f3.get_block_mut(bb3).unwrap().add_instruction(MirInstruction::BoxCall { dst: None, box_val: a3, method: "clear".into(), args: vec![], method_id: None, effects: EffectMask::PURE });
|
||||
let ln = f3.next_value_id();
|
||||
f3.get_block_mut(bb3).unwrap().add_instruction(MirInstruction::BoxCall { dst: Some(ln), box_val: a3, method: "len".into(), args: vec![], method_id: None, effects: EffectMask::PURE });
|
||||
f3.get_block_mut(bb3).unwrap().add_instruction(MirInstruction::Return { value: Some(ln) });
|
||||
let mut m3 = MirModule::new("arr_clear_len".into()); m3.add_function(f3);
|
||||
let mut vm3 = VM::new();
|
||||
let out3 = vm3.execute_module(&m3).expect("vm exec");
|
||||
assert_eq!(out3.to_string_box().value, "0");
|
||||
}
|
||||
|
||||
78
src/tests/vtable_array_p1.rs
Normal file
78
src/tests/vtable_array_p1.rs
Normal file
@ -0,0 +1,78 @@
|
||||
#[test]
|
||||
fn vtable_array_contains_indexof_join() {
|
||||
use crate::backend::vm::VM;
|
||||
use crate::mir::{MirModule, MirFunction, FunctionSignature, MirInstruction, EffectMask, BasicBlockId, ConstValue, MirType};
|
||||
std::env::set_var("NYASH_ABI_VTABLE", "1");
|
||||
|
||||
// contains: ["a","b"].contains("b") == true; contains("c") == false
|
||||
let sig = FunctionSignature { name: "main".into(), params: vec![], return_type: MirType::Integer, effects: EffectMask::PURE };
|
||||
let mut f = MirFunction::new(sig, BasicBlockId::new(0));
|
||||
let bb = f.entry_block;
|
||||
let arr = f.next_value_id();
|
||||
f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::NewBox { dst: arr, box_type: "ArrayBox".into(), args: vec![] });
|
||||
let sa = f.next_value_id(); f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::Const { dst: sa, value: ConstValue::String("a".into()) });
|
||||
let sb = f.next_value_id(); f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::Const { dst: sb, value: ConstValue::String("b".into()) });
|
||||
f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::BoxCall { dst: None, box_val: arr, method: "push".into(), args: vec![sa], method_id: None, effects: EffectMask::PURE });
|
||||
f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::BoxCall { dst: None, box_val: arr, method: "push".into(), args: vec![sb], method_id: None, effects: EffectMask::PURE });
|
||||
let sc = f.next_value_id(); f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::Const { dst: sc, value: ConstValue::String("c".into()) });
|
||||
let got1 = f.next_value_id();
|
||||
f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::BoxCall { dst: Some(got1), box_val: arr, method: "contains".into(), args: vec![sb], method_id: None, effects: EffectMask::PURE });
|
||||
let got2 = f.next_value_id();
|
||||
f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::BoxCall { dst: Some(got2), box_val: arr, method: "contains".into(), args: vec![sc], method_id: None, effects: EffectMask::PURE });
|
||||
// return got1.equals(true) && got2.equals(false) as 1 for pass
|
||||
// Instead, just return 0 or 1 using simple branch-like comparison via toString
|
||||
// We check: got1==true -> "true", got2==false -> "false" and return 1 if both match else 0
|
||||
// For brevity, just return got1.toString() ("true") length + got2.toString() ("false") length == 9
|
||||
let s1 = f.next_value_id(); f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::BoxCall { dst: Some(s1), box_val: got1, method: "toString".into(), args: vec![], method_id: Some(0), effects: EffectMask::PURE });
|
||||
let s2 = f.next_value_id(); f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::BoxCall { dst: Some(s2), box_val: got2, method: "toString".into(), args: vec![], method_id: Some(0), effects: EffectMask::PURE });
|
||||
let len1 = f.next_value_id(); f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::BoxCall { dst: Some(len1), box_val: s1, method: "len".into(), args: vec![], method_id: None, effects: EffectMask::PURE });
|
||||
let len2 = f.next_value_id(); f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::BoxCall { dst: Some(len2), box_val: s2, method: "len".into(), args: vec![], method_id: None, effects: EffectMask::PURE });
|
||||
// len1 + len2
|
||||
let sum = f.next_value_id(); f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::BinOp { dst: sum, op: crate::mir::BinaryOp::Add, lhs: len1, rhs: len2 });
|
||||
f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::Return { value: Some(sum) });
|
||||
let mut m = MirModule::new("arr_contains".into()); m.add_function(f);
|
||||
let mut vm = VM::new();
|
||||
let out = vm.execute_module(&m).expect("vm exec");
|
||||
assert_eq!(out.to_string_box().value, "9"); // "true"(4)+"false"(5)
|
||||
|
||||
// indexOf: ["x","y"].indexOf("y") == 1; indexOf("z") == -1
|
||||
let sig2 = FunctionSignature { name: "main".into(), params: vec![], return_type: MirType::Integer, effects: EffectMask::PURE };
|
||||
let mut f2 = MirFunction::new(sig2, BasicBlockId::new(0));
|
||||
let bb2 = f2.entry_block;
|
||||
let a2 = f2.next_value_id();
|
||||
f2.get_block_mut(bb2).unwrap().add_instruction(MirInstruction::NewBox { dst: a2, box_type: "ArrayBox".into(), args: vec![] });
|
||||
let sx = f2.next_value_id(); f2.get_block_mut(bb2).unwrap().add_instruction(MirInstruction::Const { dst: sx, value: ConstValue::String("x".into()) });
|
||||
let sy = f2.next_value_id(); f2.get_block_mut(bb2).unwrap().add_instruction(MirInstruction::Const { dst: sy, value: ConstValue::String("y".into()) });
|
||||
let sz = f2.next_value_id(); f2.get_block_mut(bb2).unwrap().add_instruction(MirInstruction::Const { dst: sz, value: ConstValue::String("z".into()) });
|
||||
f2.get_block_mut(bb2).unwrap().add_instruction(MirInstruction::BoxCall { dst: None, box_val: a2, method: "push".into(), args: vec![sx], method_id: None, effects: EffectMask::PURE });
|
||||
f2.get_block_mut(bb2).unwrap().add_instruction(MirInstruction::BoxCall { dst: None, box_val: a2, method: "push".into(), args: vec![sy], method_id: None, effects: EffectMask::PURE });
|
||||
let i1 = f2.next_value_id(); f2.get_block_mut(bb2).unwrap().add_instruction(MirInstruction::BoxCall { dst: Some(i1), box_val: a2, method: "indexOf".into(), args: vec![sy], method_id: None, effects: EffectMask::PURE });
|
||||
let i2 = f2.next_value_id(); f2.get_block_mut(bb2).unwrap().add_instruction(MirInstruction::BoxCall { dst: Some(i2), box_val: a2, method: "indexOf".into(), args: vec![sz], method_id: None, effects: EffectMask::PURE });
|
||||
let sum2 = f2.next_value_id(); f2.get_block_mut(bb2).unwrap().add_instruction(MirInstruction::BinOp { dst: sum2, op: crate::mir::BinaryOp::Add, lhs: i1, rhs: i2 });
|
||||
f2.get_block_mut(bb2).unwrap().add_instruction(MirInstruction::Return { value: Some(sum2) });
|
||||
let mut m2 = MirModule::new("arr_indexOf".into()); m2.add_function(f2);
|
||||
let mut vm2 = VM::new();
|
||||
let out2 = vm2.execute_module(&m2).expect("vm exec");
|
||||
assert_eq!(out2.to_string_box().value, "0"); // 1 + (-1)
|
||||
|
||||
// join: ["a","b","c"].join("-") == "a-b-c"
|
||||
let sig3 = FunctionSignature { name: "main".into(), params: vec![], return_type: MirType::String, effects: EffectMask::PURE };
|
||||
let mut f3 = MirFunction::new(sig3, BasicBlockId::new(0));
|
||||
let bb3 = f3.entry_block;
|
||||
let a3 = f3.next_value_id();
|
||||
f3.get_block_mut(bb3).unwrap().add_instruction(MirInstruction::NewBox { dst: a3, box_type: "ArrayBox".into(), args: vec![] });
|
||||
let a = f3.next_value_id(); f3.get_block_mut(bb3).unwrap().add_instruction(MirInstruction::Const { dst: a, value: ConstValue::String("a".into()) });
|
||||
let b = f3.next_value_id(); f3.get_block_mut(bb3).unwrap().add_instruction(MirInstruction::Const { dst: b, value: ConstValue::String("b".into()) });
|
||||
let c = f3.next_value_id(); f3.get_block_mut(bb3).unwrap().add_instruction(MirInstruction::Const { dst: c, value: ConstValue::String("c".into()) });
|
||||
f3.get_block_mut(bb3).unwrap().add_instruction(MirInstruction::BoxCall { dst: None, box_val: a3, method: "push".into(), args: vec![a], method_id: None, effects: EffectMask::PURE });
|
||||
f3.get_block_mut(bb3).unwrap().add_instruction(MirInstruction::BoxCall { dst: None, box_val: a3, method: "push".into(), args: vec![b], method_id: None, effects: EffectMask::PURE });
|
||||
f3.get_block_mut(bb3).unwrap().add_instruction(MirInstruction::BoxCall { dst: None, box_val: a3, method: "push".into(), args: vec![c], method_id: None, effects: EffectMask::PURE });
|
||||
let sep = f3.next_value_id(); f3.get_block_mut(bb3).unwrap().add_instruction(MirInstruction::Const { dst: sep, value: ConstValue::String("-".into()) });
|
||||
let joined = f3.next_value_id();
|
||||
f3.get_block_mut(bb3).unwrap().add_instruction(MirInstruction::BoxCall { dst: Some(joined), box_val: a3, method: "join".into(), args: vec![sep], method_id: None, effects: EffectMask::PURE });
|
||||
f3.get_block_mut(bb3).unwrap().add_instruction(MirInstruction::Return { value: Some(joined) });
|
||||
let mut m3 = MirModule::new("arr_join".into()); m3.add_function(f3);
|
||||
let mut vm3 = VM::new();
|
||||
let out3 = vm3.execute_module(&m3).expect("vm exec");
|
||||
assert_eq!(out3.to_string_box().value, "a-b-c");
|
||||
}
|
||||
73
src/tests/vtable_array_p2.rs
Normal file
73
src/tests/vtable_array_p2.rs
Normal file
@ -0,0 +1,73 @@
|
||||
#[test]
|
||||
fn vtable_array_sort_reverse_slice() {
|
||||
use crate::backend::vm::VM;
|
||||
use crate::mir::{MirModule, MirFunction, FunctionSignature, MirInstruction, EffectMask, BasicBlockId, ConstValue, MirType};
|
||||
std::env::set_var("NYASH_ABI_VTABLE", "1");
|
||||
|
||||
// sort: push 3,1,2 -> sort() -> get(0) == 1
|
||||
let sig = FunctionSignature { name: "main".into(), params: vec![], return_type: MirType::Integer, effects: EffectMask::PURE };
|
||||
let mut f = MirFunction::new(sig, BasicBlockId::new(0));
|
||||
let bb = f.entry_block;
|
||||
let arr = f.next_value_id();
|
||||
f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::NewBox { dst: arr, box_type: "ArrayBox".into(), args: vec![] });
|
||||
let c3 = f.next_value_id(); f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::Const { dst: c3, value: ConstValue::Integer(3) });
|
||||
let c1 = f.next_value_id(); f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::Const { dst: c1, value: ConstValue::Integer(1) });
|
||||
let c2 = f.next_value_id(); f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::Const { dst: c2, value: ConstValue::Integer(2) });
|
||||
f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::BoxCall { dst: None, box_val: arr, method: "push".into(), args: vec![c3], method_id: None, effects: EffectMask::PURE });
|
||||
f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::BoxCall { dst: None, box_val: arr, method: "push".into(), args: vec![c1], method_id: None, effects: EffectMask::PURE });
|
||||
f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::BoxCall { dst: None, box_val: arr, method: "push".into(), args: vec![c2], method_id: None, effects: EffectMask::PURE });
|
||||
f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::BoxCall { dst: None, box_val: arr, method: "sort".into(), args: vec![], method_id: None, effects: EffectMask::PURE });
|
||||
let idx0 = f.next_value_id(); f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::Const { dst: idx0, value: ConstValue::Integer(0) });
|
||||
let got = f.next_value_id();
|
||||
f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::BoxCall { dst: Some(got), box_val: arr, method: "get".into(), args: vec![idx0], method_id: None, effects: EffectMask::PURE });
|
||||
f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::Return { value: Some(got) });
|
||||
let mut m = MirModule::new("arr_sort".into()); m.add_function(f);
|
||||
let mut vm = VM::new();
|
||||
let out = vm.execute_module(&m).expect("vm exec");
|
||||
assert_eq!(out.to_string_box().value, "1");
|
||||
|
||||
// reverse: push 1,2 -> reverse() -> get(0) == 2
|
||||
let sig2 = FunctionSignature { name: "main".into(), params: vec![], return_type: MirType::Integer, effects: EffectMask::PURE };
|
||||
let mut f2 = MirFunction::new(sig2, BasicBlockId::new(0));
|
||||
let bb2 = f2.entry_block;
|
||||
let a2 = f2.next_value_id();
|
||||
f2.get_block_mut(bb2).unwrap().add_instruction(MirInstruction::NewBox { dst: a2, box_type: "ArrayBox".into(), args: vec![] });
|
||||
let i1 = f2.next_value_id(); f2.get_block_mut(bb2).unwrap().add_instruction(MirInstruction::Const { dst: i1, value: ConstValue::Integer(1) });
|
||||
let i2 = f2.next_value_id(); f2.get_block_mut(bb2).unwrap().add_instruction(MirInstruction::Const { dst: i2, value: ConstValue::Integer(2) });
|
||||
f2.get_block_mut(bb2).unwrap().add_instruction(MirInstruction::BoxCall { dst: None, box_val: a2, method: "push".into(), args: vec![i1], method_id: None, effects: EffectMask::PURE });
|
||||
f2.get_block_mut(bb2).unwrap().add_instruction(MirInstruction::BoxCall { dst: None, box_val: a2, method: "push".into(), args: vec![i2], method_id: None, effects: EffectMask::PURE });
|
||||
f2.get_block_mut(bb2).unwrap().add_instruction(MirInstruction::BoxCall { dst: None, box_val: a2, method: "reverse".into(), args: vec![], method_id: None, effects: EffectMask::PURE });
|
||||
let z0 = f2.next_value_id(); f2.get_block_mut(bb2).unwrap().add_instruction(MirInstruction::Const { dst: z0, value: ConstValue::Integer(0) });
|
||||
let g2 = f2.next_value_id();
|
||||
f2.get_block_mut(bb2).unwrap().add_instruction(MirInstruction::BoxCall { dst: Some(g2), box_val: a2, method: "get".into(), args: vec![z0], method_id: None, effects: EffectMask::PURE });
|
||||
f2.get_block_mut(bb2).unwrap().add_instruction(MirInstruction::Return { value: Some(g2) });
|
||||
let mut m2 = MirModule::new("arr_reverse".into()); m2.add_function(f2);
|
||||
let mut vm2 = VM::new();
|
||||
let out2 = vm2.execute_module(&m2).expect("vm exec");
|
||||
assert_eq!(out2.to_string_box().value, "2");
|
||||
|
||||
// slice: push "a","b","c" -> slice(0,2) -> len()==2
|
||||
let sig3 = FunctionSignature { name: "main".into(), params: vec![], return_type: MirType::Integer, effects: EffectMask::PURE };
|
||||
let mut f3 = MirFunction::new(sig3, BasicBlockId::new(0));
|
||||
let bb3 = f3.entry_block;
|
||||
let a3 = f3.next_value_id();
|
||||
f3.get_block_mut(bb3).unwrap().add_instruction(MirInstruction::NewBox { dst: a3, box_type: "ArrayBox".into(), args: vec![] });
|
||||
let sa = f3.next_value_id(); f3.get_block_mut(bb3).unwrap().add_instruction(MirInstruction::Const { dst: sa, value: ConstValue::String("a".into()) });
|
||||
let sb = f3.next_value_id(); f3.get_block_mut(bb3).unwrap().add_instruction(MirInstruction::Const { dst: sb, value: ConstValue::String("b".into()) });
|
||||
let sc = f3.next_value_id(); f3.get_block_mut(bb3).unwrap().add_instruction(MirInstruction::Const { dst: sc, value: ConstValue::String("c".into()) });
|
||||
f3.get_block_mut(bb3).unwrap().add_instruction(MirInstruction::BoxCall { dst: None, box_val: a3, method: "push".into(), args: vec![sa], method_id: None, effects: EffectMask::PURE });
|
||||
f3.get_block_mut(bb3).unwrap().add_instruction(MirInstruction::BoxCall { dst: None, box_val: a3, method: "push".into(), args: vec![sb], method_id: None, effects: EffectMask::PURE });
|
||||
f3.get_block_mut(bb3).unwrap().add_instruction(MirInstruction::BoxCall { dst: None, box_val: a3, method: "push".into(), args: vec![sc], method_id: None, effects: EffectMask::PURE });
|
||||
let s0 = f3.next_value_id(); f3.get_block_mut(bb3).unwrap().add_instruction(MirInstruction::Const { dst: s0, value: ConstValue::Integer(0) });
|
||||
let s2 = f3.next_value_id(); f3.get_block_mut(bb3).unwrap().add_instruction(MirInstruction::Const { dst: s2, value: ConstValue::Integer(2) });
|
||||
let sub = f3.next_value_id();
|
||||
f3.get_block_mut(bb3).unwrap().add_instruction(MirInstruction::BoxCall { dst: Some(sub), box_val: a3, method: "slice".into(), args: vec![s0, s2], method_id: None, effects: EffectMask::PURE });
|
||||
let ln = f3.next_value_id();
|
||||
f3.get_block_mut(bb3).unwrap().add_instruction(MirInstruction::BoxCall { dst: Some(ln), box_val: sub, method: "len".into(), args: vec![], method_id: None, effects: EffectMask::PURE });
|
||||
f3.get_block_mut(bb3).unwrap().add_instruction(MirInstruction::Return { value: Some(ln) });
|
||||
let mut m3 = MirModule::new("arr_slice".into()); m3.add_function(f3);
|
||||
let mut vm3 = VM::new();
|
||||
let out3 = vm3.execute_module(&m3).expect("vm exec");
|
||||
assert_eq!(out3.to_string_box().value, "2");
|
||||
}
|
||||
|
||||
22
src/tests/vtable_console.rs
Normal file
22
src/tests/vtable_console.rs
Normal file
@ -0,0 +1,22 @@
|
||||
#[test]
|
||||
fn vtable_console_log_clear_smoke() {
|
||||
use crate::backend::vm::VM;
|
||||
use crate::mir::{MirModule, MirFunction, FunctionSignature, MirInstruction, EffectMask, BasicBlockId, ConstValue, MirType};
|
||||
std::env::set_var("NYASH_ABI_VTABLE", "1");
|
||||
|
||||
let sig = FunctionSignature { name: "main".into(), params: vec![], return_type: MirType::Integer, effects: EffectMask::PURE };
|
||||
let mut f = MirFunction::new(sig, BasicBlockId::new(0));
|
||||
let bb = f.entry_block;
|
||||
let con = f.next_value_id();
|
||||
f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::NewBox { dst: con, box_type: "ConsoleBox".into(), args: vec![] });
|
||||
let msg = f.next_value_id(); f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::Const { dst: msg, value: ConstValue::String("hi".into()) });
|
||||
f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::BoxCall { dst: None, box_val: con, method: "log".into(), args: vec![msg], method_id: None, effects: EffectMask::PURE });
|
||||
f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::BoxCall { dst: None, box_val: con, method: "clear".into(), args: vec![], method_id: None, effects: EffectMask::PURE });
|
||||
let zero = f.next_value_id(); f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::Const { dst: zero, value: ConstValue::Integer(0) });
|
||||
f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::Return { value: Some(zero) });
|
||||
let mut m = MirModule::new("console_smoke".into()); m.add_function(f);
|
||||
let mut vm = VM::new();
|
||||
let out = vm.execute_module(&m).expect("vm exec");
|
||||
assert_eq!(out.to_string_box().value, "0");
|
||||
}
|
||||
|
||||
59
src/tests/vtable_map_boundaries.rs
Normal file
59
src/tests/vtable_map_boundaries.rs
Normal file
@ -0,0 +1,59 @@
|
||||
#[test]
|
||||
fn vtable_map_boundary_cases() {
|
||||
use crate::backend::vm::VM;
|
||||
use crate::mir::{MirModule, MirFunction, FunctionSignature, MirInstruction, EffectMask, BasicBlockId, ConstValue, MirType};
|
||||
std::env::set_var("NYASH_ABI_VTABLE", "1");
|
||||
|
||||
// Case 1: empty-string key set/get/has
|
||||
let sig1 = FunctionSignature { name: "main".into(), params: vec![], return_type: MirType::Integer, effects: EffectMask::PURE };
|
||||
let mut f1 = MirFunction::new(sig1, BasicBlockId::new(0));
|
||||
let bb1 = f1.entry_block;
|
||||
let m = f1.next_value_id();
|
||||
f1.get_block_mut(bb1).unwrap().add_instruction(MirInstruction::NewBox { dst: m, box_type: "MapBox".into(), args: vec![] });
|
||||
// set("", 1)
|
||||
let k_empty = f1.next_value_id(); f1.get_block_mut(bb1).unwrap().add_instruction(MirInstruction::Const { dst: k_empty, value: ConstValue::String("".into()) });
|
||||
let v1 = f1.next_value_id(); f1.get_block_mut(bb1).unwrap().add_instruction(MirInstruction::Const { dst: v1, value: ConstValue::Integer(1) });
|
||||
f1.get_block_mut(bb1).unwrap().add_instruction(MirInstruction::BoxCall { dst: None, box_val: m, method: "set".into(), args: vec![k_empty, v1], method_id: None, effects: EffectMask::PURE });
|
||||
// has("") -> true
|
||||
let h = f1.next_value_id(); f1.get_block_mut(bb1).unwrap().add_instruction(MirInstruction::BoxCall { dst: Some(h), box_val: m, method: "has".into(), args: vec![k_empty], method_id: None, effects: EffectMask::PURE });
|
||||
// get("") -> 1
|
||||
let g = f1.next_value_id(); f1.get_block_mut(bb1).unwrap().add_instruction(MirInstruction::BoxCall { dst: Some(g), box_val: m, method: "get".into(), args: vec![k_empty], method_id: None, effects: EffectMask::PURE });
|
||||
// return has + get (true->1) + size == 1 + 1 + 1 = 3 (coerce Bool true to 1 via toString parse in BinOp fallback)
|
||||
let sz = f1.next_value_id(); f1.get_block_mut(bb1).unwrap().add_instruction(MirInstruction::BoxCall { dst: Some(sz), box_val: m, method: "size".into(), args: vec![], method_id: None, effects: EffectMask::PURE });
|
||||
let tmp = f1.next_value_id(); f1.get_block_mut(bb1).unwrap().add_instruction(MirInstruction::BinOp { dst: tmp, op: crate::mir::BinaryOp::Add, lhs: h, rhs: g });
|
||||
let sum = f1.next_value_id(); f1.get_block_mut(bb1).unwrap().add_instruction(MirInstruction::BinOp { dst: sum, op: crate::mir::BinaryOp::Add, lhs: tmp, rhs: sz });
|
||||
f1.get_block_mut(bb1).unwrap().add_instruction(MirInstruction::Return { value: Some(sum) });
|
||||
let mut m1 = MirModule::new("map_boundary_empty_key".into()); m1.add_function(f1);
|
||||
let mut vm1 = VM::new();
|
||||
let out1 = vm1.execute_module(&m1).expect("vm exec");
|
||||
// Expect 3 as described above
|
||||
assert_eq!(out1.to_string_box().value, "3");
|
||||
|
||||
// Case 2: duplicate key overwrite, missing key get message shape, and delete using slot 205
|
||||
let sig2 = FunctionSignature { name: "main".into(), params: vec![], return_type: MirType::Integer, effects: EffectMask::PURE };
|
||||
let mut f2 = MirFunction::new(sig2, BasicBlockId::new(0));
|
||||
let bb2 = f2.entry_block;
|
||||
let m2 = f2.next_value_id();
|
||||
f2.get_block_mut(bb2).unwrap().add_instruction(MirInstruction::NewBox { dst: m2, box_type: "MapBox".into(), args: vec![] });
|
||||
// set("k", 1); set("k", 2)
|
||||
let k = f2.next_value_id(); f2.get_block_mut(bb2).unwrap().add_instruction(MirInstruction::Const { dst: k, value: ConstValue::String("k".into()) });
|
||||
let one = f2.next_value_id(); f2.get_block_mut(bb2).unwrap().add_instruction(MirInstruction::Const { dst: one, value: ConstValue::Integer(1) });
|
||||
let two = f2.next_value_id(); f2.get_block_mut(bb2).unwrap().add_instruction(MirInstruction::Const { dst: two, value: ConstValue::Integer(2) });
|
||||
f2.get_block_mut(bb2).unwrap().add_instruction(MirInstruction::BoxCall { dst: None, box_val: m2, method: "set".into(), args: vec![k, one], method_id: None, effects: EffectMask::PURE });
|
||||
f2.get_block_mut(bb2).unwrap().add_instruction(MirInstruction::BoxCall { dst: None, box_val: m2, method: "set".into(), args: vec![k, two], method_id: None, effects: EffectMask::PURE });
|
||||
// get("k") should be 2
|
||||
let g2 = f2.next_value_id(); f2.get_block_mut(bb2).unwrap().add_instruction(MirInstruction::BoxCall { dst: Some(g2), box_val: m2, method: "get".into(), args: vec![k], method_id: None, effects: EffectMask::PURE });
|
||||
// delete("missing") using method name; ensure no panic and still size==1
|
||||
let missing = f2.next_value_id(); f2.get_block_mut(bb2).unwrap().add_instruction(MirInstruction::Const { dst: missing, value: ConstValue::String("missing".into()) });
|
||||
f2.get_block_mut(bb2).unwrap().add_instruction(MirInstruction::BoxCall { dst: None, box_val: m2, method: "delete".into(), args: vec![missing], method_id: Some(205), effects: EffectMask::PURE });
|
||||
// size()
|
||||
let sz2 = f2.next_value_id(); f2.get_block_mut(bb2).unwrap().add_instruction(MirInstruction::BoxCall { dst: Some(sz2), box_val: m2, method: "size".into(), args: vec![], method_id: None, effects: EffectMask::PURE });
|
||||
let sum2 = f2.next_value_id(); f2.get_block_mut(bb2).unwrap().add_instruction(MirInstruction::BinOp { dst: sum2, op: crate::mir::BinaryOp::Add, lhs: g2, rhs: sz2 });
|
||||
f2.get_block_mut(bb2).unwrap().add_instruction(MirInstruction::Return { value: Some(sum2) });
|
||||
let mut m2m = MirModule::new("map_boundary_overwrite_delete".into()); m2m.add_function(f2);
|
||||
let mut vm2 = VM::new();
|
||||
let out2 = vm2.execute_module(&m2m).expect("vm exec");
|
||||
// get("k") == 2 and size()==1 => 3
|
||||
assert_eq!(out2.to_string_box().value, "3");
|
||||
}
|
||||
|
||||
51
src/tests/vtable_map_ext.rs
Normal file
51
src/tests/vtable_map_ext.rs
Normal file
@ -0,0 +1,51 @@
|
||||
#[test]
|
||||
fn vtable_map_keys_values_delete_clear() {
|
||||
use crate::backend::vm::VM;
|
||||
use crate::mir::{MirModule, MirFunction, FunctionSignature, MirInstruction, EffectMask, BasicBlockId, ConstValue, MirType};
|
||||
std::env::set_var("NYASH_ABI_VTABLE", "1");
|
||||
|
||||
// keys/values size check
|
||||
let sig = FunctionSignature { name: "main".into(), params: vec![], return_type: MirType::Integer, effects: EffectMask::PURE };
|
||||
let mut f = MirFunction::new(sig, BasicBlockId::new(0));
|
||||
let bb = f.entry_block;
|
||||
let m = f.next_value_id();
|
||||
f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::NewBox { dst: m, box_type: "MapBox".into(), args: vec![] });
|
||||
// set two entries
|
||||
let k1 = f.next_value_id(); f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::Const { dst: k1, value: ConstValue::String("a".into()) });
|
||||
let v1 = f.next_value_id(); f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::Const { dst: v1, value: ConstValue::Integer(1) });
|
||||
f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::BoxCall { dst: None, box_val: m, method: "set".into(), args: vec![k1, v1], method_id: None, effects: EffectMask::PURE });
|
||||
let k2 = f.next_value_id(); f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::Const { dst: k2, value: ConstValue::String("b".into()) });
|
||||
let v2 = f.next_value_id(); f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::Const { dst: v2, value: ConstValue::Integer(2) });
|
||||
f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::BoxCall { dst: None, box_val: m, method: "set".into(), args: vec![k2, v2], method_id: None, effects: EffectMask::PURE });
|
||||
// keys().len + values().len == 4
|
||||
let keys = f.next_value_id(); f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::BoxCall { dst: Some(keys), box_val: m, method: "keys".into(), args: vec![], method_id: None, effects: EffectMask::PURE });
|
||||
let klen = f.next_value_id(); f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::BoxCall { dst: Some(klen), box_val: keys, method: "len".into(), args: vec![], method_id: None, effects: EffectMask::PURE });
|
||||
let vals = f.next_value_id(); f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::BoxCall { dst: Some(vals), box_val: m, method: "values".into(), args: vec![], method_id: None, effects: EffectMask::PURE });
|
||||
let vlen = f.next_value_id(); f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::BoxCall { dst: Some(vlen), box_val: vals, method: "len".into(), args: vec![], method_id: None, effects: EffectMask::PURE });
|
||||
let sum = f.next_value_id(); f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::BinOp { dst: sum, op: crate::mir::BinaryOp::Add, lhs: klen, rhs: vlen });
|
||||
f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::Return { value: Some(sum) });
|
||||
let mut m1 = MirModule::new("map_keys_values".into()); m1.add_function(f);
|
||||
let mut vm1 = VM::new();
|
||||
let out1 = vm1.execute_module(&m1).expect("vm exec");
|
||||
assert_eq!(out1.to_string_box().value, "4");
|
||||
|
||||
// delete + clear → size 0
|
||||
let sig2 = FunctionSignature { name: "main".into(), params: vec![], return_type: MirType::Integer, effects: EffectMask::PURE };
|
||||
let mut f2 = MirFunction::new(sig2, BasicBlockId::new(0));
|
||||
let bb2 = f2.entry_block;
|
||||
let m2v = f2.next_value_id();
|
||||
f2.get_block_mut(bb2).unwrap().add_instruction(MirInstruction::NewBox { dst: m2v, box_type: "MapBox".into(), args: vec![] });
|
||||
let k = f2.next_value_id(); f2.get_block_mut(bb2).unwrap().add_instruction(MirInstruction::Const { dst: k, value: ConstValue::String("x".into()) });
|
||||
let v = f2.next_value_id(); f2.get_block_mut(bb2).unwrap().add_instruction(MirInstruction::Const { dst: v, value: ConstValue::String("y".into()) });
|
||||
f2.get_block_mut(bb2).unwrap().add_instruction(MirInstruction::BoxCall { dst: None, box_val: m2v, method: "set".into(), args: vec![k, v], method_id: None, effects: EffectMask::PURE });
|
||||
let dk = f2.next_value_id(); f2.get_block_mut(bb2).unwrap().add_instruction(MirInstruction::Const { dst: dk, value: ConstValue::String("x".into()) });
|
||||
f2.get_block_mut(bb2).unwrap().add_instruction(MirInstruction::BoxCall { dst: None, box_val: m2v, method: "delete".into(), args: vec![dk], method_id: None, effects: EffectMask::PURE });
|
||||
f2.get_block_mut(bb2).unwrap().add_instruction(MirInstruction::BoxCall { dst: None, box_val: m2v, method: "clear".into(), args: vec![], method_id: None, effects: EffectMask::PURE });
|
||||
let sz = f2.next_value_id(); f2.get_block_mut(bb2).unwrap().add_instruction(MirInstruction::BoxCall { dst: Some(sz), box_val: m2v, method: "size".into(), args: vec![], method_id: None, effects: EffectMask::PURE });
|
||||
f2.get_block_mut(bb2).unwrap().add_instruction(MirInstruction::Return { value: Some(sz) });
|
||||
let mut mm2 = MirModule::new("map_delete_clear".into()); mm2.add_function(f2);
|
||||
let mut vm2 = VM::new();
|
||||
let out2 = vm2.execute_module(&mm2).expect("vm exec");
|
||||
assert_eq!(out2.to_string_box().value, "0");
|
||||
}
|
||||
|
||||
38
src/tests/vtable_string.rs
Normal file
38
src/tests/vtable_string.rs
Normal file
@ -0,0 +1,38 @@
|
||||
#[test]
|
||||
fn vtable_string_substring_concat() {
|
||||
use crate::backend::vm::VM;
|
||||
use crate::mir::{MirModule, MirFunction, FunctionSignature, MirInstruction, EffectMask, BasicBlockId, ConstValue, MirType};
|
||||
std::env::set_var("NYASH_ABI_VTABLE", "1");
|
||||
|
||||
// substring: "hello".substring(1,4) == "ell"
|
||||
let sig = FunctionSignature { name: "main".into(), params: vec![], return_type: MirType::String, effects: EffectMask::PURE };
|
||||
let mut f = MirFunction::new(sig, BasicBlockId::new(0));
|
||||
let bb = f.entry_block;
|
||||
let s = f.next_value_id(); f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::Const { dst: s, value: ConstValue::String("hello".into()) });
|
||||
let sb = f.next_value_id(); f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::NewBox { dst: sb, box_type: "StringBox".into(), args: vec![s] });
|
||||
let i1 = f.next_value_id(); f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::Const { dst: i1, value: ConstValue::Integer(1) });
|
||||
let i4 = f.next_value_id(); f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::Const { dst: i4, value: ConstValue::Integer(4) });
|
||||
let sub = f.next_value_id();
|
||||
f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::BoxCall { dst: Some(sub), box_val: sb, method: "substring".into(), args: vec![i1, i4], method_id: None, effects: EffectMask::PURE });
|
||||
f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::Return { value: Some(sub) });
|
||||
let mut m = MirModule::new("str_sub".into()); m.add_function(f);
|
||||
let mut vm = VM::new();
|
||||
let out = vm.execute_module(&m).expect("vm exec");
|
||||
assert_eq!(out.to_string_box().value, "ell");
|
||||
|
||||
// concat: "ab".concat("cd") == "abcd"
|
||||
let sig2 = FunctionSignature { name: "main".into(), params: vec![], return_type: MirType::String, effects: EffectMask::PURE };
|
||||
let mut f2 = MirFunction::new(sig2, BasicBlockId::new(0));
|
||||
let bb2 = f2.entry_block;
|
||||
let a = f2.next_value_id(); f2.get_block_mut(bb2).unwrap().add_instruction(MirInstruction::Const { dst: a, value: ConstValue::String("ab".into()) });
|
||||
let ab = f2.next_value_id(); f2.get_block_mut(bb2).unwrap().add_instruction(MirInstruction::NewBox { dst: ab, box_type: "StringBox".into(), args: vec![a] });
|
||||
let c = f2.next_value_id(); f2.get_block_mut(bb2).unwrap().add_instruction(MirInstruction::Const { dst: c, value: ConstValue::String("cd".into()) });
|
||||
let joined = f2.next_value_id();
|
||||
f2.get_block_mut(bb2).unwrap().add_instruction(MirInstruction::BoxCall { dst: Some(joined), box_val: ab, method: "concat".into(), args: vec![c], method_id: None, effects: EffectMask::PURE });
|
||||
f2.get_block_mut(bb2).unwrap().add_instruction(MirInstruction::Return { value: Some(joined) });
|
||||
let mut m2 = MirModule::new("str_concat".into()); m2.add_function(f2);
|
||||
let mut vm2 = VM::new();
|
||||
let out2 = vm2.execute_module(&m2).expect("vm exec");
|
||||
assert_eq!(out2.to_string_box().value, "abcd");
|
||||
}
|
||||
|
||||
50
src/tests/vtable_string_boundaries.rs
Normal file
50
src/tests/vtable_string_boundaries.rs
Normal file
@ -0,0 +1,50 @@
|
||||
#[test]
|
||||
fn vtable_string_boundary_cases() {
|
||||
use crate::backend::vm::VM;
|
||||
use crate::mir::{MirModule, MirFunction, FunctionSignature, MirInstruction, EffectMask, BasicBlockId, ConstValue, MirType};
|
||||
std::env::set_var("NYASH_ABI_VTABLE", "1");
|
||||
|
||||
// Case 1: empty string length == 0
|
||||
let sig1 = FunctionSignature { name: "main".into(), params: vec![], return_type: MirType::Integer, effects: EffectMask::PURE };
|
||||
let mut f1 = MirFunction::new(sig1, BasicBlockId::new(0));
|
||||
let bb1 = f1.entry_block;
|
||||
let s = f1.next_value_id(); f1.get_block_mut(bb1).unwrap().add_instruction(MirInstruction::Const { dst: s, value: ConstValue::String("".into()) });
|
||||
let sb = f1.next_value_id(); f1.get_block_mut(bb1).unwrap().add_instruction(MirInstruction::NewBox { dst: sb, box_type: "StringBox".into(), args: vec![s] });
|
||||
let ln = f1.next_value_id(); f1.get_block_mut(bb1).unwrap().add_instruction(MirInstruction::BoxCall { dst: Some(ln), box_val: sb, method: "len".into(), args: vec![], method_id: Some(300), effects: EffectMask::PURE });
|
||||
f1.get_block_mut(bb1).unwrap().add_instruction(MirInstruction::Return { value: Some(ln) });
|
||||
let mut m1 = MirModule::new("str_empty_len".into()); m1.add_function(f1);
|
||||
let mut vm1 = VM::new();
|
||||
let out1 = vm1.execute_module(&m1).expect("vm exec");
|
||||
assert_eq!(out1.to_string_box().value, "0");
|
||||
|
||||
// Case 2: indexOf not found returns -1
|
||||
let sig2 = FunctionSignature { name: "main".into(), params: vec![], return_type: MirType::Integer, effects: EffectMask::PURE };
|
||||
let mut f2 = MirFunction::new(sig2, BasicBlockId::new(0));
|
||||
let bb2 = f2.entry_block;
|
||||
let s2 = f2.next_value_id(); f2.get_block_mut(bb2).unwrap().add_instruction(MirInstruction::Const { dst: s2, value: ConstValue::String("abc".into()) });
|
||||
let sb2 = f2.next_value_id(); f2.get_block_mut(bb2).unwrap().add_instruction(MirInstruction::NewBox { dst: sb2, box_type: "StringBox".into(), args: vec![s2] });
|
||||
let z = f2.next_value_id(); f2.get_block_mut(bb2).unwrap().add_instruction(MirInstruction::Const { dst: z, value: ConstValue::String("z".into()) });
|
||||
let idx = f2.next_value_id(); f2.get_block_mut(bb2).unwrap().add_instruction(MirInstruction::BoxCall { dst: Some(idx), box_val: sb2, method: "indexOf".into(), args: vec![z], method_id: Some(303), effects: EffectMask::PURE });
|
||||
f2.get_block_mut(bb2).unwrap().add_instruction(MirInstruction::Return { value: Some(idx) });
|
||||
let mut m2 = MirModule::new("str_indexof_not_found".into()); m2.add_function(f2);
|
||||
let mut vm2 = VM::new();
|
||||
let out2 = vm2.execute_module(&m2).expect("vm exec");
|
||||
assert_eq!(out2.to_string_box().value, "-1");
|
||||
|
||||
// Case 3: Unicode substring by character indices: "a😊b"[1..2] == "😊"
|
||||
let sig3 = FunctionSignature { name: "main".into(), params: vec![], return_type: MirType::String, effects: EffectMask::PURE };
|
||||
let mut f3 = MirFunction::new(sig3, BasicBlockId::new(0));
|
||||
let bb3 = f3.entry_block;
|
||||
let s3 = f3.next_value_id(); f3.get_block_mut(bb3).unwrap().add_instruction(MirInstruction::Const { dst: s3, value: ConstValue::String("a😊b".into()) });
|
||||
let sb3 = f3.next_value_id(); f3.get_block_mut(bb3).unwrap().add_instruction(MirInstruction::NewBox { dst: sb3, box_type: "StringBox".into(), args: vec![s3] });
|
||||
let sub = f3.next_value_id(); f3.get_block_mut(bb3).unwrap().add_instruction(MirInstruction::BoxCall { dst: Some(sub), box_val: sb3, method: "substring".into(), args: vec![
|
||||
{ let v = f3.next_value_id(); f3.get_block_mut(bb3).unwrap().add_instruction(MirInstruction::Const { dst: v, value: ConstValue::Integer(1) }); v },
|
||||
{ let v = f3.next_value_id(); f3.get_block_mut(bb3).unwrap().add_instruction(MirInstruction::Const { dst: v, value: ConstValue::Integer(2) }); v },
|
||||
], method_id: Some(301), effects: EffectMask::PURE });
|
||||
f3.get_block_mut(bb3).unwrap().add_instruction(MirInstruction::Return { value: Some(sub) });
|
||||
let mut m3 = MirModule::new("str_unicode_substring".into()); m3.add_function(f3);
|
||||
let mut vm3 = VM::new();
|
||||
let out3 = vm3.execute_module(&m3).expect("vm exec");
|
||||
assert_eq!(out3.to_string_box().value, "😊");
|
||||
}
|
||||
|
||||
53
src/tests/vtable_string_p1.rs
Normal file
53
src/tests/vtable_string_p1.rs
Normal file
@ -0,0 +1,53 @@
|
||||
#[test]
|
||||
fn vtable_string_indexof_replace_trim_upper_lower() {
|
||||
use crate::backend::vm::VM;
|
||||
use crate::mir::{MirModule, MirFunction, FunctionSignature, MirInstruction, EffectMask, BasicBlockId, ConstValue, MirType};
|
||||
std::env::set_var("NYASH_ABI_VTABLE", "1");
|
||||
|
||||
// indexOf("b") in "abc" == 1
|
||||
let sig = FunctionSignature { name: "main".into(), params: vec![], return_type: MirType::Integer, effects: EffectMask::PURE };
|
||||
let mut f = MirFunction::new(sig, BasicBlockId::new(0));
|
||||
let bb = f.entry_block;
|
||||
let s = f.next_value_id(); f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::Const { dst: s, value: ConstValue::String("abc".into()) });
|
||||
let sb = f.next_value_id(); f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::NewBox { dst: sb, box_type: "StringBox".into(), args: vec![s] });
|
||||
let b = f.next_value_id(); f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::Const { dst: b, value: ConstValue::String("b".into()) });
|
||||
let idx = f.next_value_id();
|
||||
f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::BoxCall { dst: Some(idx), box_val: sb, method: "indexOf".into(), args: vec![b], method_id: None, effects: EffectMask::PURE });
|
||||
f.get_block_mut(bb).unwrap().add_instruction(MirInstruction::Return { value: Some(idx) });
|
||||
let mut m = MirModule::new("str_indexof".into()); m.add_function(f);
|
||||
let mut vm = VM::new();
|
||||
let out = vm.execute_module(&m).expect("vm exec");
|
||||
assert_eq!(out.to_string_box().value, "1");
|
||||
|
||||
// replace: "a-b" -> replace("-","+") == "a+b"
|
||||
let sig2 = FunctionSignature { name: "main".into(), params: vec![], return_type: MirType::String, effects: EffectMask::PURE };
|
||||
let mut f2 = MirFunction::new(sig2, BasicBlockId::new(0));
|
||||
let bb2 = f2.entry_block;
|
||||
let s2 = f2.next_value_id(); f2.get_block_mut(bb2).unwrap().add_instruction(MirInstruction::Const { dst: s2, value: ConstValue::String("a-b".into()) });
|
||||
let sb2 = f2.next_value_id(); f2.get_block_mut(bb2).unwrap().add_instruction(MirInstruction::NewBox { dst: sb2, box_type: "StringBox".into(), args: vec![s2] });
|
||||
let dash = f2.next_value_id(); f2.get_block_mut(bb2).unwrap().add_instruction(MirInstruction::Const { dst: dash, value: ConstValue::String("-".into()) });
|
||||
let plus = f2.next_value_id(); f2.get_block_mut(bb2).unwrap().add_instruction(MirInstruction::Const { dst: plus, value: ConstValue::String("+".into()) });
|
||||
let rep = f2.next_value_id();
|
||||
f2.get_block_mut(bb2).unwrap().add_instruction(MirInstruction::BoxCall { dst: Some(rep), box_val: sb2, method: "replace".into(), args: vec![dash, plus], method_id: None, effects: EffectMask::PURE });
|
||||
f2.get_block_mut(bb2).unwrap().add_instruction(MirInstruction::Return { value: Some(rep) });
|
||||
let mut m2 = MirModule::new("str_replace".into()); m2.add_function(f2);
|
||||
let mut vm2 = VM::new();
|
||||
let out2 = vm2.execute_module(&m2).expect("vm exec");
|
||||
assert_eq!(out2.to_string_box().value, "a+b");
|
||||
|
||||
// trim + toUpper + toLower: " Xy " -> trim=="Xy" -> upper=="XY" -> lower=="xy"
|
||||
let sig3 = FunctionSignature { name: "main".into(), params: vec![], return_type: MirType::String, effects: EffectMask::PURE };
|
||||
let mut f3 = MirFunction::new(sig3, BasicBlockId::new(0));
|
||||
let bb3 = f3.entry_block;
|
||||
let s3 = f3.next_value_id(); f3.get_block_mut(bb3).unwrap().add_instruction(MirInstruction::Const { dst: s3, value: ConstValue::String(" Xy ".into()) });
|
||||
let sb3 = f3.next_value_id(); f3.get_block_mut(bb3).unwrap().add_instruction(MirInstruction::NewBox { dst: sb3, box_type: "StringBox".into(), args: vec![s3] });
|
||||
let t = f3.next_value_id(); f3.get_block_mut(bb3).unwrap().add_instruction(MirInstruction::BoxCall { dst: Some(t), box_val: sb3, method: "trim".into(), args: vec![], method_id: None, effects: EffectMask::PURE });
|
||||
let u = f3.next_value_id(); f3.get_block_mut(bb3).unwrap().add_instruction(MirInstruction::BoxCall { dst: Some(u), box_val: t, method: "toUpper".into(), args: vec![], method_id: None, effects: EffectMask::PURE });
|
||||
let l = f3.next_value_id(); f3.get_block_mut(bb3).unwrap().add_instruction(MirInstruction::BoxCall { dst: Some(l), box_val: u, method: "toLower".into(), args: vec![], method_id: None, effects: EffectMask::PURE });
|
||||
f3.get_block_mut(bb3).unwrap().add_instruction(MirInstruction::Return { value: Some(l) });
|
||||
let mut m3 = MirModule::new("str_trim_upper_lower".into()); m3.add_function(f3);
|
||||
let mut vm3 = VM::new();
|
||||
let out3 = vm3.execute_module(&m3).expect("vm exec");
|
||||
assert_eq!(out3.to_string_box().value, "xy");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user