docs(phase-20.33): update Gate-C(Core) status (v1→MIR interpreter), mark parity smokes done; clean up wording\nchore: remove unused bak/ (external backup kept)\nsmokes: add Gate-C v1 file/pipe opt-in canaries; env toggles documented\nrunner: include json_v1_bridge + bridge toggles (singleton/phi) wiring
This commit is contained in:
@ -1,23 +1,230 @@
|
||||
/*!
|
||||
* core_bridge.rs — NyVM wrapper bridge helpers
|
||||
*
|
||||
* Provides a minimal JSON canonicalizer for NyVmDispatcher wrapper path.
|
||||
* Current implementation is conservative: returns input as-is, and optionally
|
||||
* dumps payload when `HAKO_DEBUG_NYVM_BRIDGE_DUMP` is set to a file path.
|
||||
* Provides a JSON canonicalizer for NyVmDispatcher wrapper path.
|
||||
* Optional env toggles:
|
||||
* - HAKO_BRIDGE_INJECT_SINGLETON / NYASH_BRIDGE_INJECT_SINGLETON:
|
||||
* Rewrite ModuleFunction Array/Map len calls into Method form.
|
||||
* - HAKO_BRIDGE_EARLY_PHI_MATERIALIZE / NYASH_BRIDGE_EARLY_PHI_MATERIALIZE:
|
||||
* Move phi instructions to block head (order-preserving).
|
||||
* Dumps payload when `HAKO_DEBUG_NYVM_BRIDGE_DUMP` is set to a file path.
|
||||
*/
|
||||
|
||||
use std::fs;
|
||||
use serde_json::Value;
|
||||
use std::{env, fs};
|
||||
|
||||
/// Canonicalize JSON to module shape expected by NyVmDispatcher.
|
||||
/// For now, this is a passthrough with optional debug dump.
|
||||
pub fn canonicalize_module_json(input: &str) -> Result<String, String> {
|
||||
if let Ok(path) = std::env::var("HAKO_DEBUG_NYVM_BRIDGE_DUMP") {
|
||||
let mut output = input.to_string();
|
||||
|
||||
if let Ok(path) = env::var("HAKO_DEBUG_NYVM_BRIDGE_DUMP") {
|
||||
if !path.trim().is_empty() {
|
||||
if let Err(e) = fs::write(&path, input.as_bytes()) {
|
||||
eprintln!("[bridge/dump] write error: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(input.to_string())
|
||||
|
||||
let inject_singleton = env_flag("HAKO_BRIDGE_INJECT_SINGLETON")
|
||||
|| env_flag("NYASH_BRIDGE_INJECT_SINGLETON");
|
||||
let materialize_phi = env_flag("HAKO_BRIDGE_EARLY_PHI_MATERIALIZE")
|
||||
|| env_flag("NYASH_BRIDGE_EARLY_PHI_MATERIALIZE");
|
||||
|
||||
if inject_singleton || materialize_phi {
|
||||
let mut json: Value = serde_json::from_str(input)
|
||||
.map_err(|e| format!("bridge canonicalize: invalid JSON ({})", e))?;
|
||||
let mut mutated = false;
|
||||
if inject_singleton {
|
||||
mutated |= inject_singleton_methods(&mut json)?;
|
||||
}
|
||||
if materialize_phi {
|
||||
mutated |= materialize_phi_blocks(&mut json)?;
|
||||
}
|
||||
if mutated {
|
||||
output = serde_json::to_string(&json)
|
||||
.map_err(|e| format!("bridge canonicalize: serialize error ({})", e))?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(output)
|
||||
}
|
||||
|
||||
fn env_flag(name: &str) -> bool {
|
||||
env::var(name)
|
||||
.ok()
|
||||
.map(|v| matches!(v.trim().to_ascii_lowercase().as_str(), "1" | "true" | "on"))
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
fn inject_singleton_methods(root: &mut Value) -> Result<bool, String> {
|
||||
let mut changed = false;
|
||||
let functions = match root.as_object_mut() {
|
||||
Some(obj) => obj.get_mut("functions"),
|
||||
None => return Err("bridge canonicalize: expected JSON object at root".into()),
|
||||
};
|
||||
let functions = match functions {
|
||||
Some(Value::Array(arr)) => arr,
|
||||
Some(_) => return Err("bridge canonicalize: functions must be array".into()),
|
||||
None => return Ok(false),
|
||||
};
|
||||
|
||||
for func in functions.iter_mut() {
|
||||
let blocks = func
|
||||
.get_mut("blocks")
|
||||
.and_then(Value::as_array_mut);
|
||||
let Some(blocks) = blocks else { continue };
|
||||
for block in blocks.iter_mut() {
|
||||
let insts = block
|
||||
.get_mut("instructions")
|
||||
.and_then(Value::as_array_mut);
|
||||
let Some(insts) = insts else { continue };
|
||||
for inst in insts.iter_mut() {
|
||||
if transform_module_function(inst)? {
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(changed)
|
||||
}
|
||||
|
||||
fn transform_module_function(inst: &mut Value) -> Result<bool, String> {
|
||||
let obj = match inst.as_object_mut() {
|
||||
Some(map) => map,
|
||||
None => return Ok(false),
|
||||
};
|
||||
match obj.get("op").and_then(Value::as_str) {
|
||||
Some("mir_call") => {}
|
||||
_ => return Ok(false),
|
||||
}
|
||||
let mir_call = match obj.get_mut("mir_call").and_then(Value::as_object_mut) {
|
||||
Some(mc) => mc,
|
||||
None => return Ok(false),
|
||||
};
|
||||
let name_owned = {
|
||||
let callee_obj = match mir_call.get("callee").and_then(Value::as_object) {
|
||||
Some(c) => c,
|
||||
None => return Ok(false),
|
||||
};
|
||||
match callee_obj.get("type").and_then(Value::as_str) {
|
||||
Some("ModuleFunction") => {}
|
||||
_ => return Ok(false),
|
||||
}
|
||||
callee_obj
|
||||
.get("name")
|
||||
.and_then(Value::as_str)
|
||||
.ok_or_else(|| "bridge canonicalize: ModuleFunction missing name".to_string())?
|
||||
.to_string()
|
||||
};
|
||||
let name = name_owned.as_str();
|
||||
|
||||
let (box_name, method) = match name {
|
||||
"ArrayBox.len" => ("ArrayBox", "size"),
|
||||
"MapBox.len" => ("MapBox", "len"),
|
||||
_ => return Ok(false),
|
||||
};
|
||||
|
||||
let receiver_value = mir_call
|
||||
.get_mut("args")
|
||||
.and_then(Value::as_array_mut)
|
||||
.ok_or_else(|| "bridge canonicalize: mir_call.args missing".to_string())?;
|
||||
if receiver_value.is_empty() {
|
||||
return Err(format!(
|
||||
"bridge canonicalize: {} requires receiver argument",
|
||||
name
|
||||
));
|
||||
}
|
||||
let receiver_value = receiver_value.remove(0);
|
||||
let receiver = receiver_value
|
||||
.as_u64()
|
||||
.ok_or_else(|| format!("bridge canonicalize: {} receiver must be integer", name))?;
|
||||
|
||||
let num = serde_json::Number::from_u128(receiver as u128)
|
||||
.ok_or_else(|| "bridge canonicalize: receiver out of range".to_string())?;
|
||||
|
||||
let callee = mir_call
|
||||
.get_mut("callee")
|
||||
.and_then(Value::as_object_mut)
|
||||
.ok_or_else(|| "bridge canonicalize: callee missing".to_string())?;
|
||||
callee.insert("type".to_string(), Value::String("Method".into()));
|
||||
callee.insert("method".to_string(), Value::String(method.into()));
|
||||
callee.insert("box_name".to_string(), Value::String(box_name.into()));
|
||||
callee.insert("receiver".to_string(), Value::Number(num));
|
||||
callee.remove("name");
|
||||
if !callee.contains_key("certainty") {
|
||||
callee.insert("certainty".to_string(), Value::String("Known".into()));
|
||||
}
|
||||
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
fn materialize_phi_blocks(root: &mut Value) -> Result<bool, String> {
|
||||
let mut changed = false;
|
||||
let functions = match root.as_object_mut() {
|
||||
Some(obj) => obj.get_mut("functions"),
|
||||
None => return Err("bridge canonicalize: expected JSON object at root".into()),
|
||||
};
|
||||
let functions = match functions {
|
||||
Some(Value::Array(arr)) => arr,
|
||||
Some(_) => return Err("bridge canonicalize: functions must be array".into()),
|
||||
None => return Ok(false),
|
||||
};
|
||||
|
||||
for func in functions.iter_mut() {
|
||||
let blocks = func
|
||||
.get_mut("blocks")
|
||||
.and_then(Value::as_array_mut);
|
||||
let Some(blocks) = blocks else { continue };
|
||||
for block in blocks.iter_mut() {
|
||||
let insts = block
|
||||
.get_mut("instructions")
|
||||
.and_then(Value::as_array_mut);
|
||||
let Some(insts) = insts else { continue };
|
||||
if reorder_block_phi(insts)? {
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(changed)
|
||||
}
|
||||
|
||||
fn reorder_block_phi(insts: &mut Vec<Value>) -> Result<bool, String> {
|
||||
let mut seen_non_phi = false;
|
||||
let mut needs_reorder = false;
|
||||
for inst in insts.iter() {
|
||||
if is_phi(inst) {
|
||||
if seen_non_phi {
|
||||
needs_reorder = true;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
seen_non_phi = true;
|
||||
}
|
||||
}
|
||||
if !needs_reorder {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
let original = std::mem::take(insts);
|
||||
let mut phis = Vec::new();
|
||||
let mut others = Vec::new();
|
||||
for inst in original.into_iter() {
|
||||
if is_phi(&inst) {
|
||||
phis.push(inst);
|
||||
} else {
|
||||
others.push(inst);
|
||||
}
|
||||
}
|
||||
insts.extend(phis);
|
||||
insts.extend(others);
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
fn is_phi(inst: &Value) -> bool {
|
||||
inst.as_object()
|
||||
.and_then(|obj| obj.get("op"))
|
||||
.and_then(Value::as_str)
|
||||
.map(|op| op == "phi")
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user