refactor: 大規模ファイル分割とプラグインリファクタリング

## 🎯 プラグイン整理
-  **nyash-json-plugin**: プロバイダー抽象化、NodeRep統一
-  **nyash-string-plugin**: TLVヘルパー整理
-  **nyash-net-plugin**: HTTPヘルパー分離、ソケット管理改善
-  **nyash-counter-plugin/fixture-plugin**: 基本構造整理

## 📂 mir_interpreter分割
-  **mir_interpreter.rs → mir_interpreter/ディレクトリ**
  - mod.rs: メイン構造体定義
  - execution.rs: 実行エンジン
  - memory.rs: メモリ管理
  - instructions/: 命令別実装

## 🔧 その他の改善
- テストファイル群の最適化
- LLVMコンパイラのメイン関数整理
- 不要なインポート削除

1000行超のファイルを適切なモジュール構造に分割完了!

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Selfhosting Dev
2025-09-25 01:09:48 +09:00
parent d052f9dc97
commit 824ca600ea
27 changed files with 1605 additions and 1060 deletions

View File

@ -0,0 +1,125 @@
use super::*;
use crate::mir::basic_block::BasicBlock;
use std::mem;
impl MirInterpreter {
pub(super) fn exec_function_inner(
&mut self,
func: &MirFunction,
arg_vals: Option<&[VMValue]>,
) -> Result<VMValue, VMError> {
let saved_regs = mem::take(&mut self.regs);
let saved_fn = self.cur_fn.clone();
self.cur_fn = Some(func.signature.name.clone());
if let Some(args) = arg_vals {
for (i, pid) in func.params.iter().enumerate() {
let v = args.get(i).cloned().unwrap_or(VMValue::Void);
self.regs.insert(*pid, v);
}
}
let mut cur = func.entry_block;
let mut last_pred: Option<BasicBlockId> = None;
loop {
let block = func
.blocks
.get(&cur)
.ok_or_else(|| VMError::InvalidBasicBlock(format!("bb {:?} not found", cur)))?;
self.apply_phi_nodes(block, last_pred)?;
self.execute_block_instructions(block)?;
match self.handle_terminator(block)? {
BlockOutcome::Return(result) => {
self.cur_fn = saved_fn;
self.regs = saved_regs;
return Ok(result);
}
BlockOutcome::Next {
target,
predecessor,
} => {
last_pred = Some(predecessor);
cur = target;
}
}
}
}
fn apply_phi_nodes(
&mut self,
block: &BasicBlock,
last_pred: Option<BasicBlockId>,
) -> Result<(), VMError> {
for inst in block.phi_instructions() {
if let MirInstruction::Phi { dst, inputs } = inst {
let dst_id = *dst;
if let Some(pred) = last_pred {
if let Some((_, val)) = inputs.iter().find(|(bb, _)| *bb == pred) {
let v = self.reg_load(*val)?;
self.regs.insert(dst_id, v);
}
} else if let Some((_, val)) = inputs.first() {
let v = self.reg_load(*val)?;
self.regs.insert(dst_id, v);
}
}
}
Ok(())
}
fn execute_block_instructions(&mut self, block: &BasicBlock) -> Result<(), VMError> {
for inst in block.non_phi_instructions() {
self.execute_instruction(inst)?;
}
Ok(())
}
fn handle_terminator(&mut self, block: &BasicBlock) -> Result<BlockOutcome, VMError> {
match &block.terminator {
Some(MirInstruction::Return { value }) => {
let result = if let Some(v) = value {
self.reg_load(*v)?
} else {
VMValue::Void
};
Ok(BlockOutcome::Return(result))
}
Some(MirInstruction::Jump { target }) => Ok(BlockOutcome::Next {
target: *target,
predecessor: block.id,
}),
Some(MirInstruction::Branch {
condition,
then_bb,
else_bb,
}) => {
let cond = self.reg_load(*condition)?;
let branch = to_bool_vm(&cond).map_err(VMError::TypeError)?;
let target = if branch { *then_bb } else { *else_bb };
Ok(BlockOutcome::Next {
target,
predecessor: block.id,
})
}
None => Err(VMError::InvalidBasicBlock(format!(
"unterminated block {:?}",
block.id
))),
Some(other) => Err(VMError::InvalidInstruction(format!(
"invalid terminator in MIR interp: {:?}",
other
))),
}
}
}
enum BlockOutcome {
Return(VMValue),
Next {
target: BasicBlockId,
predecessor: BasicBlockId,
},
}

