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:
355
src/runner/json_v1_bridge.rs
Normal file
355
src/runner/json_v1_bridge.rs
Normal file
@ -0,0 +1,355 @@
|
||||
use crate::mir::{
|
||||
function::{FunctionSignature, MirFunction, MirModule},
|
||||
BasicBlock, BasicBlockId, ConstValue, EffectMask, MirInstruction, MirType, ValueId,
|
||||
};
|
||||
use serde_json::Value;
|
||||
|
||||
/// Try to parse MIR JSON v1 schema into a MIR module.
|
||||
/// Returns Ok(None) when the input is not v1 (schema_version missing).
|
||||
/// Currently supports a minimal subset required for Gate-C parity tests:
|
||||
/// - const (integer)
|
||||
/// - copy
|
||||
/// - ret
|
||||
#[allow(dead_code)]
|
||||
pub fn try_parse_v1_to_module(json: &str) -> Result<Option<MirModule>, String> {
|
||||
let value: Value = match serde_json::from_str(json) {
|
||||
Ok(v) => v,
|
||||
Err(e) => return Err(format!("invalid JSON: {}", e)),
|
||||
};
|
||||
|
||||
let schema = match value.get("schema_version") {
|
||||
Some(Value::String(s)) => s.clone(),
|
||||
Some(other) => {
|
||||
return Err(format!(
|
||||
"expected schema_version string, found {}",
|
||||
other
|
||||
))
|
||||
}
|
||||
None => return Ok(None),
|
||||
};
|
||||
|
||||
if !schema.starts_with('1') {
|
||||
return Err(format!(
|
||||
"unsupported schema_version '{}': expected 1.x",
|
||||
schema
|
||||
));
|
||||
}
|
||||
|
||||
let functions = value
|
||||
.get("functions")
|
||||
.and_then(|f| f.as_array())
|
||||
.ok_or_else(|| "v1 JSON missing functions array".to_string())?;
|
||||
|
||||
let mut module = MirModule::new("ny_json_v1".to_string());
|
||||
|
||||
for func in functions {
|
||||
let func_name = func
|
||||
.get("name")
|
||||
.and_then(|n| n.as_str())
|
||||
.unwrap_or("main")
|
||||
.to_string();
|
||||
|
||||
let blocks = func
|
||||
.get("blocks")
|
||||
.and_then(|b| b.as_array())
|
||||
.ok_or_else(|| format!("function '{}' missing blocks array", func_name))?;
|
||||
|
||||
if blocks.is_empty() {
|
||||
return Err(format!("function '{}' has no blocks", func_name));
|
||||
}
|
||||
|
||||
let entry_id = blocks
|
||||
.get(0)
|
||||
.and_then(|b| b.get("id"))
|
||||
.and_then(|id| id.as_u64())
|
||||
.ok_or_else(|| format!("function '{}' entry block missing id", func_name))?;
|
||||
let entry_bb = BasicBlockId::new(entry_id as u32);
|
||||
|
||||
let mut signature = FunctionSignature {
|
||||
name: func_name.clone(),
|
||||
params: Vec::new(),
|
||||
return_type: MirType::Unknown,
|
||||
effects: EffectMask::PURE,
|
||||
};
|
||||
let mut mir_fn = MirFunction::new(signature.clone(), entry_bb);
|
||||
let mut max_value_id: u32 = 0;
|
||||
|
||||
for block in blocks {
|
||||
let block_id = block
|
||||
.get("id")
|
||||
.and_then(|id| id.as_u64())
|
||||
.ok_or_else(|| format!("function '{}' block missing id", func_name))? as u32;
|
||||
let bb_id = BasicBlockId::new(block_id);
|
||||
if mir_fn.get_block(bb_id).is_none() {
|
||||
mir_fn.add_block(BasicBlock::new(bb_id));
|
||||
}
|
||||
let block_ref = mir_fn
|
||||
.get_block_mut(bb_id)
|
||||
.expect("block must exist after insertion");
|
||||
|
||||
let instructions = block
|
||||
.get("instructions")
|
||||
.and_then(|insts| insts.as_array())
|
||||
.ok_or_else(|| {
|
||||
format!(
|
||||
"function '{}' block {} missing instructions array",
|
||||
func_name, block_id
|
||||
)
|
||||
})?;
|
||||
|
||||
for inst in instructions {
|
||||
let op = inst
|
||||
.get("op")
|
||||
.and_then(|o| o.as_str())
|
||||
.ok_or_else(|| {
|
||||
format!(
|
||||
"function '{}' block {} missing op field",
|
||||
func_name, block_id
|
||||
)
|
||||
})?;
|
||||
match op {
|
||||
"const" => {
|
||||
let dst = inst
|
||||
.get("dst")
|
||||
.and_then(|d| d.as_u64())
|
||||
.ok_or_else(|| {
|
||||
format!(
|
||||
"const instruction missing dst in function '{}'",
|
||||
func_name
|
||||
)
|
||||
})? as u32;
|
||||
let value_obj = inst
|
||||
.get("value")
|
||||
.ok_or_else(|| {
|
||||
format!(
|
||||
"const instruction missing value in function '{}'",
|
||||
func_name
|
||||
)
|
||||
})?;
|
||||
let const_val = parse_const_value(value_obj)?;
|
||||
block_ref.add_instruction(MirInstruction::Const {
|
||||
dst: ValueId::new(dst),
|
||||
value: const_val,
|
||||
});
|
||||
if dst >= max_value_id {
|
||||
max_value_id = dst + 1;
|
||||
}
|
||||
}
|
||||
"copy" => {
|
||||
let dst = inst
|
||||
.get("dst")
|
||||
.and_then(|d| d.as_u64())
|
||||
.ok_or_else(|| {
|
||||
format!(
|
||||
"copy instruction missing dst in function '{}'",
|
||||
func_name
|
||||
)
|
||||
})? as u32;
|
||||
let src = inst
|
||||
.get("src")
|
||||
.and_then(|d| d.as_u64())
|
||||
.ok_or_else(|| {
|
||||
format!(
|
||||
"copy instruction missing src in function '{}'",
|
||||
func_name
|
||||
)
|
||||
})? as u32;
|
||||
block_ref.add_instruction(MirInstruction::Copy {
|
||||
dst: ValueId::new(dst),
|
||||
src: ValueId::new(src),
|
||||
});
|
||||
if dst >= max_value_id {
|
||||
max_value_id = dst + 1;
|
||||
}
|
||||
}
|
||||
"binop" => {
|
||||
let dst = require_u64(inst, "dst", "binop dst")? as u32;
|
||||
let lhs = require_u64(inst, "lhs", "binop lhs")? as u32;
|
||||
let rhs = require_u64(inst, "rhs", "binop rhs")? as u32;
|
||||
let operation = inst
|
||||
.get("operation")
|
||||
.and_then(Value::as_str)
|
||||
.ok_or_else(|| format!("binop operation missing in function '{}'", func_name))?;
|
||||
let bop = parse_binop(operation)?;
|
||||
block_ref.add_instruction(MirInstruction::BinOp {
|
||||
dst: ValueId::new(dst),
|
||||
op: bop,
|
||||
lhs: ValueId::new(lhs),
|
||||
rhs: ValueId::new(rhs),
|
||||
});
|
||||
max_value_id = max_value_id.max(dst + 1);
|
||||
}
|
||||
"compare" => {
|
||||
let dst = require_u64(inst, "dst", "compare dst")? as u32;
|
||||
let lhs = require_u64(inst, "lhs", "compare lhs")? as u32;
|
||||
let rhs = require_u64(inst, "rhs", "compare rhs")? as u32;
|
||||
let operation = inst
|
||||
.get("operation")
|
||||
.and_then(Value::as_str)
|
||||
.ok_or_else(|| format!("compare operation missing in function '{}'", func_name))?;
|
||||
let cop = parse_compare(operation)?;
|
||||
block_ref.add_instruction(MirInstruction::Compare {
|
||||
dst: ValueId::new(dst),
|
||||
op: cop,
|
||||
lhs: ValueId::new(lhs),
|
||||
rhs: ValueId::new(rhs),
|
||||
});
|
||||
max_value_id = max_value_id.max(dst + 1);
|
||||
}
|
||||
"branch" => {
|
||||
let cond = require_u64(inst, "cond", "branch cond")? as u32;
|
||||
let then_bb = require_u64(inst, "then", "branch then")? as u32;
|
||||
let else_bb = require_u64(inst, "else", "branch else")? as u32;
|
||||
block_ref.add_instruction(MirInstruction::Branch {
|
||||
condition: ValueId::new(cond),
|
||||
then_bb: BasicBlockId::new(then_bb),
|
||||
else_bb: BasicBlockId::new(else_bb),
|
||||
});
|
||||
}
|
||||
"jump" => {
|
||||
let target = require_u64(inst, "target", "jump target")? as u32;
|
||||
block_ref.add_instruction(MirInstruction::Jump {
|
||||
target: BasicBlockId::new(target),
|
||||
});
|
||||
}
|
||||
"phi" => {
|
||||
let dst = require_u64(inst, "dst", "phi dst")? as u32;
|
||||
let incoming = inst
|
||||
.get("incoming")
|
||||
.and_then(Value::as_array)
|
||||
.ok_or_else(|| format!("phi incoming missing in function '{}'", func_name))?;
|
||||
let mut pairs = Vec::with_capacity(incoming.len());
|
||||
for entry in incoming {
|
||||
let pair = entry
|
||||
.as_array()
|
||||
.ok_or_else(|| format!("phi incoming entry must be array in function '{}'", func_name))?;
|
||||
if pair.len() != 2 {
|
||||
return Err("phi incoming entry must have 2 elements".into());
|
||||
}
|
||||
let val = pair[0]
|
||||
.as_u64()
|
||||
.ok_or_else(|| "phi incoming value must be integer".to_string())?;
|
||||
let bb = pair[1]
|
||||
.as_u64()
|
||||
.ok_or_else(|| "phi incoming block must be integer".to_string())?;
|
||||
pairs.push((BasicBlockId::new(bb as u32), ValueId::new(val as u32)));
|
||||
}
|
||||
block_ref.add_instruction(MirInstruction::Phi {
|
||||
dst: ValueId::new(dst),
|
||||
inputs: pairs,
|
||||
});
|
||||
max_value_id = max_value_id.max(dst + 1);
|
||||
}
|
||||
"ret" => {
|
||||
let value = inst
|
||||
.get("value")
|
||||
.and_then(|v| v.as_u64())
|
||||
.map(|v| ValueId::new(v as u32));
|
||||
block_ref.add_instruction(MirInstruction::Return { value });
|
||||
if let Some(val) = value {
|
||||
signature.return_type = MirType::Integer;
|
||||
max_value_id = max_value_id.max(val.as_u32() + 1);
|
||||
} else {
|
||||
signature.return_type = MirType::Void;
|
||||
}
|
||||
}
|
||||
other => {
|
||||
return Err(format!(
|
||||
"unsupported instruction '{}' in function '{}' (Gate-C v1 bridge)",
|
||||
other, func_name
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
mir_fn.signature = signature;
|
||||
mir_fn.next_value_id = max_value_id;
|
||||
module.add_function(mir_fn);
|
||||
}
|
||||
|
||||
Ok(Some(module))
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn parse_const_value(value_obj: &Value) -> Result<ConstValue, String> {
|
||||
let (type_str, raw_val) = if let Some(t) = value_obj.get("type") {
|
||||
(
|
||||
t.clone(),
|
||||
value_obj
|
||||
.get("value")
|
||||
.cloned()
|
||||
.ok_or_else(|| "const value missing numeric value".to_string())?,
|
||||
)
|
||||
} else {
|
||||
(Value::String("i64".to_string()), value_obj.clone())
|
||||
};
|
||||
|
||||
match type_str {
|
||||
Value::String(s) => match s.as_str() {
|
||||
"i64" | "int" => {
|
||||
let val = raw_val
|
||||
.as_i64()
|
||||
.ok_or_else(|| "const value expected integer".to_string())?;
|
||||
Ok(ConstValue::Integer(val))
|
||||
}
|
||||
other => Err(format!(
|
||||
"unsupported const type '{}' in Gate-C v1 bridge",
|
||||
other
|
||||
)),
|
||||
},
|
||||
Value::Object(obj) => {
|
||||
if let Some(Value::String(kind)) = obj.get("kind") {
|
||||
if kind == "handle" {
|
||||
if let Some(Value::String(box_type)) = obj.get("box_type") {
|
||||
return Err(format!(
|
||||
"unsupported const handle type '{}' in Gate-C v1 bridge",
|
||||
box_type
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
Err("unsupported const type object in Gate-C v1 bridge".to_string())
|
||||
}
|
||||
_ => Err("const value has unsupported type descriptor".to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
fn require_u64(node: &Value, key: &str, context: &str) -> Result<u64, String> {
|
||||
node.get(key)
|
||||
.and_then(Value::as_u64)
|
||||
.ok_or_else(|| format!("{} missing field '{}'", context, key))
|
||||
}
|
||||
|
||||
fn parse_binop(op: &str) -> Result<crate::mir::types::BinaryOp, String> {
|
||||
use crate::mir::types::BinaryOp;
|
||||
let bop = match op {
|
||||
"+" => BinaryOp::Add,
|
||||
"-" => BinaryOp::Sub,
|
||||
"*" => BinaryOp::Mul,
|
||||
"/" => BinaryOp::Div,
|
||||
"%" => BinaryOp::Mod,
|
||||
"&" | "bitand" => BinaryOp::BitAnd,
|
||||
"|" | "bitor" => BinaryOp::BitOr,
|
||||
"^" | "bitxor" => BinaryOp::BitXor,
|
||||
"shl" => BinaryOp::Shl,
|
||||
"shr" => BinaryOp::Shr,
|
||||
"and" => BinaryOp::And,
|
||||
"or" => BinaryOp::Or,
|
||||
other => return Err(format!("unsupported binop '{}'", other)),
|
||||
};
|
||||
Ok(bop)
|
||||
}
|
||||
|
||||
fn parse_compare(op: &str) -> Result<crate::mir::types::CompareOp, String> {
|
||||
use crate::mir::types::CompareOp;
|
||||
let cop = match op {
|
||||
"==" => CompareOp::Eq,
|
||||
"!=" => CompareOp::Ne,
|
||||
"<" => CompareOp::Lt,
|
||||
"<=" => CompareOp::Le,
|
||||
">" => CompareOp::Gt,
|
||||
">=" => CompareOp::Ge,
|
||||
other => return Err(format!("unsupported compare op '{}'", other)),
|
||||
};
|
||||
Ok(cop)
|
||||
}
|
||||
@ -21,6 +21,7 @@ mod cli_directives;
|
||||
mod demos;
|
||||
mod dispatch;
|
||||
mod json_v0_bridge;
|
||||
mod json_v1_bridge;
|
||||
mod mir_json_emit;
|
||||
pub mod modes;
|
||||
mod pipe_io;
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
@ -36,11 +36,25 @@ impl NyashRunner {
|
||||
}
|
||||
buf
|
||||
};
|
||||
if crate::config::env::nyvm_core_wrapper() {
|
||||
let use_core_wrapper = crate::config::env::nyvm_core_wrapper();
|
||||
let use_downconvert = crate::config::env::nyvm_v1_downconvert();
|
||||
if use_core_wrapper || use_downconvert {
|
||||
match crate::runner::modes::common_util::core_bridge::canonicalize_module_json(&json) {
|
||||
Ok(j) => json = j,
|
||||
Err(e) => eprintln!("[bridge] canonicalize warning: {}", e),
|
||||
}
|
||||
match crate::runner::json_v1_bridge::try_parse_v1_to_module(&json) {
|
||||
Ok(Some(module)) => {
|
||||
super::json_v0_bridge::maybe_dump_mir(&module);
|
||||
self.execute_mir_module(&module);
|
||||
return true;
|
||||
}
|
||||
Ok(None) => {}
|
||||
Err(e) => {
|
||||
eprintln!("❌ JSON v1 bridge error: {}", e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
match super::json_v0_bridge::parse_json_v0_to_module(&json) {
|
||||
Ok(module) => {
|
||||
|
||||
Reference in New Issue
Block a user