fix(bridge): implement env.box_introspect.kind lowering + Stage0 build fixes
Phase 25.1b type system groundwork - env.* namespace support in Bridge layer
Changes:
- Bridge layer (JSON v0 → MIR):
- Add 'env' as well-known variable in MapVars::resolve()
- Implement env.box_introspect.kind(value) → ExternCall lowering
- Pattern: Method { recv: Method { recv: Var("env"), method: "box_introspect" }, method: "kind" }
- VM/extern fixes:
- Add Arc::from() conversion for env.box_introspect.kind result
- Fix MapBox API usage in extern_functions.rs logging
- Build fixes:
- Comment out missing llvm_legacy/llvm modules in src/backend/mod.rs
- Comment out missing gui_visual_node_prototype in Cargo.toml
- New files:
- lang/src/shared/common/box_type_inspector_box.hako (type introspection API)
Context:
- Enables BoxTypeInspectorBox to query runtime Box types via env.box_introspect.kind
- Required for selfhost MirBuilder type-aware lowering (multi-carrier loops, etc.)
- Part of Phase 25.1b "no fallback" selfhosting strategy
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@ -124,10 +124,10 @@ name = "gui_test_icon_extraction"
|
||||
path = "examples/test_icon_extraction.rs"
|
||||
required-features = ["gui-examples"]
|
||||
|
||||
[[example]]
|
||||
name = "gui_visual_node_prototype"
|
||||
path = "development/egui_research/experiments/visual_node_prototype.rs"
|
||||
required-features = ["gui-examples"]
|
||||
# [[example]]
|
||||
# name = "gui_visual_node_prototype"
|
||||
# path = "development/egui_research/experiments/visual_node_prototype.rs"
|
||||
# required-features = ["gui-examples"]
|
||||
|
||||
|
||||
|
||||
|
||||
59
lang/src/shared/common/box_type_inspector_box.hako
Normal file
59
lang/src/shared/common/box_type_inspector_box.hako
Normal file
@ -0,0 +1,59 @@
|
||||
// box_type_inspector_box.hako — Runtime box type metadata helper
|
||||
// Responsibility:
|
||||
// - Wrap env.box_introspect.* extern calls for Stage1 code.
|
||||
// - Provide describe/kind/is_map/is_array helpers without depending on `"" + MapBox`.
|
||||
|
||||
static box BoxTypeInspectorBox {
|
||||
method _describe(value) {
|
||||
local args = new ArrayBox()
|
||||
args.push(value)
|
||||
local info = hostbridge.extern_invoke("env.box_introspect", "kind", args)
|
||||
if env.get("HAKO_BOX_INTROSPECT_TRACE") == "1" {
|
||||
if info != null {
|
||||
print("[box_introspect:hako] kind=" + ("" + info.get("kind")) +
|
||||
" is_map=" + ("" + info.get("is_map")) +
|
||||
" is_array=" + ("" + info.get("is_array")))
|
||||
} else {
|
||||
print("[box_introspect:hako] info=null")
|
||||
}
|
||||
}
|
||||
return info
|
||||
}
|
||||
|
||||
method kind(value) {
|
||||
local info = me._describe(value)
|
||||
if info == null { return "Unknown" }
|
||||
local k = info.get("kind")
|
||||
if k == null { return "Unknown" }
|
||||
return "" + k
|
||||
}
|
||||
|
||||
method is_map(value) {
|
||||
local info = me._describe(value)
|
||||
if info != null {
|
||||
local flag = info.get("is_map")
|
||||
if flag != null { return flag }
|
||||
}
|
||||
// Fallback: detect MapBox from repr when extern is unavailable
|
||||
local repr = "" + value
|
||||
if repr.indexOf("MapBox(") == 0 { return true }
|
||||
return false
|
||||
}
|
||||
|
||||
method is_array(value) {
|
||||
local info = me._describe(value)
|
||||
if info != null {
|
||||
local flag = info.get("is_array")
|
||||
if flag != null { return flag }
|
||||
}
|
||||
// Fallback: detect ArrayBox from repr when extern is unavailable
|
||||
local repr = "" + value
|
||||
if repr.indexOf("ArrayBox(") == 0 { return true }
|
||||
return false
|
||||
}
|
||||
|
||||
method describe(value) {
|
||||
// Expose full Map so callers can inspect additional fields (type_name/type_id/etc.)
|
||||
return me._describe(value)
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,7 @@
|
||||
use super::*;
|
||||
use crate::backend::mir_interpreter::utils::error_helpers::ErrorBuilder;
|
||||
use serde_json::Value as JsonValue;
|
||||
use std::sync::Arc;
|
||||
|
||||
impl MirInterpreter {
|
||||
#[inline]
|
||||
@ -212,7 +213,44 @@ impl MirInterpreter {
|
||||
let val = std::env::var(&key).ok();
|
||||
Some(Ok(match val { Some(s) => VMValue::String(s), None => VMValue::Void }))
|
||||
}
|
||||
// Legacy global-call form: hostbridge.extern_invoke(name, method, args?)
|
||||
// Direct env.box_introspect.kind extern (ExternCall form)
|
||||
"env.box_introspect.kind" => {
|
||||
use crate::box_trait::{NyashBox, StringBox};
|
||||
use crate::runtime::plugin_loader_v2;
|
||||
|
||||
let mut collected: Vec<Box<dyn NyashBox>> = Vec::new();
|
||||
if let Some(arg_reg) = args.get(0) {
|
||||
let v = match self.reg_load(*arg_reg) {
|
||||
Ok(v) => v,
|
||||
Err(e) => return Some(Err(e)),
|
||||
};
|
||||
match v {
|
||||
VMValue::BoxRef(b) => collected.push(b.clone_box()),
|
||||
other => {
|
||||
collected.push(Box::new(StringBox::new(&other.to_string())));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return Some(Err(self.err_invalid(
|
||||
"env.box_introspect.kind expects 1 arg",
|
||||
)));
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "plugins", not(target_arch = "wasm32")))]
|
||||
let result = plugin_loader_v2::handle_box_introspect("kind", &collected);
|
||||
#[cfg(any(not(feature = "plugins"), target_arch = "wasm32"))]
|
||||
let result: crate::bid::BidResult<Option<Box<dyn crate::box_trait::NyashBox>>> =
|
||||
Err(crate::bid::BidError::PluginError);
|
||||
|
||||
match result {
|
||||
Ok(Some(b)) => Some(Ok(VMValue::BoxRef(Arc::from(b)))),
|
||||
Ok(None) => Some(Ok(VMValue::Void)),
|
||||
Err(e) => Some(Err(self.err_with_context(
|
||||
"env.box_introspect.kind",
|
||||
&format!("{:?}", e),
|
||||
))),
|
||||
}
|
||||
}
|
||||
"hostbridge.extern_invoke" => {
|
||||
if std::env::var("HAKO_CABI_TRACE").ok().as_deref() == Some("1") {
|
||||
eprintln!("[hb:entry:provider] hostbridge.extern_invoke");
|
||||
@ -386,12 +424,93 @@ impl MirInterpreter {
|
||||
Err(e) => Err(ErrorBuilder::with_context("env.codegen.link_object", &e.to_string()))
|
||||
}
|
||||
}
|
||||
("env.box_introspect", "kind") => {
|
||||
// hostbridge.extern_invoke("env.box_introspect","kind",[value])
|
||||
// args layout (regs): [name, method, array_box_or_value, ...]
|
||||
// For BoxTypeInspectorBox we only care about the first element of the ArrayBox.
|
||||
use crate::box_trait::{NyashBox, StringBox};
|
||||
use crate::runtime::plugin_loader_v2;
|
||||
|
||||
let mut collected: Vec<Box<dyn NyashBox>> = Vec::new();
|
||||
if let Some(arg_reg) = args.get(2) {
|
||||
let v = match self.reg_load(*arg_reg) {
|
||||
Ok(v) => v,
|
||||
Err(e) => return Some(Err(e)),
|
||||
};
|
||||
match v {
|
||||
VMValue::BoxRef(b) => {
|
||||
if let Some(ab) =
|
||||
b.as_any().downcast_ref::<crate::boxes::array::ArrayBox>()
|
||||
{
|
||||
let idx0: Box<dyn NyashBox> =
|
||||
Box::new(crate::box_trait::IntegerBox::new(0));
|
||||
let elem0 = ab.get(idx0);
|
||||
if std::env::var("NYASH_BOX_INTROSPECT_TRACE")
|
||||
.ok()
|
||||
.as_deref()
|
||||
== Some("1")
|
||||
{
|
||||
eprintln!(
|
||||
"[box_introspect:extern] using ArrayBox[0] value_type={}",
|
||||
elem0.type_name()
|
||||
);
|
||||
}
|
||||
collected.push(elem0);
|
||||
} else {
|
||||
if std::env::var("NYASH_BOX_INTROSPECT_TRACE")
|
||||
.ok()
|
||||
.as_deref()
|
||||
== Some("1")
|
||||
{
|
||||
eprintln!(
|
||||
"[box_introspect:extern] using BoxRef({}) directly",
|
||||
b.type_name()
|
||||
);
|
||||
}
|
||||
collected.push(b.clone_box());
|
||||
}
|
||||
}
|
||||
other => {
|
||||
if std::env::var("NYASH_BOX_INTROSPECT_TRACE")
|
||||
.ok()
|
||||
.as_deref()
|
||||
== Some("1")
|
||||
{
|
||||
eprintln!(
|
||||
"[box_introspect:extern] non-box arg kind={:?}",
|
||||
other
|
||||
);
|
||||
}
|
||||
collected.push(Box::new(StringBox::new(&other.to_string())));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return Some(Err(self.err_invalid(
|
||||
"extern_invoke env.box_introspect.kind expects args array",
|
||||
)));
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "plugins", not(target_arch = "wasm32")))]
|
||||
let result = plugin_loader_v2::handle_box_introspect("kind", &collected);
|
||||
#[cfg(any(not(feature = "plugins"), target_arch = "wasm32"))]
|
||||
let result: crate::bid::BidResult<Option<Box<dyn NyashBox>>> =
|
||||
Err(crate::bid::BidError::PluginError);
|
||||
|
||||
match result {
|
||||
Ok(Some(b)) => Ok(VMValue::BoxRef(Arc::from(b))),
|
||||
Ok(None) => Ok(VMValue::Void),
|
||||
Err(e) => Err(self.err_with_context(
|
||||
"env.box_introspect.kind",
|
||||
&format!("{:?}", e),
|
||||
)),
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
if std::env::var("HAKO_CABI_TRACE").ok().as_deref() == Some("1") {
|
||||
eprintln!("[hb:unsupported:provider] {}.{}", name, method);
|
||||
}
|
||||
Err(self.err_invalid(format!(
|
||||
"hostbridge.extern_invoke unsupported for {}.{} [provider]",
|
||||
"hostbridge.extern_invoke unsupported for {}.{} [provider] (check extern_provider_dispatch / env.* handlers)",
|
||||
name, method
|
||||
)))
|
||||
},
|
||||
|
||||
@ -23,10 +23,10 @@ pub mod wasm;
|
||||
#[cfg(feature = "wasm-backend")]
|
||||
pub mod wasm_v2;
|
||||
|
||||
#[cfg(feature = "llvm-inkwell-legacy")]
|
||||
pub mod llvm_legacy;
|
||||
#[cfg(feature = "llvm-inkwell-legacy")]
|
||||
pub mod llvm;
|
||||
// #[cfg(feature = "llvm-inkwell-legacy")]
|
||||
// pub mod llvm_legacy;
|
||||
// #[cfg(feature = "llvm-inkwell-legacy")]
|
||||
// pub mod llvm;
|
||||
|
||||
// Public aliases to make the role of the VM clear in runner/tests
|
||||
pub use mir_interpreter::MirInterpreter;
|
||||
|
||||
@ -80,6 +80,19 @@ impl<'a> VarScope for MapVars<'a> {
|
||||
self.vars.insert(name.to_string(), dst);
|
||||
return Ok(Some(dst));
|
||||
}
|
||||
// Phase 25.1b: Treat `env` as a well-known global for env.box_introspect.* etc.
|
||||
// Similar to hostbridge, we need a placeholder value for the nested method pattern.
|
||||
if name == "env" {
|
||||
let dst = f.next_value_id();
|
||||
if let Some(bb) = f.get_block_mut(cur_bb) {
|
||||
bb.add_instruction(MirInstruction::Const {
|
||||
dst,
|
||||
value: ConstValue::String("env".into()),
|
||||
});
|
||||
}
|
||||
self.vars.insert(name.to_string(), dst);
|
||||
return Ok(Some(dst));
|
||||
}
|
||||
if name == "me" {
|
||||
if env.allow_me_dummy {
|
||||
let dst = f.next_value_id();
|
||||
@ -363,6 +376,29 @@ pub(super) fn lower_expr_with_scope<S: VarScope>(
|
||||
}
|
||||
return Ok((dst, cur2));
|
||||
}
|
||||
// Phase 25.1b: Handle env.box_introspect.kind(value) pattern
|
||||
// Pattern: Method { recv: Method { recv: Var("env"), method: "box_introspect" }, method: "kind", args }
|
||||
if let ExprV0::Method { recv: inner_recv, method: inner_method, args: inner_args } = &**recv {
|
||||
if matches!(&**inner_recv, ExprV0::Var { name } if name == "env")
|
||||
&& inner_method == "box_introspect"
|
||||
&& inner_args.is_empty() {
|
||||
|
||||
// Lower args for the final method call
|
||||
let (arg_ids, cur2) = lower_args_with_scope(env, f, cur_bb, args, vars)?;
|
||||
let dst = f.next_value_id();
|
||||
|
||||
if let Some(bb) = f.get_block_mut(cur2) {
|
||||
bb.add_instruction(MirInstruction::ExternCall {
|
||||
dst: Some(dst),
|
||||
iface_name: "env.box_introspect".into(),
|
||||
method_name: method.clone(),
|
||||
args: arg_ids,
|
||||
effects: EffectMask::READ,
|
||||
});
|
||||
}
|
||||
return Ok((dst, cur2));
|
||||
}
|
||||
}
|
||||
let (recv_v, cur) = lower_expr_with_scope(env, f, cur_bb, recv, vars)?;
|
||||
let (arg_ids, cur2) = lower_args_with_scope(env, f, cur, args, vars)?;
|
||||
let dst = f.next_value_id();
|
||||
|
||||
@ -4,12 +4,18 @@
|
||||
//! that were previously in a large switch statement in loader.rs
|
||||
|
||||
use crate::bid::{BidError, BidResult};
|
||||
use crate::box_trait::{NyashBox, StringBox, VoidBox};
|
||||
use crate::boxes::result::NyashResultBox;
|
||||
use crate::box_trait::IntegerBox;
|
||||
use crate::box_trait::{BoolBox, NyashBox, StringBox, VoidBox};
|
||||
use crate::boxes::array::ArrayBox;
|
||||
use crate::boxes::future::FutureBox;
|
||||
use crate::boxes::map_box::MapBox;
|
||||
use crate::boxes::null_box::NullBox;
|
||||
use crate::boxes::result::NyashResultBox;
|
||||
use crate::boxes::token_box::TokenBox;
|
||||
use crate::runtime::modules_registry;
|
||||
use crate::runtime::global_hooks;
|
||||
use crate::runtime::modules_registry;
|
||||
use std::collections::hash_map::DefaultHasher;
|
||||
use std::hash::{Hash, Hasher};
|
||||
|
||||
/// Handle external function calls from the runtime
|
||||
pub fn extern_call(
|
||||
@ -32,6 +38,7 @@ pub fn extern_call(
|
||||
"env.future" => handle_future(method_name, args),
|
||||
"env.mirbuilder" => handle_mirbuilder(method_name, args),
|
||||
"env.codegen" => handle_codegen(method_name, args),
|
||||
"env.box_introspect" => handle_box_introspect(method_name, args),
|
||||
_ => Err(BidError::PluginError),
|
||||
}
|
||||
}
|
||||
@ -41,8 +48,12 @@ fn should_trace_call_extern(target: &str, method: &str) -> bool {
|
||||
let key = format!("{}.{}", target, method);
|
||||
for pat in flt.split(',') {
|
||||
let p = pat.trim();
|
||||
if p.is_empty() { continue; }
|
||||
if p == method || p == key { return true; }
|
||||
if p.is_empty() {
|
||||
continue;
|
||||
}
|
||||
if p == method || p == key {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -50,7 +61,10 @@ fn should_trace_call_extern(target: &str, method: &str) -> bool {
|
||||
}
|
||||
|
||||
/// Handle env.console.* methods
|
||||
fn handle_console(method_name: &str, args: &[Box<dyn NyashBox>]) -> BidResult<Option<Box<dyn NyashBox>>> {
|
||||
fn handle_console(
|
||||
method_name: &str,
|
||||
args: &[Box<dyn NyashBox>],
|
||||
) -> BidResult<Option<Box<dyn NyashBox>>> {
|
||||
match method_name {
|
||||
"log" => {
|
||||
let trace = std::env::var("NYASH_CONSOLE_TRACE").ok().as_deref() == Some("1");
|
||||
@ -68,7 +82,10 @@ fn handle_console(method_name: &str, args: &[Box<dyn NyashBox>]) -> BidResult<Op
|
||||
}
|
||||
|
||||
/// Handle env.result.* methods
|
||||
fn handle_result(method_name: &str, args: &[Box<dyn NyashBox>]) -> BidResult<Option<Box<dyn NyashBox>>> {
|
||||
fn handle_result(
|
||||
method_name: &str,
|
||||
args: &[Box<dyn NyashBox>],
|
||||
) -> BidResult<Option<Box<dyn NyashBox>>> {
|
||||
match method_name {
|
||||
"ok" => {
|
||||
// Wrap the first argument as Result.Ok; if missing, use Void
|
||||
@ -91,7 +108,10 @@ fn handle_result(method_name: &str, args: &[Box<dyn NyashBox>]) -> BidResult<Opt
|
||||
}
|
||||
|
||||
/// Handle env.modules.* methods
|
||||
fn handle_modules(method_name: &str, args: &[Box<dyn NyashBox>]) -> BidResult<Option<Box<dyn NyashBox>>> {
|
||||
fn handle_modules(
|
||||
method_name: &str,
|
||||
args: &[Box<dyn NyashBox>],
|
||||
) -> BidResult<Option<Box<dyn NyashBox>>> {
|
||||
match method_name {
|
||||
"set" => {
|
||||
if args.len() >= 2 {
|
||||
@ -115,7 +135,10 @@ fn handle_modules(method_name: &str, args: &[Box<dyn NyashBox>]) -> BidResult<Op
|
||||
}
|
||||
|
||||
/// Handle env.task.* methods
|
||||
fn handle_task(method_name: &str, args: &[Box<dyn NyashBox>]) -> BidResult<Option<Box<dyn NyashBox>>> {
|
||||
fn handle_task(
|
||||
method_name: &str,
|
||||
args: &[Box<dyn NyashBox>],
|
||||
) -> BidResult<Option<Box<dyn NyashBox>>> {
|
||||
match method_name {
|
||||
"cancelCurrent" => {
|
||||
let tok = global_hooks::current_group_token();
|
||||
@ -153,7 +176,10 @@ fn handle_task_wait(_args: &[Box<dyn NyashBox>]) -> BidResult<Option<Box<dyn Nya
|
||||
}
|
||||
|
||||
/// Handle env.debug.* methods
|
||||
fn handle_debug(method_name: &str, args: &[Box<dyn NyashBox>]) -> BidResult<Option<Box<dyn NyashBox>>> {
|
||||
fn handle_debug(
|
||||
method_name: &str,
|
||||
args: &[Box<dyn NyashBox>],
|
||||
) -> BidResult<Option<Box<dyn NyashBox>>> {
|
||||
match method_name {
|
||||
"trace" => {
|
||||
if std::env::var("NYASH_DEBUG_TRACE").ok().as_deref() == Some("1") {
|
||||
@ -168,7 +194,10 @@ fn handle_debug(method_name: &str, args: &[Box<dyn NyashBox>]) -> BidResult<Opti
|
||||
}
|
||||
|
||||
/// Handle env.runtime.* methods
|
||||
fn handle_runtime(method_name: &str, _args: &[Box<dyn NyashBox>]) -> BidResult<Option<Box<dyn NyashBox>>> {
|
||||
fn handle_runtime(
|
||||
method_name: &str,
|
||||
_args: &[Box<dyn NyashBox>],
|
||||
) -> BidResult<Option<Box<dyn NyashBox>>> {
|
||||
match method_name {
|
||||
"checkpoint" => {
|
||||
if crate::config::env::runtime_checkpoint_trace() {
|
||||
@ -182,7 +211,10 @@ fn handle_runtime(method_name: &str, _args: &[Box<dyn NyashBox>]) -> BidResult<O
|
||||
}
|
||||
|
||||
/// Handle env.future.* methods
|
||||
fn handle_future(method_name: &str, args: &[Box<dyn NyashBox>]) -> BidResult<Option<Box<dyn NyashBox>>> {
|
||||
fn handle_future(
|
||||
method_name: &str,
|
||||
args: &[Box<dyn NyashBox>],
|
||||
) -> BidResult<Option<Box<dyn NyashBox>>> {
|
||||
match method_name {
|
||||
"new" | "birth" => {
|
||||
let fut = FutureBox::new();
|
||||
@ -193,10 +225,7 @@ fn handle_future(method_name: &str, args: &[Box<dyn NyashBox>]) -> BidResult<Opt
|
||||
}
|
||||
"set" => {
|
||||
if args.len() >= 2 {
|
||||
if let Some(fut) = args[0]
|
||||
.as_any()
|
||||
.downcast_ref::<FutureBox>()
|
||||
{
|
||||
if let Some(fut) = args[0].as_any().downcast_ref::<FutureBox>() {
|
||||
fut.set_result(args[1].clone_box());
|
||||
}
|
||||
}
|
||||
@ -207,11 +236,110 @@ fn handle_future(method_name: &str, args: &[Box<dyn NyashBox>]) -> BidResult<Opt
|
||||
}
|
||||
}
|
||||
|
||||
/// Handle env.box_introspect.* methods
|
||||
pub fn handle_box_introspect(
|
||||
method_name: &str,
|
||||
args: &[Box<dyn NyashBox>],
|
||||
) -> BidResult<Option<Box<dyn NyashBox>>> {
|
||||
match method_name {
|
||||
"kind" => {
|
||||
let value = args.get(0).ok_or(BidError::PluginError)?;
|
||||
let info = build_box_info(value.as_ref());
|
||||
if std::env::var("NYASH_BOX_INTROSPECT_TRACE")
|
||||
.ok()
|
||||
.as_deref() == Some("1")
|
||||
{
|
||||
eprintln!(
|
||||
"[box_introspect:plugin] kind={} type_name={} is_map={} is_array={}",
|
||||
info.get(Box::new(StringBox::new("kind"))).to_string_box().value,
|
||||
info.get(Box::new(StringBox::new("type_name"))).to_string_box().value,
|
||||
info.get(Box::new(StringBox::new("is_map"))).to_string_box().value,
|
||||
info.get(Box::new(StringBox::new("is_array"))).to_string_box().value,
|
||||
);
|
||||
}
|
||||
Ok(Some(Box::new(info)))
|
||||
}
|
||||
_ => Err(BidError::PluginError),
|
||||
}
|
||||
}
|
||||
|
||||
fn build_box_info(value: &dyn NyashBox) -> MapBox {
|
||||
let info = MapBox::new();
|
||||
insert_string(&info, "kind", &classify_kind(value));
|
||||
insert_string(&info, "type_name", value.type_name());
|
||||
insert_string(&info, "type_id", &format!("{:016x}", type_id_hash(value)));
|
||||
insert_bool(
|
||||
&info,
|
||||
"is_map",
|
||||
value.as_any().downcast_ref::<MapBox>().is_some(),
|
||||
);
|
||||
insert_bool(
|
||||
&info,
|
||||
"is_array",
|
||||
value.as_any().downcast_ref::<ArrayBox>().is_some(),
|
||||
);
|
||||
insert_bool(
|
||||
&info,
|
||||
"is_null",
|
||||
value.as_any().downcast_ref::<NullBox>().is_some(),
|
||||
);
|
||||
info
|
||||
}
|
||||
|
||||
fn insert_string(target: &MapBox, key: &str, value: &str) {
|
||||
let _ = target.set(
|
||||
Box::new(StringBox::new(key)),
|
||||
Box::new(StringBox::new(value)),
|
||||
);
|
||||
}
|
||||
|
||||
fn insert_bool(target: &MapBox, key: &str, value: bool) {
|
||||
let _ = target.set(Box::new(StringBox::new(key)), Box::new(BoolBox::new(value)));
|
||||
}
|
||||
|
||||
fn classify_kind(value: &dyn NyashBox) -> String {
|
||||
if value.as_any().downcast_ref::<MapBox>().is_some() {
|
||||
return "MapBox".to_string();
|
||||
}
|
||||
if value.as_any().downcast_ref::<ArrayBox>().is_some() {
|
||||
return "ArrayBox".to_string();
|
||||
}
|
||||
if value.as_any().downcast_ref::<StringBox>().is_some() {
|
||||
return "StringBox".to_string();
|
||||
}
|
||||
if value.as_any().downcast_ref::<IntegerBox>().is_some() {
|
||||
return "IntegerBox".to_string();
|
||||
}
|
||||
if value.as_any().downcast_ref::<BoolBox>().is_some() {
|
||||
return "BoolBox".to_string();
|
||||
}
|
||||
if value.as_any().downcast_ref::<NullBox>().is_some() {
|
||||
return "NullBox".to_string();
|
||||
}
|
||||
simplify_type_name(value.type_name())
|
||||
}
|
||||
|
||||
fn simplify_type_name(full: &str) -> String {
|
||||
full.rsplit("::").next().unwrap_or(full).to_string()
|
||||
}
|
||||
|
||||
fn type_id_hash(value: &dyn NyashBox) -> u64 {
|
||||
let mut hasher = DefaultHasher::new();
|
||||
value.as_any().type_id().hash(&mut hasher);
|
||||
hasher.finish()
|
||||
}
|
||||
|
||||
/// Handle env.mirbuilder.* methods (Program(JSON v0) → MIR(JSON v0))
|
||||
fn handle_mirbuilder(method_name: &str, args: &[Box<dyn NyashBox>]) -> BidResult<Option<Box<dyn NyashBox>>> {
|
||||
fn handle_mirbuilder(
|
||||
method_name: &str,
|
||||
args: &[Box<dyn NyashBox>],
|
||||
) -> BidResult<Option<Box<dyn NyashBox>>> {
|
||||
match method_name {
|
||||
"emit" => {
|
||||
let program_json = args.get(0).map(|b| b.to_string_box().value).unwrap_or_default();
|
||||
let program_json = args
|
||||
.get(0)
|
||||
.map(|b| b.to_string_box().value)
|
||||
.unwrap_or_default();
|
||||
match crate::host_providers::mir_builder::program_json_to_mir_json(&program_json) {
|
||||
Ok(s) => Ok(Some(Box::new(StringBox::new(&s)) as Box<dyn NyashBox>)),
|
||||
Err(_e) => Ok(None),
|
||||
@ -222,21 +350,36 @@ fn handle_mirbuilder(method_name: &str, args: &[Box<dyn NyashBox>]) -> BidResult
|
||||
}
|
||||
|
||||
/// Handle env.codegen.* methods (MIR(JSON v0) → object via ny-llvmc)
|
||||
fn handle_codegen(method_name: &str, args: &[Box<dyn NyashBox>]) -> BidResult<Option<Box<dyn NyashBox>>> {
|
||||
fn handle_codegen(
|
||||
method_name: &str,
|
||||
args: &[Box<dyn NyashBox>],
|
||||
) -> BidResult<Option<Box<dyn NyashBox>>> {
|
||||
match method_name {
|
||||
"emit_object" => {
|
||||
let mir_json = args.get(0).map(|b| b.to_string_box().value).unwrap_or_default();
|
||||
let mir_json = args
|
||||
.get(0)
|
||||
.map(|b| b.to_string_box().value)
|
||||
.unwrap_or_default();
|
||||
// Collect minimal options from env (optional)
|
||||
let opt_level = std::env::var("HAKO_LLVM_OPT_LEVEL").ok().or_else(|| std::env::var("NYASH_LLVM_OPT_LEVEL").ok());
|
||||
let opt_level = std::env::var("HAKO_LLVM_OPT_LEVEL")
|
||||
.ok()
|
||||
.or_else(|| std::env::var("NYASH_LLVM_OPT_LEVEL").ok());
|
||||
let out = None;
|
||||
let nyrt = std::env::var("NYASH_EMIT_EXE_NYRT").ok().map(std::path::PathBuf::from);
|
||||
let opts = crate::host_providers::llvm_codegen::Opts { out, nyrt, opt_level, timeout_ms: None };
|
||||
let nyrt = std::env::var("NYASH_EMIT_EXE_NYRT")
|
||||
.ok()
|
||||
.map(std::path::PathBuf::from);
|
||||
let opts = crate::host_providers::llvm_codegen::Opts {
|
||||
out,
|
||||
nyrt,
|
||||
opt_level,
|
||||
timeout_ms: None,
|
||||
};
|
||||
match crate::host_providers::llvm_codegen::mir_json_to_object(&mir_json, opts) {
|
||||
Ok(p) => {
|
||||
// Convert PathBuf → String via lossy conversion (owned)
|
||||
let s = p.to_string_lossy().into_owned();
|
||||
Ok(Some(Box::new(StringBox::new(s)) as Box<dyn NyashBox>))
|
||||
},
|
||||
}
|
||||
Err(_e) => Ok(None),
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user