View File

@ -0,0 +1,82 @@
use super::*;
impl MirInterpreter {
pub(super) fn handle_const(&mut self, dst: ValueId, value: &ConstValue) -> Result<(), VMError> {
let v = match value {
ConstValue::Integer(i) => VMValue::Integer(*i),
ConstValue::Float(f) => VMValue::Float(*f),
ConstValue::Bool(b) => VMValue::Bool(*b),
ConstValue::String(s) => VMValue::String(s.clone()),
ConstValue::Null | ConstValue::Void => VMValue::Void,
};
self.regs.insert(dst, v);
Ok(())
}
pub(super) fn handle_binop(
&mut self,
dst: ValueId,
op: BinaryOp,
lhs: ValueId,
rhs: ValueId,
) -> Result<(), VMError> {
let a = self.reg_load(lhs)?;
let b = self.reg_load(rhs)?;
let v = self.eval_binop(op, a, b)?;
self.regs.insert(dst, v);
Ok(())
}
pub(super) fn handle_unary_op(
&mut self,
dst: ValueId,
op: crate::mir::UnaryOp,
operand: ValueId,
) -> Result<(), VMError> {
let x = self.reg_load(operand)?;
let v = match op {
crate::mir::UnaryOp::Neg => match x {
VMValue::Integer(i) => VMValue::Integer(-i),
VMValue::Float(f) => VMValue::Float(-f),
_ => {
return Err(VMError::TypeError(format!(
"neg expects number, got {:?}",
x
)))
}
},
crate::mir::UnaryOp::Not => VMValue::Bool(!to_bool_vm(&x).map_err(VMError::TypeError)?),
crate::mir::UnaryOp::BitNot => match x {
VMValue::Integer(i) => VMValue::Integer(!i),
_ => {
return Err(VMError::TypeError(format!(
"bitnot expects integer, got {:?}",
x
)))
}
},
};
self.regs.insert(dst, v);
Ok(())
}
pub(super) fn handle_compare(
&mut self,
dst: ValueId,
op: CompareOp,
lhs: ValueId,
rhs: ValueId,
) -> Result<(), VMError> {
let a = self.reg_load(lhs)?;
let b = self.reg_load(rhs)?;
let res = self.eval_cmp(op, a, b)?;
self.regs.insert(dst, VMValue::Bool(res));
Ok(())
}
pub(super) fn handle_copy(&mut self, dst: ValueId, src: ValueId) -> Result<(), VMError> {
let v = self.reg_load(src)?;
self.regs.insert(dst, v);
Ok(())
}
}

View File

