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:
82
src/backend/mir_interpreter/handlers/arithmetic.rs
Normal file
82
src/backend/mir_interpreter/handlers/arithmetic.rs
Normal 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(())
|
||||
}
|
||||
}
|
||||
265
src/backend/mir_interpreter/handlers/boxes.rs
Normal file
265
src/backend/mir_interpreter/handlers/boxes.rs
Normal 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
|
||||
)))
|
||||
}
|
||||
}
|
||||
}
|
||||
252
src/backend/mir_interpreter/handlers/calls.rs
Normal file
252
src/backend/mir_interpreter/handlers/calls.rs
Normal 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
|
||||
))),
|
||||
}
|
||||
}
|
||||
}
|
||||
100
src/backend/mir_interpreter/handlers/externals.rs
Normal file
100
src/backend/mir_interpreter/handlers/externals.rs
Normal 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
|
||||
))),
|
||||
}
|
||||
}
|
||||
}
|
||||
45
src/backend/mir_interpreter/handlers/memory.rs
Normal file
45
src/backend/mir_interpreter/handlers/memory.rs
Normal 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(())
|
||||
}
|
||||
}
|
||||
17
src/backend/mir_interpreter/handlers/misc.rs
Normal file
17
src/backend/mir_interpreter/handlers/misc.rs
Normal 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(())
|
||||
}
|
||||
}
|
||||
87
src/backend/mir_interpreter/handlers/mod.rs
Normal file
87
src/backend/mir_interpreter/handlers/mod.rs
Normal 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(())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user