builder+vm: unify method calls via emit_unified_call; add RouterPolicy trace; finalize LocalSSA/BlockSchedule guards; docs + selfhost quickstart
- Unify standard method calls to emit_unified_call; route via RouterPolicy and apply rewrite::{special,known} at a single entry.\n- Stabilize emit-time invariants: LocalSSA finalize + BlockSchedule PHI→Copy→Call ordering; metadata propagation on copies.\n- Known rewrite default ON (userbox only, strict guards) with opt-out flag NYASH_REWRITE_KNOWN_DEFAULT=0.\n- Expand TypeAnnotation whitelist (is_digit_char/is_hex_digit_char/is_alpha_char/Map.has).\n- Docs: unified-method-resolution design note; Quick Reference normalization note; selfhosting/quickstart.\n- Tools: add tools/selfhost_smoke.sh (dev-only).\n- Keep behavior unchanged for Unknown/core/user-instance via BoxCall fallback; all tests green (quick/integration).
This commit is contained in:
@ -79,6 +79,33 @@ pub(super) fn try_handle_string_box(
|
||||
if let Some(d) = dst { this.regs.insert(d, VMValue::from_nyash_box(Box::new(crate::box_trait::StringBox::new(new_s)))) ; }
|
||||
return Ok(true);
|
||||
}
|
||||
"is_digit_char" => {
|
||||
// Accept either 0-arg (use first char of receiver) or 1-arg (string/char to test)
|
||||
let ch_opt = if args.is_empty() {
|
||||
sb.value.chars().next()
|
||||
} else if args.len() == 1 {
|
||||
let s = this.reg_load(args[0])?.to_string();
|
||||
s.chars().next()
|
||||
} else {
|
||||
return Err(VMError::InvalidInstruction("is_digit_char expects 0 or 1 arg".into()));
|
||||
};
|
||||
let is_digit = ch_opt.map(|c| c.is_ascii_digit()).unwrap_or(false);
|
||||
if let Some(d) = dst { this.regs.insert(d, VMValue::Bool(is_digit)); }
|
||||
return Ok(true);
|
||||
}
|
||||
"is_hex_digit_char" => {
|
||||
let ch_opt = if args.is_empty() {
|
||||
sb.value.chars().next()
|
||||
} else if args.len() == 1 {
|
||||
let s = this.reg_load(args[0])?.to_string();
|
||||
s.chars().next()
|
||||
} else {
|
||||
return Err(VMError::InvalidInstruction("is_hex_digit_char expects 0 or 1 arg".into()));
|
||||
};
|
||||
let is_hex = ch_opt.map(|c| c.is_ascii_hexdigit()).unwrap_or(false);
|
||||
if let Some(d) = dst { this.regs.insert(d, VMValue::Bool(is_hex)); }
|
||||
return Ok(true);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
@ -28,7 +28,24 @@ impl MirInterpreter {
|
||||
Callee::Global(func_name) => self.execute_global_function(func_name, args),
|
||||
Callee::Method { box_name: _, method, receiver, certainty: _, } => {
|
||||
if let Some(recv_id) = receiver {
|
||||
let recv_val = self.reg_load(*recv_id)?;
|
||||
// Primary: load receiver by id. Dev fallback: if undefined and env allows,
|
||||
// use args[0] as a surrogate receiver (builder localization gap workaround).
|
||||
let recv_val = match self.reg_load(*recv_id) {
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
let tolerate = std::env::var("NYASH_VM_RECV_ARG_FALLBACK").ok().as_deref() == Some("1")
|
||||
|| std::env::var("NYASH_VM_TOLERATE_VOID").ok().as_deref() == Some("1");
|
||||
if tolerate {
|
||||
if let Some(a0) = args.get(0) {
|
||||
self.reg_load(*a0)?
|
||||
} else {
|
||||
return Err(e);
|
||||
}
|
||||
} else {
|
||||
return Err(e);
|
||||
}
|
||||
}
|
||||
};
|
||||
let dev_trace = std::env::var("NYASH_VM_TRACE").ok().as_deref() == Some("1");
|
||||
// Fast bridge for builtin boxes (Array) and common methods.
|
||||
// Preserve legacy semantics when plugins are absent.
|
||||
|
||||
@ -36,6 +36,11 @@ impl MirInterpreter {
|
||||
keys.join(", ")
|
||||
);
|
||||
}
|
||||
// Dev-time safety valve: tolerate undefined registers as Void when enabled
|
||||
let tolerate = std::env::var("NYASH_VM_TOLERATE_VOID").ok().as_deref() == Some("1");
|
||||
if tolerate {
|
||||
return Ok(VMValue::Void);
|
||||
}
|
||||
Err(VMError::InvalidValue(format!(
|
||||
"use of undefined value {:?}",
|
||||
id
|
||||
@ -64,8 +69,7 @@ impl MirInterpreter {
|
||||
use BinaryOp::*;
|
||||
use VMValue::*;
|
||||
// Dev-time: normalize BoxRef(VoidBox) → VMValue::Void when tolerance is enabled or in --dev mode.
|
||||
let tolerate = std::env::var("NYASH_VM_TOLERATE_VOID").ok().as_deref() == Some("1")
|
||||
|| std::env::var("NYASH_DEV").ok().as_deref() == Some("1");
|
||||
let tolerate = std::env::var("NYASH_VM_TOLERATE_VOID").ok().as_deref() == Some("1");
|
||||
let (a, b) = if tolerate {
|
||||
let norm = |v: VMValue| -> VMValue {
|
||||
if let VMValue::BoxRef(bx) = &v {
|
||||
@ -131,8 +135,7 @@ impl MirInterpreter {
|
||||
use CompareOp::*;
|
||||
use VMValue::*;
|
||||
// Dev-time: normalize BoxRef(VoidBox) → VMValue::Void when tolerance is enabled or in --dev.
|
||||
let tolerate = std::env::var("NYASH_VM_TOLERATE_VOID").ok().as_deref() == Some("1")
|
||||
|| std::env::var("NYASH_DEV").ok().as_deref() == Some("1");
|
||||
let tolerate = std::env::var("NYASH_VM_TOLERATE_VOID").ok().as_deref() == Some("1");
|
||||
let (a, b) = if tolerate {
|
||||
let norm = |v: VMValue| -> VMValue {
|
||||
if let VMValue::BoxRef(bx) = &v {
|
||||
|
||||
Reference in New Issue
Block a user