@ -0,0 +1,265 @@
use super::*;
use crate::box_trait::NyashBox;
impl MirInterpreter {
pub(super) fn handle_new_box(
&mut self,
dst: ValueId,
box_type: &str,
args: &[ValueId],
) -> Result<(), VMError> {
let mut converted: Vec<Box<dyn NyashBox>> = Vec::with_capacity(args.len());
for vid in args {
converted.push(self.reg_load(*vid)?.to_nyash_box());
}
let reg = crate::runtime::unified_registry::get_global_unified_registry();
let created = reg
.lock()
.unwrap()
.create_box(box_type, &converted)
.map_err(|e| {
VMError::InvalidInstruction(format!("NewBox {} failed: {}", box_type, e))
})?;
self.regs.insert(dst, VMValue::from_nyash_box(created));
Ok(())
}
pub(super) fn handle_plugin_invoke(
&mut self,
dst: Option<ValueId>,
box_val: ValueId,
method: &str,
args: &[ValueId],
) -> Result<(), VMError> {
let recv = self.reg_load(box_val)?;
let recv_box: Box<dyn NyashBox> = match recv.clone() {
VMValue::BoxRef(b) => b.share_box(),
other => other.to_nyash_box(),
};
if let Some(p) = recv_box
.as_any()
.downcast_ref::<crate::runtime::plugin_loader_v2::PluginBoxV2>()
{
let host = crate::runtime::plugin_loader_unified::get_global_plugin_host();
let host = host.read().unwrap();
let mut argv: Vec<Box<dyn NyashBox>> = Vec::with_capacity(args.len());
for a in args {
argv.push(self.reg_load(*a)?.to_nyash_box());
}
match host.invoke_instance_method(&p.box_type, method, p.inner.instance_id, &argv) {
Ok(Some(ret)) => {
if let Some(d) = dst {
self.regs.insert(d, VMValue::from_nyash_box(ret));
}
}
Ok(None) => {
if let Some(d) = dst {
self.regs.insert(d, VMValue::Void);
}
}
Err(e) => {
return Err(VMError::InvalidInstruction(format!(
"PluginInvoke {}.{} failed: {:?}",
p.box_type, method, e
)))
}
}
Ok(())
} else if method == "toString" {
if let Some(d) = dst {
self.regs
.insert(d, VMValue::String(recv_box.to_string_box().value));
}
Ok(())
} else {
Err(VMError::InvalidInstruction(format!(
"PluginInvoke unsupported on {} for method {}",
recv_box.type_name(),
method
)))
}
}
pub(super) fn handle_box_call(
&mut self,
dst: Option<ValueId>,
box_val: ValueId,
method: &str,
args: &[ValueId],
) -> Result<(), VMError> {
if self.try_handle_object_fields(dst, box_val, method, args)? {
return Ok(());
}
if self.try_handle_string_box(dst, box_val, method, args)? {
return Ok(());
}
self.invoke_plugin_box(dst, box_val, method, args)
}
fn try_handle_object_fields(
&mut self,
dst: Option<ValueId>,
box_val: ValueId,
method: &str,
args: &[ValueId],
) -> Result<bool, VMError> {
match method {
"getField" => {
if args.len() != 1 {
return Err(VMError::InvalidInstruction("getField expects 1 arg".into()));
}
let fname = match self.reg_load(args[0])? {
VMValue::String(s) => s,
v => v.to_string(),
};
let v = self
.obj_fields
.get(&box_val)
.and_then(|m| m.get(&fname))
.cloned()
.unwrap_or(VMValue::Void);
if let Some(d) = dst {
self.regs.insert(d, v);
}
Ok(true)
}
"setField" => {
if args.len() != 2 {
return Err(VMError::InvalidInstruction(
"setField expects 2 args".into(),
));
}
let fname = match self.reg_load(args[0])? {
VMValue::String(s) => s,
v => v.to_string(),
};
let valv = self.reg_load(args[1])?;
self.obj_fields
.entry(box_val)
.or_default()
.insert(fname, valv);
Ok(true)
}
_ => Ok(false),
}
}
fn try_handle_string_box(
&mut self,
dst: Option<ValueId>,
box_val: ValueId,
method: &str,
args: &[ValueId],
) -> Result<bool, VMError> {
let recv = self.reg_load(box_val)?;
let recv_box_any: Box<dyn NyashBox> = match recv.clone() {
VMValue::BoxRef(b) => b.share_box(),
other => other.to_nyash_box(),
};
if let Some(sb) = recv_box_any
.as_any()
.downcast_ref::<crate::box_trait::StringBox>()
{
match method {
"length" => {
let ret = sb.length();
if let Some(d) = dst {
self.regs.insert(d, VMValue::from_nyash_box(ret));
}
return Ok(true);
}
"concat" => {
if args.len() != 1 {
return Err(VMError::InvalidInstruction("concat expects 1 arg".into()));
}
let rhs = self.reg_load(args[0])?;
let new_s = format!("{}{}", sb.value, rhs.to_string());
if let Some(d) = dst {
self.regs.insert(
d,
VMValue::from_nyash_box(Box::new(crate::box_trait::StringBox::new(
new_s,
))),
);
}
return Ok(true);
}
_ => {}
}
}
Ok(false)
}
fn invoke_plugin_box(
&mut self,
dst: Option<ValueId>,
box_val: ValueId,
method: &str,
args: &[ValueId],
) -> Result<(), VMError> {
let recv = self.reg_load(box_val)?;
let recv_box: Box<dyn NyashBox> = match recv.clone() {
VMValue::BoxRef(b) => b.share_box(),
other => other.to_nyash_box(),
};
if let Some(p) = recv_box
.as_any()
.downcast_ref::<crate::runtime::plugin_loader_v2::PluginBoxV2>()
{
if p.box_type == "ConsoleBox" && method == "readLine" {
use std::io::{self, Read};
let mut s = String::new();
let mut stdin = io::stdin();
let mut buf = [0u8; 1];
while let Ok(n) = stdin.read(&mut buf) {
if n == 0 {
break;
}
let ch = buf[0] as char;
if ch == '\n' {
break;
}
s.push(ch);
if s.len() > 1_000_000 {
break;
}
}
if let Some(d) = dst {
self.regs.insert(d, VMValue::String(s));
}
return Ok(());
}
let host = crate::runtime::plugin_loader_unified::get_global_plugin_host();
let host = host.read().unwrap();
let mut argv: Vec<Box<dyn NyashBox>> = Vec::with_capacity(args.len());
for a in args {
argv.push(self.reg_load(*a)?.to_nyash_box());
}
match host.invoke_instance_method(&p.box_type, method, p.inner.instance_id, &argv) {
Ok(Some(ret)) => {
if let Some(d) = dst {
self.regs.insert(d, VMValue::from_nyash_box(ret));
}
Ok(())
}
Ok(None) => {
if let Some(d) = dst {
self.regs.insert(d, VMValue::Void);
}
Ok(())
}
Err(e) => Err(VMError::InvalidInstruction(format!(
"BoxCall {}.{} failed: {:?}",
p.box_type, method, e
))),
}
} else {
Err(VMError::InvalidInstruction(format!(
"BoxCall unsupported on {}.{}",
recv_box.type_name(),
method
)))
}
}
}

