From 31f90012e0485017ede32a5da9f7c7c96ec0ff01 Mon Sep 17 00:00:00 2001 From: Selfhosting Dev Date: Wed, 17 Sep 2025 08:20:44 +0900 Subject: [PATCH] =?UTF-8?q?refactor:=20extract=20helpers=20(builder=5Fcall?= =?UTF-8?q?s:=20math/env/me;=20json=5Fv0=5Fbridge:=20new=5Fblock/merge=5Fv?= =?UTF-8?q?alues)=20=E2=80=94=20non-functional=20cleanup;=20cargo=20check?= =?UTF-8?q?=20+=20smokes=20green?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/mir/builder/builder_calls.rs | 301 ++++++++++---------------- src/runner/json_v0_bridge/lowering.rs | 90 +++----- 2 files changed, 141 insertions(+), 250 deletions(-) diff --git a/src/mir/builder/builder_calls.rs b/src/mir/builder/builder_calls.rs index 08a3893d..d9103a88 100644 --- a/src/mir/builder/builder_calls.rs +++ b/src/mir/builder/builder_calls.rs @@ -4,6 +4,111 @@ use crate::ast::{ASTNode, LiteralValue, MethodCallExpr}; use crate::mir::{slot_registry, TypeOpKind}; impl super::MirBuilder { + /// Try handle math.* function in function-style (sin/cos/abs/min/max). + /// Returns Some(result) if handled, otherwise None. + fn try_handle_math_function( + &mut self, + name: &str, + raw_args: Vec, + ) -> Option> { + let is_math_func = matches!(name, "sin" | "cos" | "abs" | "min" | "max"); + if !is_math_func { + return None; + } + // Build numeric args directly for math.* to preserve f64 typing + let mut math_args: Vec = Vec::new(); + for a in raw_args.into_iter() { + match a { + ASTNode::New { class, arguments, .. } if class == "FloatBox" && arguments.len() == 1 => { + match self.build_expression(arguments[0].clone()) { v @ Ok(_) => math_args.push(v.unwrap()), err @ Err(_) => return Some(err), } + } + ASTNode::New { class, arguments, .. } if class == "IntegerBox" && arguments.len() == 1 => { + let iv = match self.build_expression(arguments[0].clone()) { Ok(v) => v, Err(e) => return Some(Err(e)) }; + let fv = self.value_gen.next(); + if let Err(e) = self.emit_instruction(MirInstruction::TypeOp { dst: fv, op: TypeOpKind::Cast, value: iv, ty: MirType::Float }) { return Some(Err(e)); } + math_args.push(fv); + } + ASTNode::Literal { value: LiteralValue::Float(_), .. } => { + match self.build_expression(a) { v @ Ok(_) => math_args.push(v.unwrap()), err @ Err(_) => return Some(err), } + } + other => { + match self.build_expression(other) { v @ Ok(_) => math_args.push(v.unwrap()), err @ Err(_) => return Some(err), } + } + } + } + // new MathBox() + let math_recv = self.value_gen.next(); + if let Err(e) = self.emit_instruction(MirInstruction::NewBox { dst: math_recv, box_type: "MathBox".to_string(), args: vec![] }) { return Some(Err(e)); } + self.value_origin_newbox.insert(math_recv, "MathBox".to_string()); + // birth() + let birt_mid = slot_registry::resolve_slot_by_type_name("MathBox", "birth"); + if let Err(e) = self.emit_box_or_plugin_call(None, math_recv, "birth".to_string(), birt_mid, vec![], EffectMask::READ) { return Some(Err(e)); } + // call method + let dst = self.value_gen.next(); + if let Err(e) = self.emit_box_or_plugin_call(Some(dst), math_recv, name.to_string(), None, math_args, EffectMask::READ) { return Some(Err(e)); } + Some(Ok(dst)) + } + + /// Try handle env.* extern methods like env.console.log via FieldAccess(object, field). + fn try_handle_env_method( + &mut self, + object: &ASTNode, + method: &str, + arguments: &Vec, + ) -> Option> { + let ASTNode::FieldAccess { object: env_obj, field: env_field, .. } = object else { return None; }; + if let ASTNode::Variable { name: env_name, .. } = env_obj.as_ref() { + if env_name != "env" { return None; } + // Build arguments once + let mut arg_values = Vec::new(); + for arg in arguments { + match self.build_expression(arg.clone()) { Ok(v) => arg_values.push(v), Err(e) => return Some(Err(e)) } + } + let iface = env_field.as_str(); + let m = method; + let mut extern_call = |iface_name: &str, method_name: &str, effects: EffectMask, returns: bool| -> Result { + let result_id = self.value_gen.next(); + self.emit_instruction(MirInstruction::ExternCall { dst: if returns { Some(result_id) } else { None }, iface_name: iface_name.to_string(), method_name: method_name.to_string(), args: arg_values.clone(), effects })?; + if returns { + Ok(result_id) + } else { + let void_id = self.value_gen.next(); + self.emit_instruction(MirInstruction::Const { dst: void_id, value: super::ConstValue::Void })?; + Ok(void_id) + } + }; + return Some(match (iface, m) { + ("future", "delay") => extern_call("env.future", "delay", EffectMask::READ.add(Effect::Io), true), + ("task", "currentToken") => extern_call("env.task", "currentToken", EffectMask::READ, true), + ("task", "cancelCurrent") => extern_call("env.task", "cancelCurrent", EffectMask::IO, false), + ("console", "log") => extern_call("env.console", "log", EffectMask::IO, false), + ("console", "readLine") => extern_call("env.console", "readLine", EffectMask::IO, true), + ("canvas", m) if matches!(m, "fillRect" | "fillText") => extern_call("env.canvas", m, EffectMask::IO, false), + _ => return None, + }); + } + None + } + + /// Try direct static call for `me` in static box + fn try_handle_me_direct_call( + &mut self, + method: &str, + arguments: &Vec, + ) -> Option> { + let Some(cls_name) = self.current_static_box.clone() else { return None; }; + // Build args + let mut arg_values = Vec::new(); + for a in arguments { + match self.build_expression(a.clone()) { Ok(v) => arg_values.push(v), Err(e) => return Some(Err(e)) } + } + let result_id = self.value_gen.next(); + let fun_name = format!("{}.{}{}", cls_name, method, format!("/{}", arg_values.len())); + let fun_val = self.value_gen.next(); + if let Err(e) = self.emit_instruction(MirInstruction::Const { dst: fun_val, value: super::ConstValue::String(fun_name) }) { return Some(Err(e)); } + if let Err(e) = self.emit_instruction(MirInstruction::Call { dst: Some(result_id), func: fun_val, args: arg_values, effects: EffectMask::READ.add(Effect::ReadHeap) }) { return Some(Err(e)); } + Some(Ok(result_id)) + } // Build function call: name(args) pub(super) fn build_function_call( &mut self, @@ -33,77 +138,9 @@ impl super::MirBuilder { // Keep original args for special handling (math.*) let raw_args = args.clone(); - let dst = self.value_gen.next(); + if let Some(res) = self.try_handle_math_function(&name, raw_args) { return res; } - // Special-case: math.* as function-style (sin/cos/abs/min/max) - let is_math_func = matches!(name.as_str(), "sin" | "cos" | "abs" | "min" | "max"); - if is_math_func { - // Build numeric args directly for math.* to preserve f64 typing - let mut math_args: Vec = Vec::new(); - for a in raw_args.into_iter() { - match a { - ASTNode::New { - class, arguments, .. - } if class == "FloatBox" && arguments.len() == 1 => { - let v = self.build_expression(arguments[0].clone())?; - math_args.push(v); - } - ASTNode::New { - class, arguments, .. - } if class == "IntegerBox" && arguments.len() == 1 => { - let iv = self.build_expression(arguments[0].clone())?; - let fv = self.value_gen.next(); - self.emit_instruction(MirInstruction::TypeOp { - dst: fv, - op: TypeOpKind::Cast, - value: iv, - ty: MirType::Float, - })?; - math_args.push(fv); - } - ASTNode::Literal { - value: LiteralValue::Float(_), - .. - } => { - let v = self.build_expression(a)?; - math_args.push(v); - } - other => { - let v = self.build_expression(other)?; - math_args.push(v); - } - } - } - // new MathBox() - let math_recv = self.value_gen.next(); - self.emit_instruction(MirInstruction::NewBox { - dst: math_recv, - box_type: "MathBox".to_string(), - args: vec![], - })?; - self.value_origin_newbox - .insert(math_recv, "MathBox".to_string()); - // birth() - let birt_mid = slot_registry::resolve_slot_by_type_name("MathBox", "birth"); - self.emit_box_or_plugin_call( - None, - math_recv, - "birth".to_string(), - birt_mid, - vec![], - EffectMask::READ, - )?; - // call method - self.emit_box_or_plugin_call( - Some(dst), - math_recv, - name, - None, - math_args, - EffectMask::READ, - )?; - return Ok(dst); - } + let dst = self.value_gen.next(); // Default: call via fully-qualified function name string let mut arg_values = Vec::new(); @@ -151,130 +188,10 @@ impl super::MirBuilder { return Ok(dst); } } - // ExternCall: env.X.* pattern via field access (e.g., env.future.delay) - if let ASTNode::FieldAccess { - object: env_obj, - field: env_field, - .. - } = object.clone() - { - if let ASTNode::Variable { name: env_name, .. } = *env_obj { - if env_name == "env" { - let mut arg_values = Vec::new(); - for arg in &arguments { - arg_values.push(self.build_expression(arg.clone())?); - } - match (env_field.as_str(), method.as_str()) { - ("future", "delay") => { - let result_id = self.value_gen.next(); - self.emit_instruction(MirInstruction::ExternCall { - dst: Some(result_id), - iface_name: "env.future".to_string(), - method_name: "delay".to_string(), - args: arg_values, - effects: EffectMask::READ.add(Effect::Io), - })?; - return Ok(result_id); - } - ("task", "currentToken") => { - let result_id = self.value_gen.next(); - self.emit_instruction(MirInstruction::ExternCall { - dst: Some(result_id), - iface_name: "env.task".to_string(), - method_name: "currentToken".to_string(), - args: arg_values, - effects: EffectMask::READ, - })?; - return Ok(result_id); - } - ("task", "cancelCurrent") => { - self.emit_instruction(MirInstruction::ExternCall { - dst: None, - iface_name: "env.task".to_string(), - method_name: "cancelCurrent".to_string(), - args: arg_values, - effects: EffectMask::IO, - })?; - let void_id = self.value_gen.next(); - self.emit_instruction(MirInstruction::Const { - dst: void_id, - value: super::ConstValue::Void, - })?; - return Ok(void_id); - } - ("console", "log") => { - self.emit_instruction(MirInstruction::ExternCall { - dst: None, - iface_name: "env.console".to_string(), - method_name: "log".to_string(), - args: arg_values, - effects: EffectMask::IO, - })?; - let void_id = self.value_gen.next(); - self.emit_instruction(MirInstruction::Const { - dst: void_id, - value: super::ConstValue::Void, - })?; - return Ok(void_id); - } - ("console", "readLine") => { - let result_id = self.value_gen.next(); - self.emit_instruction(MirInstruction::ExternCall { - dst: Some(result_id), - iface_name: "env.console".to_string(), - method_name: "readLine".to_string(), - args: arg_values, - effects: EffectMask::IO, - })?; - return Ok(result_id); - } - ("canvas", m @ ("fillRect" | "fillText")) => { - self.emit_instruction(MirInstruction::ExternCall { - dst: None, - iface_name: "env.canvas".to_string(), - method_name: m.to_string(), - args: arg_values, - effects: EffectMask::IO, - })?; - let void_id = self.value_gen.next(); - self.emit_instruction(MirInstruction::Const { - dst: void_id, - value: super::ConstValue::Void, - })?; - return Ok(void_id); - } - _ => {} - } - } - } - } + if let Some(res) = self.try_handle_env_method(&object, &method, &arguments) { return res; } // If object is `me` within a static box, lower to direct Call: BoxName.method/N if let ASTNode::Me { .. } = object { - if let Some(cls_name) = self.current_static_box.clone() { - let mut arg_values: Vec = Vec::new(); - for a in &arguments { - arg_values.push(self.build_expression(a.clone())?); - } - let result_id = self.value_gen.next(); - let fun_name = format!( - "{}.{}{}", - cls_name, - method, - format!("/{}", arg_values.len()) - ); - let fun_val = self.value_gen.next(); - self.emit_instruction(MirInstruction::Const { - dst: fun_val, - value: super::ConstValue::String(fun_name), - })?; - self.emit_instruction(MirInstruction::Call { - dst: Some(result_id), - func: fun_val, - args: arg_values, - effects: EffectMask::READ.add(Effect::ReadHeap), - })?; - return Ok(result_id); - } + if let Some(res) = self.try_handle_me_direct_call(&method, &arguments) { return res; } } // Build the object expression (wrapper allows simple access if needed in future) let _mc = MethodCallExpr { object: Box::new(object.clone()), method: method.clone(), arguments: arguments.clone(), span: crate::ast::Span::unknown() }; diff --git a/src/runner/json_v0_bridge/lowering.rs b/src/runner/json_v0_bridge/lowering.rs index a9e6f9bf..52047379 100644 --- a/src/runner/json_v0_bridge/lowering.rs +++ b/src/runner/json_v0_bridge/lowering.rs @@ -4,6 +4,7 @@ use crate::mir::{ MirInstruction, MirModule, MirPrinter, MirType, ValueId, }; use std::collections::HashMap; +use std::collections::HashSet; #[derive(Clone, Copy)] pub(super) struct LoopContext { @@ -110,6 +111,34 @@ fn new_block(f: &mut MirFunction) -> BasicBlockId { id } +/// Merge two incoming values either by inserting Copy on predecessor edges +/// (no_phi mode) or by adding a Phi at the merge block head. +fn merge_values( + f: &mut MirFunction, + no_phi: bool, + merge_bb: BasicBlockId, + pred_a: BasicBlockId, + val_a: ValueId, + pred_b: BasicBlockId, + val_b: ValueId, +) -> ValueId { + if val_a == val_b { + return val_a; + } + let dst = f.next_value_id(); + if no_phi { + if let Some(bb) = f.get_block_mut(pred_a) { + bb.add_instruction(MirInstruction::Copy { dst, src: val_a }); + } + if let Some(bb) = f.get_block_mut(pred_b) { + bb.add_instruction(MirInstruction::Copy { dst, src: val_b }); + } + } else if let Some(bb) = f.get_block_mut(merge_bb) { + bb.insert_instruction_after_phis(MirInstruction::Phi { dst, inputs: vec![(pred_a, val_a), (pred_b, val_b)] }); + } + dst +} + fn lower_throw( env: &BridgeEnv, f: &mut MirFunction, @@ -802,7 +831,6 @@ fn lower_stmt_with_vars( } (else_bb, base_vars.clone()) }; - use std::collections::HashSet; let no_phi = env.mir_no_phi; let mut names: HashSet = base_vars.keys().cloned().collect(); for k in then_vars.keys() { @@ -817,72 +845,18 @@ fn lower_stmt_with_vars( let exists_base = base_vars.contains_key(&name); match (tv, ev, exists_base) { (Some(tval), Some(eval), _) => { - let merged = if tval == eval { - tval - } else { - let dst = f.next_value_id(); - if no_phi { - if let Some(bb) = f.get_block_mut(tend) { - bb.add_instruction(MirInstruction::Copy { dst, src: tval }); - } - if let Some(bb) = f.get_block_mut(else_end_pred) { - bb.add_instruction(MirInstruction::Copy { dst, src: eval }); - } - } else if let Some(bb) = f.get_block_mut(merge_bb) { - bb.insert_instruction_after_phis(MirInstruction::Phi { - dst, - inputs: vec![(tend, tval), (else_end_pred, eval)], - }); - } - dst - }; + let merged = merge_values(f, no_phi, merge_bb, tend, tval, else_end_pred, eval); vars.insert(name, merged); } (Some(tval), None, true) => { if let Some(&bval) = base_vars.get(&name) { - let merged = if tval == bval { - tval - } else { - let dst = f.next_value_id(); - if no_phi { - if let Some(bb) = f.get_block_mut(tend) { - bb.add_instruction(MirInstruction::Copy { dst, src: tval }); - } - if let Some(bb) = f.get_block_mut(else_end_pred) { - bb.add_instruction(MirInstruction::Copy { dst, src: bval }); - } - } else if let Some(bb) = f.get_block_mut(merge_bb) { - bb.insert_instruction_after_phis(MirInstruction::Phi { - dst, - inputs: vec![(tend, tval), (else_end_pred, bval)], - }); - } - dst - }; + let merged = merge_values(f, no_phi, merge_bb, tend, tval, else_end_pred, bval); vars.insert(name, merged); } } (None, Some(eval), true) => { if let Some(&bval) = base_vars.get(&name) { - let merged = if eval == bval { - eval - } else { - let dst = f.next_value_id(); - if no_phi { - if let Some(bb) = f.get_block_mut(tend) { - bb.add_instruction(MirInstruction::Copy { dst, src: bval }); - } - if let Some(bb) = f.get_block_mut(else_end_pred) { - bb.add_instruction(MirInstruction::Copy { dst, src: eval }); - } - } else if let Some(bb) = f.get_block_mut(merge_bb) { - bb.insert_instruction_after_phis(MirInstruction::Phi { - dst, - inputs: vec![(tend, bval), (else_end_pred, eval)], - }); - } - dst - }; + let merged = merge_values(f, no_phi, merge_bb, tend, bval, else_end_pred, eval); vars.insert(name, merged); } }