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:
@ -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