View File

@ -0,0 +1,252 @@
use super::*;
impl MirInterpreter {
pub(super) fn handle_call(
&mut self,
dst: Option<ValueId>,
func: ValueId,
callee: Option<&Callee>,
args: &[ValueId],
) -> Result<(), VMError> {
let call_result = if let Some(callee_type) = callee {
self.execute_callee_call(callee_type, args)?
} else {
self.execute_legacy_call(func, args)?
};
if let Some(d) = dst {
self.regs.insert(d, call_result);
}
Ok(())
}
pub(super) fn execute_callee_call(
&mut self,
callee: &Callee,
args: &[ValueId],
) -> Result<VMValue, VMError> {
match callee {
Callee::Global(func_name) => self.execute_global_function(func_name, args),
Callee::Method {
box_name: _,
method,
receiver,
} => {
if let Some(recv_id) = receiver {
let recv_val = self.reg_load(*recv_id)?;
self.execute_method_call(&recv_val, method, args)
} else {
Err(VMError::InvalidInstruction(format!(
"Method call missing receiver for {}",
method
)))
}
}
Callee::Constructor { box_type } => Err(VMError::InvalidInstruction(format!(
"Constructor calls not yet implemented for {}",
box_type
))),
Callee::Closure { .. } => Err(VMError::InvalidInstruction(
"Closure creation not yet implemented in VM".into(),
)),
Callee::Value(func_val_id) => {
let _func_val = self.reg_load(*func_val_id)?;
Err(VMError::InvalidInstruction(
"First-class function calls not yet implemented in VM".into(),
))
}
Callee::Extern(extern_name) => self.execute_extern_function(extern_name, args),
}
}
pub(super) fn execute_legacy_call(
&mut self,
func_id: ValueId,
args: &[ValueId],
) -> Result<VMValue, VMError> {
let name_val = self.reg_load(func_id)?;
let raw = match name_val {
VMValue::String(ref s) => s.clone(),
other => other.to_string(),
};
let mut pick: Option<String> = None;
if self.functions.contains_key(&raw) {
pick = Some(raw.clone());
} else {
let arity = args.len();
let mut cands: Vec<String> = Vec::new();
let suf = format!(".{}{}", raw, format!("/{}", arity));
for k in self.functions.keys() {
if k.ends_with(&suf) {
cands.push(k.clone());
}
}
if cands.is_empty() && raw.contains('/') && self.functions.contains_key(&raw) {
cands.push(raw.clone());
}
if cands.len() > 1 {
if let Some(cur) = &self.cur_fn {
let cur_box = cur.split('.').next().unwrap_or("");
let scoped: Vec<String> = cands
.iter()
.filter(|k| k.starts_with(&format!("{}.", cur_box)))
.cloned()
.collect();
if scoped.len() == 1 {
cands = scoped;
}
}
}
if cands.len() == 1 {
pick = Some(cands.remove(0));
} else if cands.len() > 1 {
cands.sort();
pick = Some(cands[0].clone());
}
}
let fname = pick.ok_or_else(|| {
VMError::InvalidInstruction(format!(
"call unresolved: '{}' (arity={})",
raw,
args.len()
))
})?;
if std::env::var("NYASH_VM_CALL_TRACE").ok().as_deref() == Some("1") {
eprintln!("[vm] legacy-call resolved '{}' -> '{}'", raw, fname);
}
let callee =
self.functions.get(&fname).cloned().ok_or_else(|| {
VMError::InvalidInstruction(format!("function not found: {}", fname))
})?;
let mut argv: Vec<VMValue> = Vec::new();
for a in args {
argv.push(self.reg_load(*a)?);
}
self.exec_function_inner(&callee, Some(&argv))
}
fn execute_global_function(
&mut self,
func_name: &str,
args: &[ValueId],
) -> Result<VMValue, VMError> {
match func_name {
"nyash.builtin.print" | "print" | "nyash.console.log" => {
if let Some(arg_id) = args.get(0) {
let val = self.reg_load(*arg_id)?;
println!("{}", val.to_string());
}
Ok(VMValue::Void)
}
"nyash.builtin.error" => {
if let Some(arg_id) = args.get(0) {
let val = self.reg_load(*arg_id)?;
eprintln!("Error: {}", val.to_string());
}
Ok(VMValue::Void)
}
_ => Err(VMError::InvalidInstruction(format!(
"Unknown global function: {}",
func_name
))),
}
}
fn execute_method_call(
&mut self,
receiver: &VMValue,
method: &str,
args: &[ValueId],
) -> Result<VMValue, VMError> {
match receiver {
VMValue::String(s) => match method {
"length" => Ok(VMValue::Integer(s.len() as i64)),
"concat" => {
if let Some(arg_id) = args.get(0) {
let arg_val = self.reg_load(*arg_id)?;
let new_str = format!("{}{}", s, arg_val.to_string());
Ok(VMValue::String(new_str))
} else {
Err(VMError::InvalidInstruction(
"concat requires 1 argument".into(),
))
}
}
_ => Err(VMError::InvalidInstruction(format!(
"Unknown String method: {}",
method
))),
},
VMValue::BoxRef(box_ref) => {
if let Some(p) = box_ref
.as_any()
.downcast_ref::<crate::runtime::plugin_loader_v2::PluginBoxV2>()
{
let host = crate::runtime::plugin_loader_unified::get_global_plugin_host();
let host = host.read().unwrap();
let mut argv: Vec<Box<dyn crate::box_trait::NyashBox>> =
Vec::with_capacity(args.len());
for a in args {
argv.push(self.reg_load(*a)?.to_nyash_box());
}
match host.invoke_instance_method(
&p.box_type,
method,
p.inner.instance_id,
&argv,
) {
Ok(Some(ret)) => Ok(VMValue::from_nyash_box(ret)),
Ok(None) => Ok(VMValue::Void),
Err(e) => Err(VMError::InvalidInstruction(format!(
"Plugin method {}.{} failed: {:?}",
p.box_type, method, e
))),
}
} else {
Err(VMError::InvalidInstruction(format!(
"Method {} not supported on BoxRef({})",
method,
box_ref.type_name()
)))
}
}
_ => Err(VMError::InvalidInstruction(format!(
"Method {} not supported on {:?}",
method, receiver
))),
}
}
fn execute_extern_function(
&mut self,
extern_name: &str,
args: &[ValueId],
) -> Result<VMValue, VMError> {
match extern_name {
"exit" => {
let code = if let Some(arg_id) = args.get(0) {
self.reg_load(*arg_id)?.as_integer().unwrap_or(0)
} else {
0
};
std::process::exit(code as i32);
}
"panic" => {
let msg = if let Some(arg_id) = args.get(0) {
self.reg_load(*arg_id)?.to_string()
} else {
"VM panic".to_string()
};
panic!("{}", msg);
}
_ => Err(VMError::InvalidInstruction(format!(
"Unknown extern function: {}",
extern_name
))),
}
}
}

