2025-09-03 01:37:38 +09:00
|
|
|
// Extracted call-related builders from builder.rs to keep files lean
|
2025-09-17 07:43:07 +09:00
|
|
|
use super::{Effect, EffectMask, FunctionSignature, MirInstruction, MirType, ValueId};
|
2025-09-17 08:11:47 +09:00
|
|
|
use crate::ast::{ASTNode, LiteralValue, MethodCallExpr};
|
2025-09-17 07:43:07 +09:00
|
|
|
use crate::mir::{slot_registry, TypeOpKind};
|
2025-09-03 01:37:38 +09:00
|
|
|
|
|
|
|
|
impl super::MirBuilder {
|
|
|
|
|
// Build function call: name(args)
|
2025-09-17 07:43:07 +09:00
|
|
|
pub(super) fn build_function_call(
|
|
|
|
|
&mut self,
|
|
|
|
|
name: String,
|
|
|
|
|
args: Vec<ASTNode>,
|
|
|
|
|
) -> Result<ValueId, String> {
|
2025-09-03 01:37:38 +09:00
|
|
|
// Minimal TypeOp wiring via function-style: isType(value, "Type"), asType(value, "Type")
|
|
|
|
|
if (name == "isType" || name == "asType") && args.len() == 2 {
|
|
|
|
|
if let Some(type_name) = Self::extract_string_literal(&args[1]) {
|
|
|
|
|
let val = self.build_expression(args[0].clone())?;
|
|
|
|
|
let ty = Self::parse_type_name_to_mir(&type_name);
|
|
|
|
|
let dst = self.value_gen.next();
|
2025-09-17 07:43:07 +09:00
|
|
|
let op = if name == "isType" {
|
|
|
|
|
TypeOpKind::Check
|
|
|
|
|
} else {
|
|
|
|
|
TypeOpKind::Cast
|
|
|
|
|
};
|
|
|
|
|
self.emit_instruction(MirInstruction::TypeOp {
|
|
|
|
|
dst,
|
|
|
|
|
op,
|
|
|
|
|
value: val,
|
|
|
|
|
ty,
|
|
|
|
|
})?;
|
2025-09-03 01:37:38 +09:00
|
|
|
return Ok(dst);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Keep original args for special handling (math.*)
|
|
|
|
|
let raw_args = args.clone();
|
|
|
|
|
|
|
|
|
|
let dst = self.value_gen.next();
|
|
|
|
|
|
|
|
|
|
// 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<ValueId> = Vec::new();
|
|
|
|
|
for a in raw_args.into_iter() {
|
|
|
|
|
match a {
|
2025-09-17 07:43:07 +09:00
|
|
|
ASTNode::New {
|
|
|
|
|
class, arguments, ..
|
|
|
|
|
} if class == "FloatBox" && arguments.len() == 1 => {
|
2025-09-03 01:37:38 +09:00
|
|
|
let v = self.build_expression(arguments[0].clone())?;
|
|
|
|
|
math_args.push(v);
|
|
|
|
|
}
|
2025-09-17 07:43:07 +09:00
|
|
|
ASTNode::New {
|
|
|
|
|
class, arguments, ..
|
|
|
|
|
} if class == "IntegerBox" && arguments.len() == 1 => {
|
2025-09-03 01:37:38 +09:00
|
|
|
let iv = self.build_expression(arguments[0].clone())?;
|
|
|
|
|
let fv = self.value_gen.next();
|
2025-09-17 07:43:07 +09:00
|
|
|
self.emit_instruction(MirInstruction::TypeOp {
|
|
|
|
|
dst: fv,
|
|
|
|
|
op: TypeOpKind::Cast,
|
|
|
|
|
value: iv,
|
|
|
|
|
ty: MirType::Float,
|
|
|
|
|
})?;
|
2025-09-03 01:37:38 +09:00
|
|
|
math_args.push(fv);
|
|
|
|
|
}
|
2025-09-17 07:43:07 +09:00
|
|
|
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);
|
2025-09-03 01:37:38 +09:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// new MathBox()
|
|
|
|
|
let math_recv = self.value_gen.next();
|
2025-09-17 07:43:07 +09:00
|
|
|
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());
|
2025-09-03 01:37:38 +09:00
|
|
|
// 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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Default: call via fully-qualified function name string
|
|
|
|
|
let mut arg_values = Vec::new();
|
2025-09-17 07:43:07 +09:00
|
|
|
for a in args {
|
|
|
|
|
arg_values.push(self.build_expression(a)?);
|
|
|
|
|
}
|
2025-09-03 01:37:38 +09:00
|
|
|
let fun_val = self.value_gen.next();
|
2025-09-17 07:43:07 +09:00
|
|
|
self.emit_instruction(MirInstruction::Const {
|
|
|
|
|
dst: fun_val,
|
|
|
|
|
value: super::ConstValue::String(name),
|
|
|
|
|
})?;
|
|
|
|
|
self.emit_instruction(MirInstruction::Call {
|
|
|
|
|
dst: Some(dst),
|
|
|
|
|
func: fun_val,
|
|
|
|
|
args: arg_values,
|
|
|
|
|
effects: EffectMask::READ.add(Effect::ReadHeap),
|
|
|
|
|
})?;
|
2025-09-03 01:37:38 +09:00
|
|
|
Ok(dst)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Build method call: object.method(arguments)
|
2025-09-17 07:43:07 +09:00
|
|
|
pub(super) fn build_method_call(
|
|
|
|
|
&mut self,
|
|
|
|
|
object: ASTNode,
|
|
|
|
|
method: String,
|
|
|
|
|
arguments: Vec<ASTNode>,
|
|
|
|
|
) -> Result<ValueId, String> {
|
2025-09-03 01:37:38 +09:00
|
|
|
// Minimal TypeOp wiring via method-style syntax: value.is("Type") / value.as("Type")
|
|
|
|
|
if (method == "is" || method == "as") && arguments.len() == 1 {
|
|
|
|
|
if let Some(type_name) = Self::extract_string_literal(&arguments[0]) {
|
|
|
|
|
let object_value = self.build_expression(object.clone())?;
|
|
|
|
|
let mir_ty = Self::parse_type_name_to_mir(&type_name);
|
|
|
|
|
let dst = self.value_gen.next();
|
2025-09-17 07:43:07 +09:00
|
|
|
let op = if method == "is" {
|
|
|
|
|
TypeOpKind::Check
|
|
|
|
|
} else {
|
|
|
|
|
TypeOpKind::Cast
|
|
|
|
|
};
|
|
|
|
|
self.emit_instruction(MirInstruction::TypeOp {
|
|
|
|
|
dst,
|
|
|
|
|
op,
|
|
|
|
|
value: object_value,
|
|
|
|
|
ty: mir_ty,
|
|
|
|
|
})?;
|
2025-09-03 01:37:38 +09:00
|
|
|
return Ok(dst);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// ExternCall: env.X.* pattern via field access (e.g., env.future.delay)
|
2025-09-17 07:43:07 +09:00
|
|
|
if let ASTNode::FieldAccess {
|
|
|
|
|
object: env_obj,
|
|
|
|
|
field: env_field,
|
|
|
|
|
..
|
|
|
|
|
} = object.clone()
|
|
|
|
|
{
|
2025-09-03 01:37:38 +09:00
|
|
|
if let ASTNode::Variable { name: env_name, .. } = *env_obj {
|
|
|
|
|
if env_name == "env" {
|
|
|
|
|
let mut arg_values = Vec::new();
|
2025-09-17 07:43:07 +09:00
|
|
|
for arg in &arguments {
|
|
|
|
|
arg_values.push(self.build_expression(arg.clone())?);
|
|
|
|
|
}
|
2025-09-03 01:37:38 +09:00
|
|
|
match (env_field.as_str(), method.as_str()) {
|
|
|
|
|
("future", "delay") => {
|
|
|
|
|
let result_id = self.value_gen.next();
|
|
|
|
|
self.emit_instruction(MirInstruction::ExternCall {
|
2025-09-17 07:43:07 +09:00
|
|
|
dst: Some(result_id),
|
|
|
|
|
iface_name: "env.future".to_string(),
|
|
|
|
|
method_name: "delay".to_string(),
|
|
|
|
|
args: arg_values,
|
2025-09-03 01:37:38 +09:00
|
|
|
effects: EffectMask::READ.add(Effect::Io),
|
|
|
|
|
})?;
|
|
|
|
|
return Ok(result_id);
|
|
|
|
|
}
|
|
|
|
|
("task", "currentToken") => {
|
|
|
|
|
let result_id = self.value_gen.next();
|
|
|
|
|
self.emit_instruction(MirInstruction::ExternCall {
|
2025-09-17 07:43:07 +09:00
|
|
|
dst: Some(result_id),
|
|
|
|
|
iface_name: "env.task".to_string(),
|
|
|
|
|
method_name: "currentToken".to_string(),
|
|
|
|
|
args: arg_values,
|
2025-09-03 01:37:38 +09:00
|
|
|
effects: EffectMask::READ,
|
|
|
|
|
})?;
|
|
|
|
|
return Ok(result_id);
|
|
|
|
|
}
|
|
|
|
|
("task", "cancelCurrent") => {
|
|
|
|
|
self.emit_instruction(MirInstruction::ExternCall {
|
2025-09-17 07:43:07 +09:00
|
|
|
dst: None,
|
|
|
|
|
iface_name: "env.task".to_string(),
|
|
|
|
|
method_name: "cancelCurrent".to_string(),
|
|
|
|
|
args: arg_values,
|
2025-09-03 01:37:38 +09:00
|
|
|
effects: EffectMask::IO,
|
|
|
|
|
})?;
|
|
|
|
|
let void_id = self.value_gen.next();
|
2025-09-17 07:43:07 +09:00
|
|
|
self.emit_instruction(MirInstruction::Const {
|
|
|
|
|
dst: void_id,
|
|
|
|
|
value: super::ConstValue::Void,
|
|
|
|
|
})?;
|
2025-09-03 01:37:38 +09:00
|
|
|
return Ok(void_id);
|
|
|
|
|
}
|
|
|
|
|
("console", "log") => {
|
|
|
|
|
self.emit_instruction(MirInstruction::ExternCall {
|
2025-09-17 07:43:07 +09:00
|
|
|
dst: None,
|
|
|
|
|
iface_name: "env.console".to_string(),
|
|
|
|
|
method_name: "log".to_string(),
|
|
|
|
|
args: arg_values,
|
|
|
|
|
effects: EffectMask::IO,
|
2025-09-03 01:37:38 +09:00
|
|
|
})?;
|
|
|
|
|
let void_id = self.value_gen.next();
|
2025-09-17 07:43:07 +09:00
|
|
|
self.emit_instruction(MirInstruction::Const {
|
|
|
|
|
dst: void_id,
|
|
|
|
|
value: super::ConstValue::Void,
|
|
|
|
|
})?;
|
2025-09-03 01:37:38 +09:00
|
|
|
return Ok(void_id);
|
|
|
|
|
}
|
|
|
|
|
("console", "readLine") => {
|
|
|
|
|
let result_id = self.value_gen.next();
|
|
|
|
|
self.emit_instruction(MirInstruction::ExternCall {
|
2025-09-17 07:43:07 +09:00
|
|
|
dst: Some(result_id),
|
|
|
|
|
iface_name: "env.console".to_string(),
|
|
|
|
|
method_name: "readLine".to_string(),
|
|
|
|
|
args: arg_values,
|
2025-09-03 01:37:38 +09:00
|
|
|
effects: EffectMask::IO,
|
|
|
|
|
})?;
|
|
|
|
|
return Ok(result_id);
|
|
|
|
|
}
|
|
|
|
|
("canvas", m @ ("fillRect" | "fillText")) => {
|
|
|
|
|
self.emit_instruction(MirInstruction::ExternCall {
|
2025-09-17 07:43:07 +09:00
|
|
|
dst: None,
|
|
|
|
|
iface_name: "env.canvas".to_string(),
|
|
|
|
|
method_name: m.to_string(),
|
|
|
|
|
args: arg_values,
|
|
|
|
|
effects: EffectMask::IO,
|
2025-09-03 01:37:38 +09:00
|
|
|
})?;
|
|
|
|
|
let void_id = self.value_gen.next();
|
2025-09-17 07:43:07 +09:00
|
|
|
self.emit_instruction(MirInstruction::Const {
|
|
|
|
|
dst: void_id,
|
|
|
|
|
value: super::ConstValue::Void,
|
|
|
|
|
})?;
|
2025-09-03 01:37:38 +09:00
|
|
|
return Ok(void_id);
|
|
|
|
|
}
|
|
|
|
|
_ => {}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// 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<ValueId> = Vec::new();
|
2025-09-17 07:43:07 +09:00
|
|
|
for a in &arguments {
|
|
|
|
|
arg_values.push(self.build_expression(a.clone())?);
|
|
|
|
|
}
|
2025-09-03 01:37:38 +09:00
|
|
|
let result_id = self.value_gen.next();
|
2025-09-17 07:43:07 +09:00
|
|
|
let fun_name = format!(
|
|
|
|
|
"{}.{}{}",
|
|
|
|
|
cls_name,
|
|
|
|
|
method,
|
|
|
|
|
format!("/{}", arg_values.len())
|
|
|
|
|
);
|
2025-09-03 01:37:38 +09:00
|
|
|
let fun_val = self.value_gen.next();
|
2025-09-17 07:43:07 +09:00
|
|
|
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),
|
|
|
|
|
})?;
|
2025-09-03 01:37:38 +09:00
|
|
|
return Ok(result_id);
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-09-17 08:11:47 +09:00
|
|
|
// 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() };
|
2025-09-03 01:37:38 +09:00
|
|
|
let object_value = self.build_expression(object.clone())?;
|
|
|
|
|
// Secondary interception for is/as
|
|
|
|
|
if (method == "is" || method == "as") && arguments.len() == 1 {
|
|
|
|
|
if let Some(type_name) = Self::extract_string_literal(&arguments[0]) {
|
|
|
|
|
let mir_ty = Self::parse_type_name_to_mir(&type_name);
|
|
|
|
|
let dst = self.value_gen.next();
|
2025-09-17 07:43:07 +09:00
|
|
|
let op = if method == "is" {
|
|
|
|
|
TypeOpKind::Check
|
|
|
|
|
} else {
|
|
|
|
|
TypeOpKind::Cast
|
|
|
|
|
};
|
|
|
|
|
self.emit_instruction(MirInstruction::TypeOp {
|
|
|
|
|
dst,
|
|
|
|
|
op,
|
|
|
|
|
value: object_value,
|
|
|
|
|
ty: mir_ty,
|
|
|
|
|
})?;
|
2025-09-03 01:37:38 +09:00
|
|
|
return Ok(dst);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Fallback: generic plugin invoke
|
|
|
|
|
let mut arg_values: Vec<ValueId> = Vec::new();
|
2025-09-17 07:43:07 +09:00
|
|
|
for a in &arguments {
|
|
|
|
|
arg_values.push(self.build_expression(a.clone())?);
|
|
|
|
|
}
|
2025-09-03 01:37:38 +09:00
|
|
|
let result_id = self.value_gen.next();
|
2025-09-17 07:43:07 +09:00
|
|
|
self.emit_box_or_plugin_call(
|
|
|
|
|
Some(result_id),
|
|
|
|
|
object_value,
|
|
|
|
|
method,
|
|
|
|
|
None,
|
|
|
|
|
arg_values,
|
|
|
|
|
EffectMask::READ.add(Effect::ReadHeap),
|
|
|
|
|
)?;
|
2025-09-03 01:37:38 +09:00
|
|
|
Ok(result_id)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Map a user-facing type name to MIR type
|
|
|
|
|
pub(super) fn parse_type_name_to_mir(name: &str) -> super::MirType {
|
|
|
|
|
match name {
|
|
|
|
|
"Integer" | "Int" | "I64" => super::MirType::Integer,
|
|
|
|
|
"Float" | "F64" => super::MirType::Float,
|
|
|
|
|
"Bool" | "Boolean" => super::MirType::Bool,
|
|
|
|
|
"String" => super::MirType::String,
|
|
|
|
|
"Void" | "Unit" => super::MirType::Void,
|
|
|
|
|
other => super::MirType::Box(other.to_string()),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Extract string literal from AST node if possible
|
|
|
|
|
pub(super) fn extract_string_literal(node: &ASTNode) -> Option<String> {
|
|
|
|
|
let mut cur = node;
|
|
|
|
|
loop {
|
|
|
|
|
match cur {
|
2025-09-17 07:43:07 +09:00
|
|
|
ASTNode::Literal {
|
|
|
|
|
value: LiteralValue::String(s),
|
|
|
|
|
..
|
|
|
|
|
} => return Some(s.clone()),
|
|
|
|
|
ASTNode::New {
|
|
|
|
|
class, arguments, ..
|
|
|
|
|
} if class == "StringBox" && arguments.len() == 1 => {
|
2025-09-03 01:37:38 +09:00
|
|
|
cur = &arguments[0];
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
_ => return None,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Build from expression: from Parent.method(arguments)
|
2025-09-17 07:43:07 +09:00
|
|
|
pub(super) fn build_from_expression(
|
|
|
|
|
&mut self,
|
|
|
|
|
parent: String,
|
|
|
|
|
method: String,
|
|
|
|
|
arguments: Vec<ASTNode>,
|
|
|
|
|
) -> Result<ValueId, String> {
|
2025-09-03 01:37:38 +09:00
|
|
|
let mut arg_values = Vec::new();
|
2025-09-17 07:43:07 +09:00
|
|
|
for arg in arguments {
|
|
|
|
|
arg_values.push(self.build_expression(arg)?);
|
|
|
|
|
}
|
2025-09-03 01:37:38 +09:00
|
|
|
let parent_value = self.value_gen.next();
|
2025-09-17 07:43:07 +09:00
|
|
|
self.emit_instruction(MirInstruction::Const {
|
|
|
|
|
dst: parent_value,
|
|
|
|
|
value: super::ConstValue::String(parent),
|
|
|
|
|
})?;
|
2025-09-03 01:37:38 +09:00
|
|
|
let result_id = self.value_gen.next();
|
2025-09-17 07:43:07 +09:00
|
|
|
self.emit_box_or_plugin_call(
|
|
|
|
|
Some(result_id),
|
|
|
|
|
parent_value,
|
|
|
|
|
method,
|
|
|
|
|
None,
|
|
|
|
|
arg_values,
|
|
|
|
|
EffectMask::READ.add(Effect::ReadHeap),
|
|
|
|
|
)?;
|
2025-09-03 01:37:38 +09:00
|
|
|
Ok(result_id)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Lower a box method into a standalone MIR function (with `me` parameter)
|
2025-09-17 07:43:07 +09:00
|
|
|
pub(super) fn lower_method_as_function(
|
|
|
|
|
&mut self,
|
|
|
|
|
func_name: String,
|
|
|
|
|
box_name: String,
|
|
|
|
|
params: Vec<String>,
|
|
|
|
|
body: Vec<ASTNode>,
|
|
|
|
|
) -> Result<(), String> {
|
|
|
|
|
let mut param_types = Vec::new();
|
|
|
|
|
param_types.push(MirType::Box(box_name.clone()));
|
|
|
|
|
for _ in ¶ms {
|
|
|
|
|
param_types.push(MirType::Unknown);
|
|
|
|
|
}
|
|
|
|
|
let mut returns_value = false;
|
|
|
|
|
for st in &body {
|
|
|
|
|
if let ASTNode::Return { value: Some(_), .. } = st {
|
|
|
|
|
returns_value = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
let ret_ty = if returns_value {
|
|
|
|
|
MirType::Unknown
|
|
|
|
|
} else {
|
|
|
|
|
MirType::Void
|
|
|
|
|
};
|
|
|
|
|
let signature = FunctionSignature {
|
|
|
|
|
name: func_name,
|
|
|
|
|
params: param_types,
|
|
|
|
|
return_type: ret_ty,
|
|
|
|
|
effects: EffectMask::READ.add(Effect::ReadHeap),
|
|
|
|
|
};
|
|
|
|
|
let entry = self.block_gen.next();
|
|
|
|
|
let function = super::MirFunction::new(signature, entry);
|
|
|
|
|
let saved_function = self.current_function.take();
|
|
|
|
|
let saved_block = self.current_block.take();
|
|
|
|
|
let saved_var_map = std::mem::take(&mut self.variable_map);
|
|
|
|
|
let saved_value_gen = self.value_gen.clone();
|
|
|
|
|
self.value_gen.reset();
|
|
|
|
|
self.current_function = Some(function);
|
|
|
|
|
self.current_block = Some(entry);
|
|
|
|
|
self.ensure_block_exists(entry)?;
|
|
|
|
|
if let Some(ref mut f) = self.current_function {
|
|
|
|
|
let me_id = self.value_gen.next();
|
|
|
|
|
f.params.push(me_id);
|
|
|
|
|
self.variable_map.insert("me".to_string(), me_id);
|
|
|
|
|
self.value_origin_newbox.insert(me_id, box_name.clone());
|
|
|
|
|
for p in ¶ms {
|
|
|
|
|
let pid = self.value_gen.next();
|
|
|
|
|
f.params.push(pid);
|
|
|
|
|
self.variable_map.insert(p.clone(), pid);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
let program_ast = ASTNode::Program {
|
|
|
|
|
statements: body,
|
|
|
|
|
span: crate::ast::Span::unknown(),
|
|
|
|
|
};
|
|
|
|
|
let _last = self.build_expression(program_ast)?;
|
|
|
|
|
if let Some(ref mut f) = self.current_function {
|
|
|
|
|
if let Some(block) = f.get_block(self.current_block.unwrap()) {
|
|
|
|
|
if !block.is_terminated() {
|
|
|
|
|
let void_val = self.value_gen.next();
|
|
|
|
|
self.emit_instruction(MirInstruction::Const {
|
|
|
|
|
dst: void_val,
|
|
|
|
|
value: super::ConstValue::Void,
|
|
|
|
|
})?;
|
|
|
|
|
self.emit_instruction(MirInstruction::Return {
|
|
|
|
|
value: Some(void_val),
|
|
|
|
|
})?;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
let finalized_function = self.current_function.take().unwrap();
|
|
|
|
|
if let Some(ref mut module) = self.current_module {
|
|
|
|
|
module.add_function(finalized_function);
|
|
|
|
|
}
|
|
|
|
|
self.current_function = saved_function;
|
|
|
|
|
self.current_block = saved_block;
|
|
|
|
|
self.variable_map = saved_var_map;
|
|
|
|
|
self.value_gen = saved_value_gen;
|
|
|
|
|
Ok(())
|
2025-09-03 01:37:38 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Lower a static method body into a standalone MIR function (no `me` parameter)
|
2025-09-17 07:43:07 +09:00
|
|
|
pub(super) fn lower_static_method_as_function(
|
|
|
|
|
&mut self,
|
|
|
|
|
func_name: String,
|
|
|
|
|
params: Vec<String>,
|
|
|
|
|
body: Vec<ASTNode>,
|
|
|
|
|
) -> Result<(), String> {
|
|
|
|
|
let mut param_types = Vec::new();
|
|
|
|
|
for _ in ¶ms {
|
|
|
|
|
param_types.push(MirType::Unknown);
|
|
|
|
|
}
|
|
|
|
|
let mut returns_value = false;
|
|
|
|
|
for st in &body {
|
|
|
|
|
if let ASTNode::Return { value: Some(_), .. } = st {
|
|
|
|
|
returns_value = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
let ret_ty = if returns_value {
|
|
|
|
|
MirType::Unknown
|
|
|
|
|
} else {
|
|
|
|
|
MirType::Void
|
|
|
|
|
};
|
|
|
|
|
let signature = FunctionSignature {
|
|
|
|
|
name: func_name,
|
|
|
|
|
params: param_types,
|
|
|
|
|
return_type: ret_ty,
|
|
|
|
|
effects: EffectMask::READ.add(Effect::ReadHeap),
|
|
|
|
|
};
|
|
|
|
|
let entry = self.block_gen.next();
|
|
|
|
|
let function = super::MirFunction::new(signature, entry);
|
|
|
|
|
let saved_function = self.current_function.take();
|
|
|
|
|
let saved_block = self.current_block.take();
|
|
|
|
|
let saved_var_map = std::mem::take(&mut self.variable_map);
|
|
|
|
|
let saved_value_gen = self.value_gen.clone();
|
|
|
|
|
self.value_gen.reset();
|
|
|
|
|
self.current_function = Some(function);
|
|
|
|
|
self.current_block = Some(entry);
|
|
|
|
|
self.ensure_block_exists(entry)?;
|
|
|
|
|
if let Some(ref mut f) = self.current_function {
|
|
|
|
|
for p in ¶ms {
|
|
|
|
|
let pid = self.value_gen.next();
|
|
|
|
|
f.params.push(pid);
|
|
|
|
|
self.variable_map.insert(p.clone(), pid);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
let program_ast = ASTNode::Program {
|
|
|
|
|
statements: body,
|
|
|
|
|
span: crate::ast::Span::unknown(),
|
|
|
|
|
};
|
|
|
|
|
let _last = self.build_expression(program_ast)?;
|
|
|
|
|
if let Some(ref mut f) = self.current_function {
|
|
|
|
|
if let Some(block) = f.get_block(self.current_block.unwrap()) {
|
|
|
|
|
if !block.is_terminated() {
|
|
|
|
|
let void_val = self.value_gen.next();
|
|
|
|
|
self.emit_instruction(MirInstruction::Const {
|
|
|
|
|
dst: void_val,
|
|
|
|
|
value: super::ConstValue::Void,
|
|
|
|
|
})?;
|
|
|
|
|
self.emit_instruction(MirInstruction::Return {
|
|
|
|
|
value: Some(void_val),
|
|
|
|
|
})?;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
let finalized = self.current_function.take().unwrap();
|
|
|
|
|
if let Some(ref mut module) = self.current_module {
|
|
|
|
|
module.add_function(finalized);
|
|
|
|
|
}
|
|
|
|
|
self.current_function = saved_function;
|
|
|
|
|
self.current_block = saved_block;
|
|
|
|
|
self.variable_map = saved_var_map;
|
|
|
|
|
self.value_gen = saved_value_gen;
|
|
|
|
|
Ok(())
|
2025-09-03 01:37:38 +09:00
|
|
|
}
|
|
|
|
|
}
|