Files
hakorune/src/runner/json_v0_bridge/lowering/expr.rs

464 lines
18 KiB
Rust
Raw Normal View History

use super::merge::new_block;
use super::BridgeEnv;
use super::ternary;
use super::match_expr;
use crate::mir::{
BasicBlockId, BinaryOp, ConstValue, EffectMask, MirFunction, MirInstruction, ValueId,
};
use std::collections::HashMap;
use super::super::ast::ExprV0;
pub(super) trait VarScope {
fn resolve(
&mut self,
env: &BridgeEnv,
f: &mut MirFunction,
cur_bb: BasicBlockId,
name: &str,
) -> Result<Option<ValueId>, String>;
}
pub(super) struct NoVars;
impl VarScope for NoVars {
fn resolve(
&mut self,
_env: &BridgeEnv,
_f: &mut MirFunction,
_cur_bb: BasicBlockId,
name: &str,
) -> Result<Option<ValueId>, String> {
Err(format!("undefined variable in this context: {}", name))
}
}
pub(super) struct MapVars<'a> {
vars: &'a mut HashMap<String, ValueId>,
}
impl<'a> MapVars<'a> {
fn new(vars: &'a mut HashMap<String, ValueId>) -> Self {
Self { vars }
}
}
impl<'a> VarScope for MapVars<'a> {
fn resolve(
&mut self,
env: &BridgeEnv,
f: &mut MirFunction,
cur_bb: BasicBlockId,
name: &str,
) -> Result<Option<ValueId>, String> {
if let Some(&vid) = self.vars.get(name) {
return Ok(Some(vid));
}
// Phase 21.8: Check using-imported modules/boxes
if let Some(box_type) = env.imports.get(name) {
let dst = f.next_value_id();
if let Some(bb) = f.get_block_mut(cur_bb) {
// Treat as static box reference - create a const string representing the box type
bb.add_instruction(MirInstruction::Const {
dst,
value: ConstValue::String(box_type.clone()),
});
}
// Cache the resolution for subsequent uses
self.vars.insert(name.to_string(), dst);
return Ok(Some(dst));
}
// Phase 25.1a: Treat `hostbridge` as a well-known global for bridge lowering.
// The actual extern dispatch is handled at runtime; here we only need a stable
// placeholder value so that Program(JSON) containing hostbridge.extern_invoke(...)
// can be lowered without "undefined variable" errors.
if name == "hostbridge" {
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("hostbridge".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();
if let Some(bb) = f.get_block_mut(cur_bb) {
bb.add_instruction(MirInstruction::NewBox {
dst,
box_type: env.me_class.clone(),
args: vec![],
});
}
self.vars.insert(name.to_string(), dst);
Ok(Some(dst))
} else {
Err("undefined 'me' outside box context (set NYASH_BRIDGE_ME_DUMMY=1 to inject placeholder)".into())
}
} else {
Ok(None)
}
}
}
fn lower_throw(
env: &BridgeEnv,
f: &mut MirFunction,
cur_bb: BasicBlockId,
exception_value: ValueId,
) -> (ValueId, BasicBlockId) {
// Result-mode try context active: route to current catch via Jump and record incoming
if env.try_result_mode && super::throw_ctx::is_active() {
if crate::config::env::cli_verbose() {
eprintln!("[Bridge] lower_throw: routing to catch (Result-mode)");
}
let _ = super::throw_ctx::record_throw(f, cur_bb, exception_value);
return (exception_value, cur_bb);
}
// Legacy path: emit MIR Throw (if enabled) or degrade to const 0
if env.throw_enabled {
if let Some(bb) = f.get_block_mut(cur_bb) {
bb.set_terminator(MirInstruction::Throw {
exception: exception_value,
effects: EffectMask::PANIC,
});
}
(exception_value, cur_bb)
} else {
let dst = f.next_value_id();
if let Some(bb) = f.get_block_mut(cur_bb) {
bb.add_instruction(MirInstruction::Const { dst, value: ConstValue::Integer(0) });
}
(dst, cur_bb)
}
}
pub(super) fn lower_expr_with_scope<S: VarScope>(
env: &BridgeEnv,
f: &mut MirFunction,
cur_bb: BasicBlockId,
e: &ExprV0,
vars: &mut S,
) -> Result<(ValueId, BasicBlockId), String> {
match e {
ExprV0::Int { value } => {
let ival: i64 = if let Some(n) = value.as_i64() {
n
} else if let Some(s) = value.as_str() {
s.parse().map_err(|_| "invalid int literal")?
} else {
return Err("invalid int literal".into());
};
let dst = f.next_value_id();
if let Some(bb) = f.get_block_mut(cur_bb) {
bb.add_instruction(MirInstruction::Const {
dst,
value: ConstValue::Integer(ival),
});
}
Ok((dst, cur_bb))
}
ExprV0::Str { value } => {
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(value.clone()),
});
}
Ok((dst, cur_bb))
}
ExprV0::Bool { value } => {
let dst = f.next_value_id();
if let Some(bb) = f.get_block_mut(cur_bb) {
bb.add_instruction(MirInstruction::Const {
dst,
value: ConstValue::Bool(*value),
});
}
Ok((dst, cur_bb))
}
ExprV0::Null => {
let dst = f.next_value_id();
if let Some(bb) = f.get_block_mut(cur_bb) {
bb.add_instruction(MirInstruction::Const {
dst,
value: ConstValue::Null,
});
}
Ok((dst, cur_bb))
}
ExprV0::Binary { op, lhs, rhs } => {
let (l, cur_after_l) = lower_expr_with_scope(env, f, cur_bb, lhs, vars)?;
let (r, cur_after_r) = lower_expr_with_scope(env, f, cur_after_l, rhs, vars)?;
let bop = match crate::mir::ssot::binop_lower::parse_binop_str(op) {
Some(b) => b,
None => return Err("unsupported op".into()),
};
let dst = crate::mir::ssot::binop_lower::emit_binop_func(f, cur_after_r, bop, l, r);
Ok((dst, cur_after_r))
}
ExprV0::Extern {
iface,
method,
args,
} => {
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: iface.clone(),
method_name: method.clone(),
args: arg_ids,
effects: EffectMask::IO,
});
}
Ok((dst, cur2))
}
ExprV0::Compare { op, lhs, rhs } => {
let (l, cur_after_l) = lower_expr_with_scope(env, f, cur_bb, lhs, vars)?;
let (r, cur_after_r) = lower_expr_with_scope(env, f, cur_after_l, rhs, vars)?;
let cop = match op.as_str() {
"==" => crate::mir::CompareOp::Eq,
"!=" => crate::mir::CompareOp::Ne,
"<" => crate::mir::CompareOp::Lt,
"<=" => crate::mir::CompareOp::Le,
">" => crate::mir::CompareOp::Gt,
">=" => crate::mir::CompareOp::Ge,
_ => return Err("unsupported compare op".into()),
};
let dst = f.next_value_id();
crate::mir::ssot::cf_common::emit_compare_func(f, cur_after_r, dst, cop, l, r);
Ok((dst, cur_after_r))
}
ExprV0::Logical { op, lhs, rhs } => {
let (l, cur_after_l) = lower_expr_with_scope(env, f, cur_bb, lhs, vars)?;
let rhs_bb = new_block(f);
let fall_bb = new_block(f);
let merge_bb = new_block(f);
let is_and = matches!(op.as_str(), "&&" | "and");
if is_and {
crate::mir::ssot::cf_common::set_branch(f, cur_after_l, l, rhs_bb, fall_bb);
} else {
crate::mir::ssot::cf_common::set_branch(f, cur_after_l, l, fall_bb, rhs_bb);
}
// ARCHIVED: JIT events moved to archive/jit-cranelift/ during Phase 15
// crate::jit::events::emit_lower(
// serde_json::json!({ "id":"shortcircuit","op": if is_and {"and"} else {"or"},"rhs_bb":rhs_bb.0,"fall_bb":fall_bb.0,"merge_bb":merge_bb.0 }),
// "shortcircuit",
// "<json_v0>",
// );
let cdst = f.next_value_id();
if let Some(bb) = f.get_block_mut(fall_bb) {
let cval = if is_and { ConstValue::Bool(false) } else { ConstValue::Bool(true) };
bb.add_instruction(MirInstruction::Const { dst: cdst, value: cval });
}
crate::mir::ssot::cf_common::set_jump(f, fall_bb, merge_bb);
let (rval, rhs_end) = lower_expr_with_scope(env, f, rhs_bb, rhs, vars)?;
if let Some(bb) = f.get_block_mut(rhs_end) {
if !bb.is_terminated() {
crate::mir::ssot::cf_common::set_jump(f, rhs_end, merge_bb);
}
}
let out = f.next_value_id();
// フェーズM.2: PHI統一処理no_phi分岐削除
let mut inputs: Vec<(BasicBlockId, ValueId)> = vec![(fall_bb, cdst)];
if rhs_end != fall_bb { inputs.push((rhs_end, rval)); } else { inputs.push((fall_bb, rval)); }
crate::mir::ssot::cf_common::insert_phi_at_head(f, merge_bb, out, inputs);
Ok((out, merge_bb))
}
ExprV0::Call { name, args } => {
if name == "array.of" {
let arr = f.next_value_id();
if let Some(bb) = f.get_block_mut(cur_bb) {
bb.add_instruction(MirInstruction::NewBox {
dst: arr,
box_type: "ArrayBox".into(),
args: vec![],
});
}
let mut cur = cur_bb;
for e in args {
let (v, c) = lower_expr_with_scope(env, f, cur, e, vars)?;
cur = c;
let tmp = f.next_value_id();
if let Some(bb) = f.get_block_mut(cur) {
bb.add_instruction(MirInstruction::BoxCall {
dst: Some(tmp),
box_val: arr,
method: "push".into(),
method_id: None,
args: vec![v],
effects: EffectMask::READ,
});
}
}
return Ok((arr, cur));
}
if name == "map.of" {
let mapv = f.next_value_id();
if let Some(bb) = f.get_block_mut(cur_bb) {
bb.add_instruction(MirInstruction::NewBox {
dst: mapv,
box_type: "MapBox".into(),
args: vec![],
});
}
let mut cur = cur_bb;
let mut it = args.iter();
while let Some(k) = it.next() {
if let Some(v) = it.next() {
let (kv, cur2) = lower_expr_with_scope(env, f, cur, k, vars)?;
cur = cur2;
let (vv, cur3) = lower_expr_with_scope(env, f, cur, v, vars)?;
cur = cur3;
let tmp = f.next_value_id();
if let Some(bb) = f.get_block_mut(cur) {
bb.add_instruction(MirInstruction::BoxCall {
dst: Some(tmp),
box_val: mapv,
method: "set".into(),
method_id: None,
args: vec![kv, vv],
effects: EffectMask::READ,
});
}
} else {
break;
}
}
return Ok((mapv, cur));
}
let (arg_ids, cur) = lower_args_with_scope(env, f, cur_bb, args, vars)?;
let fun_val = f.next_value_id();
if let Some(bb) = f.get_block_mut(cur) {
bb.add_instruction(MirInstruction::Const { dst: fun_val, value: ConstValue::String(name.clone()) });
}
let dst = f.next_value_id();
if let Some(bb) = f.get_block_mut(cur) {
bb.add_instruction(MirInstruction::Call {
dst: Some(dst),
func: fun_val,
callee: None, // JSON bridge - use legacy resolution
args: arg_ids,
effects: EffectMask::READ,
});
}
Ok((dst, cur))
}
ExprV0::Method { recv, method, args } => {
let recv_is_console_new = matches!(&**recv, ExprV0::New { class, .. } if class == "ConsoleBox");
if recv_is_console_new && (method == "println" || method == "print" || method == "log") {
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.console".into(),
method_name: "log".into(),
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();
if let Some(bb) = f.get_block_mut(cur2) {
bb.add_instruction(MirInstruction::BoxCall {
dst: Some(dst),
box_val: recv_v,
method: method.clone(),
method_id: None,
args: arg_ids,
effects: EffectMask::READ,
});
}
Ok((dst, cur2))
}
ExprV0::New { class, args } => {
let (arg_ids, cur) = lower_args_with_scope(env, f, cur_bb, args, vars)?;
let dst = f.next_value_id();
if let Some(bb) = f.get_block_mut(cur) {
bb.add_instruction(MirInstruction::NewBox { dst, box_type: class.clone(), args: arg_ids });
}
Ok((dst, cur))
}
ExprV0::Var { name } => match vars.resolve(env, f, cur_bb, name)? {
Some(v) => Ok((v, cur_bb)),
None => Err(format!("undefined variable: {}", name)),
},
ExprV0::Throw { expr } => {
let (exc, cur) = lower_expr_with_scope(env, f, cur_bb, expr, vars)?;
Ok(lower_throw(env, f, cur, exc))
}
ExprV0::Ternary { cond, then, r#else } =>
ternary::lower_ternary_expr_with_scope(env, f, cur_bb, cond, then, r#else, vars),
ExprV0::Match { scrutinee, arms, r#else } =>
match_expr::lower_match_expr_with_scope(env, f, cur_bb, scrutinee, arms, r#else, vars),
}
}
fn lower_args_with_scope<S: VarScope>(
env: &BridgeEnv,
f: &mut MirFunction,
cur_bb: BasicBlockId,
args: &[ExprV0],
scope: &mut S,
) -> Result<(Vec<ValueId>, BasicBlockId), String> {
let mut out = Vec::with_capacity(args.len());
let mut cur = cur_bb;
for a in args {
let (v, c) = lower_expr_with_scope(env, f, cur, a, scope)?;
out.push(v);
cur = c;
}
Ok((out, cur))
}
#[allow(dead_code)]
fn lower_expr(
env: &BridgeEnv,
f: &mut MirFunction,
cur_bb: BasicBlockId,
e: &ExprV0,
) -> Result<(ValueId, BasicBlockId), String> {
let mut scope = NoVars;
lower_expr_with_scope(env, f, cur_bb, e, &mut scope)
}
pub(super) fn lower_expr_with_vars(
env: &BridgeEnv,
f: &mut MirFunction,
cur_bb: BasicBlockId,
e: &ExprV0,
vars: &mut HashMap<String, ValueId>,
) -> Result<(ValueId, BasicBlockId), String> {
let mut scope = MapVars::new(vars);
lower_expr_with_scope(env, f, cur_bb, e, &mut scope)
}
#[allow(dead_code)]
fn lower_args(
env: &BridgeEnv,
f: &mut MirFunction,
cur_bb: BasicBlockId,
args: &[ExprV0],
) -> Result<(Vec<ValueId>, BasicBlockId), String> {
let mut scope = NoVars;
lower_args_with_scope(env, f, cur_bb, args, &mut scope)
}
pub(super) fn lower_args_with_vars(
env: &BridgeEnv,
f: &mut MirFunction,
cur_bb: BasicBlockId,
args: &[ExprV0],
vars: &mut HashMap<String, ValueId>,
) -> Result<(Vec<ValueId>, BasicBlockId), String> {
let mut scope = MapVars::new(vars);
lower_args_with_scope(env, f, cur_bb, args, &mut scope)
}