View File

@ -0,0 +1,100 @@
use super::*;
impl MirInterpreter {
pub(super) fn handle_extern_call(
&mut self,
dst: Option<ValueId>,
iface: &str,
method: &str,
args: &[ValueId],
) -> Result<(), VMError> {
match (iface, method) {
("env.console", "log") => {
if let Some(a0) = args.get(0) {
let v = self.reg_load(*a0)?;
println!("{}", v.to_string());
}
if let Some(d) = dst {
self.regs.insert(d, VMValue::Void);
}
Ok(())
}
("env.future", "new") => {
let fut = crate::boxes::future::NyashFutureBox::new();
if let Some(a0) = args.get(0) {
let v = self.reg_load(*a0)?;
fut.set_result(v.to_nyash_box());
}
if let Some(d) = dst {
self.regs.insert(d, VMValue::Future(fut));
}
Ok(())
}
("env.future", "set") => {
if args.len() >= 2 {
let f = self.reg_load(args[0])?;
let v = self.reg_load(args[1])?;
if let VMValue::Future(fut) = f {
fut.set_result(v.to_nyash_box());
} else {
return Err(VMError::TypeError("env.future.set expects Future".into()));
}
}
if let Some(d) = dst {
self.regs.insert(d, VMValue::Void);
}
Ok(())
}
("env.future", "await") => {
if let Some(a0) = args.get(0) {
let f = self.reg_load(*a0)?;
match f {
VMValue::Future(fut) => {
let v = fut.get();
if let Some(d) = dst {
self.regs.insert(d, VMValue::from_nyash_box(v));
}
}
_ => {
return Err(VMError::TypeError("await expects Future".into()));
}
}
}
Ok(())
}
("env.runtime", "checkpoint") => {
crate::runtime::global_hooks::safepoint_and_poll();
if let Some(d) = dst {
self.regs.insert(d, VMValue::Void);
}
Ok(())
}
("env.modules", "set") => {
if args.len() >= 2 {
let k = self.reg_load(args[0])?.to_string();
let v = self.reg_load(args[1])?.to_nyash_box();
crate::runtime::modules_registry::set(k, v);
}
if let Some(d) = dst {
self.regs.insert(d, VMValue::Void);
}
Ok(())
}
("env.modules", "get") => {
if let Some(a0) = args.get(0) {
let k = self.reg_load(*a0)?.to_string();
let vb = crate::runtime::modules_registry::get(&k)
.unwrap_or_else(|| Box::new(crate::box_trait::VoidBox::new()));
if let Some(d) = dst {
self.regs.insert(d, VMValue::from_nyash_box(vb));
}
}
Ok(())
}
_ => Err(VMError::InvalidInstruction(format!(
"ExternCall {}.{} not supported",
iface, method
))),
}
}
}

