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

453 lines
17 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

use super::match_expr;
use super::merge::new_block;
use super::globals::resolve_bridge_global;
use super::ternary;
use super::BridgeEnv;
use super::throw_lower::lower_throw;
use crate::mir::{BasicBlockId, ConstValue, EffectMask, MirFunction, MirInstruction, ValueId};
use crate::ast::Span;
use std::collections::BTreeMap;
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 BTreeMap<String, ValueId>,
}
impl<'a> MapVars<'a> {
fn new(vars: &'a mut BTreeMap<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));
}
// Bridge 固有のグローバル解決imports/hostbridge/env/me dummyは専用モジュールに委譲
if let Some(vid) =
resolve_bridge_global(name, env, f, cur_bb, self.vars)?
{
return Ok(Some(vid));
}
Ok(None)
}
}
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_spanned(
f,
merge_bb,
out,
inputs,
Span::unknown(),
);
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));
}
// 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();
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 BTreeMap<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 BTreeMap<String, ValueId>,
) -> Result<(Vec<ValueId>, BasicBlockId), String> {
let mut scope = MapVars::new(vars);
lower_args_with_scope(env, f, cur_bb, args, &mut scope)
}