View File

@ -0,0 +1,45 @@
use super::*;
impl MirInterpreter {
pub(super) fn handle_ref_set(
&mut self,
reference: ValueId,
field: &str,
value: ValueId,
) -> Result<(), VMError> {
let v = self.reg_load(value)?;
self.obj_fields
.entry(reference)
.or_default()
.insert(field.into(), v);
Ok(())
}
pub(super) fn handle_ref_get(
&mut self,
dst: ValueId,
reference: ValueId,
field: &str,
) -> Result<(), VMError> {
let v = self
.obj_fields
.get(&reference)
.and_then(|m| m.get(field))
.cloned()
.unwrap_or(VMValue::Void);
self.regs.insert(dst, v);
Ok(())
}
pub(super) fn handle_load(&mut self, dst: ValueId, ptr: ValueId) -> Result<(), VMError> {
let v = self.mem.get(&ptr).cloned().unwrap_or(VMValue::Void);
self.regs.insert(dst, v);
Ok(())
}
pub(super) fn handle_store(&mut self, ptr: ValueId, value: ValueId) -> Result<(), VMError> {
let v = self.reg_load(value)?;
self.mem.insert(ptr, v);
Ok(())
}
}

View File

@ -0,0 +1,17 @@
use super::*;
impl MirInterpreter {
pub(super) fn handle_debug(&mut self, message: &str, value: ValueId) -> Result<(), VMError> {
let v = self.reg_load(value)?;
if std::env::var("NYASH_CLI_VERBOSE").ok().as_deref() == Some("1") {
eprintln!("[mir-debug] {} => {:?}", message, v);
}
Ok(())
}
pub(super) fn handle_print(&mut self, value: ValueId) -> Result<(), VMError> {
let v = self.reg_load(value)?;
println!("{}", v.to_string());
Ok(())
}
}

View File

@ -0,0 +1,87 @@
use super::*;
mod arithmetic;
mod boxes;
mod calls;
mod externals;
mod memory;
mod misc;
impl MirInterpreter {
pub(super) fn execute_instruction(&mut self, inst: &MirInstruction) -> Result<(), VMError> {
match inst {
MirInstruction::Const { dst, value } => self.handle_const(*dst, value)?,
MirInstruction::NewBox {
dst,
box_type,
args,
} => self.handle_new_box(*dst, box_type, args)?,
MirInstruction::PluginInvoke {
dst,
box_val,
method,
args,
..
} => self.handle_plugin_invoke(*dst, *box_val, method, args)?,
MirInstruction::BoxCall {
dst,
box_val,
method,
args,
..
} => self.handle_box_call(*dst, *box_val, method, args)?,
MirInstruction::ExternCall {
dst,
iface_name,
method_name,
args,
..
} => self.handle_extern_call(*dst, iface_name, method_name, args)?,
MirInstruction::RefSet {
reference,
field,
value,
} => self.handle_ref_set(*reference, field, *value)?,
MirInstruction::RefGet {
dst,
reference,
field,
} => self.handle_ref_get(*dst, *reference, field)?,
MirInstruction::BinOp { dst, op, lhs, rhs } => {
self.handle_binop(*dst, *op, *lhs, *rhs)?
}
MirInstruction::UnaryOp { dst, op, operand } => {
self.handle_unary_op(*dst, *op, *operand)?
}
MirInstruction::Compare { dst, op, lhs, rhs } => {
self.handle_compare(*dst, *op, *lhs, *rhs)?
}
MirInstruction::Copy { dst, src } => self.handle_copy(*dst, *src)?,
MirInstruction::Load { dst, ptr } => self.handle_load(*dst, *ptr)?,
MirInstruction::Store { ptr, value } => self.handle_store(*ptr, *value)?,
MirInstruction::Call {
dst,
func,
callee,
args,
..
} => self.handle_call(*dst, *func, callee.as_ref(), args)?,
MirInstruction::Debug { message, value } => {
self.handle_debug(message, *value)?;
}
MirInstruction::Print { value, .. } => self.handle_print(*value)?,
MirInstruction::BarrierRead { .. }
| MirInstruction::BarrierWrite { .. }
| MirInstruction::Barrier { .. }
| MirInstruction::Safepoint
| MirInstruction::Nop => {}
other => {
return Err(VMError::InvalidInstruction(format!(
"MIR interp: unimplemented instruction: {:?}",
other
)))
}
}
Ok(())
}
}

View File

@ -0,0 +1,76 @@
use super::*;
impl MirInterpreter {
pub(super) fn reg_load(&self, id: ValueId) -> Result<VMValue, VMError> {
self.regs
.get(&id)
.cloned()
.ok_or_else(|| VMError::InvalidValue(format!("use of undefined value {:?}", id)))
}
pub(super) fn eval_binop(
&self,
op: BinaryOp,
a: VMValue,
b: VMValue,
) -> Result<VMValue, VMError> {
use BinaryOp::*;
use VMValue::*;
Ok(match (op, a, b) {
(Add, Integer(x), Integer(y)) => Integer(x + y),
(Add, String(s), Integer(y)) => String(format!("{}{}", s, y)),
(Add, String(s), Float(y)) => String(format!("{}{}", s, y)),
(Add, String(s), Bool(y)) => String(format!("{}{}", s, y)),
(Add, String(s), String(t)) => String(format!("{}{}", s, t)),
(Add, Integer(x), String(t)) => String(format!("{}{}", x, t)),
(Add, Float(x), String(t)) => String(format!("{}{}", x, t)),
(Add, Bool(x), String(t)) => String(format!("{}{}", x, t)),
(Sub, Integer(x), Integer(y)) => Integer(x - y),
(Mul, Integer(x), Integer(y)) => Integer(x * y),
(Div, Integer(_), Integer(0)) => return Err(VMError::DivisionByZero),
(Div, Integer(x), Integer(y)) => Integer(x / y),
(Mod, Integer(_), Integer(0)) => return Err(VMError::DivisionByZero),
(Mod, Integer(x), Integer(y)) => Integer(x % y),
(Add, Float(x), Float(y)) => Float(x + y),
(Sub, Float(x), Float(y)) => Float(x - y),
(Mul, Float(x), Float(y)) => Float(x * y),
(Div, Float(_), Float(y)) if y == 0.0 => return Err(VMError::DivisionByZero),
(Div, Float(x), Float(y)) => Float(x / y),
(Mod, Float(x), Float(y)) => Float(x % y),
(BitAnd, Integer(x), Integer(y)) => Integer(x & y),
(BitOr, Integer(x), Integer(y)) => Integer(x | y),
(BitXor, Integer(x), Integer(y)) => Integer(x ^ y),
(Shl, Integer(x), Integer(y)) => Integer(x.wrapping_shl(y as u32)),
(Shr, Integer(x), Integer(y)) => Integer(x.wrapping_shr(y as u32)),
(opk, va, vb) => {
return Err(VMError::TypeError(format!(
"unsupported binop {:?} on {:?} and {:?}",
opk, va, vb
)))
}
})
}
pub(super) fn eval_cmp(&self, op: CompareOp, a: VMValue, b: VMValue) -> Result<bool, VMError> {
use CompareOp::*;
use VMValue::*;
Ok(match (op, &a, &b) {
(Eq, _, _) => eq_vm(&a, &b),
(Ne, _, _) => !eq_vm(&a, &b),
(Lt, Integer(x), Integer(y)) => x < y,
(Le, Integer(x), Integer(y)) => x <= y,
(Gt, Integer(x), Integer(y)) => x > y,
(Ge, Integer(x), Integer(y)) => x >= y,
(Lt, Float(x), Float(y)) => x < y,
(Le, Float(x), Float(y)) => x <= y,
(Gt, Float(x), Float(y)) => x > y,
(Ge, Float(x), Float(y)) => x >= y,
(opk, va, vb) => {
return Err(VMError::TypeError(format!(
"unsupported compare {:?} on {:?} and {:?}",
opk, va, vb
)))
}
})
}
}

View File

@ -0,0 +1,58 @@
/*!
* Minimal MIR Interpreter
*
* Executes a subset of MIR instructions for fast iteration without LLVM/JIT.
* Supported: Const, BinOp(Add/Sub/Mul/Div/Mod), Compare, Load/Store, Branch, Jump, Return,
* Print/Debug (best-effort), Barrier/Safepoint (no-op).
*/
use std::collections::HashMap;
use crate::box_trait::NyashBox;
pub(super) use crate::backend::abi_util::{eq_vm, to_bool_vm};
pub(super) use crate::backend::vm::{VMError, VMValue};
pub(super) use crate::mir::{
BasicBlockId, BinaryOp, Callee, CompareOp, ConstValue, MirFunction, MirInstruction, MirModule,
ValueId,
};
mod exec;
mod handlers;
mod helpers;
pub struct MirInterpreter {
pub(super) regs: HashMap<ValueId, VMValue>,
pub(super) mem: HashMap<ValueId, VMValue>,
pub(super) obj_fields: HashMap<ValueId, HashMap<String, VMValue>>,
pub(super) functions: HashMap<String, MirFunction>,
pub(super) cur_fn: Option<String>,
}
impl MirInterpreter {
pub fn new() -> Self {
Self {
regs: HashMap::new(),
mem: HashMap::new(),
obj_fields: HashMap::new(),
functions: HashMap::new(),
cur_fn: None,
}
}
/// Execute module entry (main) and return boxed result
pub fn execute_module(&mut self, module: &MirModule) -> Result<Box<dyn NyashBox>, VMError> {
// Snapshot functions for call resolution
self.functions = module.functions.clone();
let func = module
.functions
.get("main")
.ok_or_else(|| VMError::InvalidInstruction("missing main".into()))?;
let ret = self.execute_function(func)?;
Ok(ret.to_nyash_box())
}
fn execute_function(&mut self, func: &MirFunction) -> Result<VMValue, VMError> {
self.exec_function_inner(func, None)
}
}