2025-09-16 01:54:00 +09:00
|
|
|
use super::phi::extract_assigned_var;
|
2025-09-17 07:43:07 +09:00
|
|
|
use super::{ConstValue, Effect, EffectMask, MirInstruction, ValueId};
|
2025-09-17 07:54:45 +09:00
|
|
|
use crate::ast::{ASTNode, CallExpr};
|
2025-09-17 07:43:07 +09:00
|
|
|
use crate::mir::loop_builder::LoopBuilder;
|
|
|
|
|
use crate::mir::TypeOpKind;
|
2025-09-03 01:37:38 +09:00
|
|
|
|
|
|
|
|
impl super::MirBuilder {
|
2025-09-03 05:04:56 +09:00
|
|
|
// Print statement: env.console.log(value) with early TypeOp handling
|
2025-09-03 01:37:38 +09:00
|
|
|
pub(super) fn build_print_statement(&mut self, expression: ASTNode) -> Result<ValueId, String> {
|
2025-09-03 05:04:56 +09:00
|
|
|
super::utils::builder_debug_log("enter build_print_statement");
|
2025-09-17 07:54:45 +09:00
|
|
|
// Prefer wrapper for simple function-call pattern (non-breaking refactor)
|
|
|
|
|
if let Ok(call) = CallExpr::try_from(expression.clone()) {
|
|
|
|
|
if (call.name == "isType" || call.name == "asType") && call.arguments.len() == 2 {
|
|
|
|
|
super::utils::builder_debug_log("pattern: print(FunctionCall isType|asType) [via wrapper]");
|
|
|
|
|
if let Some(type_name) = super::MirBuilder::extract_string_literal(&call.arguments[1]) {
|
|
|
|
|
super::utils::builder_debug_log(&format!("extract_string_literal OK: {}", type_name));
|
|
|
|
|
let val = self.build_expression(call.arguments[0].clone())?;
|
|
|
|
|
let ty = super::MirBuilder::parse_type_name_to_mir(&type_name);
|
|
|
|
|
let dst = self.value_gen.next();
|
|
|
|
|
let op = if call.name == "isType" { TypeOpKind::Check } else { TypeOpKind::Cast };
|
|
|
|
|
super::utils::builder_debug_log(&format!("emit TypeOp {:?} value={} dst= {}", op, val, dst));
|
|
|
|
|
self.emit_instruction(MirInstruction::TypeOp { dst, op, value: val, ty })?;
|
|
|
|
|
self.emit_instruction(MirInstruction::ExternCall {
|
|
|
|
|
dst: None,
|
|
|
|
|
iface_name: "env.console".to_string(),
|
|
|
|
|
method_name: "log".to_string(),
|
|
|
|
|
args: vec![dst],
|
|
|
|
|
effects: EffectMask::PURE.add(Effect::Io),
|
|
|
|
|
})?;
|
|
|
|
|
return Ok(dst);
|
|
|
|
|
} else {
|
|
|
|
|
super::utils::builder_debug_log("extract_string_literal FAIL [via wrapper]");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-03 05:04:56 +09:00
|
|
|
match &expression {
|
|
|
|
|
// print(isType(val, "Type")) / print(asType(...))
|
2025-09-17 07:43:07 +09:00
|
|
|
ASTNode::FunctionCall {
|
|
|
|
|
name, arguments, ..
|
|
|
|
|
} if (name == "isType" || name == "asType") && arguments.len() == 2 => {
|
2025-09-03 05:04:56 +09:00
|
|
|
super::utils::builder_debug_log("pattern: print(FunctionCall isType|asType)");
|
|
|
|
|
if let Some(type_name) = super::MirBuilder::extract_string_literal(&arguments[1]) {
|
2025-09-17 07:43:07 +09:00
|
|
|
super::utils::builder_debug_log(&format!(
|
|
|
|
|
"extract_string_literal OK: {}",
|
|
|
|
|
type_name
|
|
|
|
|
));
|
2025-09-03 05:04:56 +09:00
|
|
|
let val = self.build_expression(arguments[0].clone())?;
|
|
|
|
|
let ty = super::MirBuilder::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
|
|
|
|
|
};
|
|
|
|
|
super::utils::builder_debug_log(&format!(
|
|
|
|
|
"emit TypeOp {:?} value={} dst= {}",
|
|
|
|
|
op, val, dst
|
|
|
|
|
));
|
|
|
|
|
self.emit_instruction(MirInstruction::TypeOp {
|
|
|
|
|
dst,
|
|
|
|
|
op,
|
|
|
|
|
value: val,
|
|
|
|
|
ty,
|
|
|
|
|
})?;
|
2025-09-03 05:04:56 +09:00
|
|
|
self.emit_instruction(MirInstruction::ExternCall {
|
|
|
|
|
dst: None,
|
|
|
|
|
iface_name: "env.console".to_string(),
|
|
|
|
|
method_name: "log".to_string(),
|
|
|
|
|
args: vec![dst],
|
|
|
|
|
effects: EffectMask::PURE.add(Effect::Io),
|
|
|
|
|
})?;
|
|
|
|
|
return Ok(dst);
|
|
|
|
|
} else {
|
|
|
|
|
super::utils::builder_debug_log("extract_string_literal FAIL");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// print(obj.is("Type")) / print(obj.as("Type"))
|
2025-09-17 07:43:07 +09:00
|
|
|
ASTNode::MethodCall {
|
|
|
|
|
object,
|
|
|
|
|
method,
|
|
|
|
|
arguments,
|
|
|
|
|
..
|
|
|
|
|
} if (method == "is" || method == "as") && arguments.len() == 1 => {
|
2025-09-03 05:04:56 +09:00
|
|
|
super::utils::builder_debug_log("pattern: print(MethodCall is|as)");
|
|
|
|
|
if let Some(type_name) = super::MirBuilder::extract_string_literal(&arguments[0]) {
|
2025-09-17 07:43:07 +09:00
|
|
|
super::utils::builder_debug_log(&format!(
|
|
|
|
|
"extract_string_literal OK: {}",
|
|
|
|
|
type_name
|
|
|
|
|
));
|
2025-09-03 05:04:56 +09:00
|
|
|
let obj_val = self.build_expression(*object.clone())?;
|
|
|
|
|
let ty = super::MirBuilder::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
|
|
|
|
|
};
|
|
|
|
|
super::utils::builder_debug_log(&format!(
|
|
|
|
|
"emit TypeOp {:?} obj={} dst= {}",
|
|
|
|
|
op, obj_val, dst
|
|
|
|
|
));
|
|
|
|
|
self.emit_instruction(MirInstruction::TypeOp {
|
|
|
|
|
dst,
|
|
|
|
|
op,
|
|
|
|
|
value: obj_val,
|
|
|
|
|
ty,
|
|
|
|
|
})?;
|
2025-09-03 05:04:56 +09:00
|
|
|
self.emit_instruction(MirInstruction::ExternCall {
|
|
|
|
|
dst: None,
|
|
|
|
|
iface_name: "env.console".to_string(),
|
|
|
|
|
method_name: "log".to_string(),
|
|
|
|
|
args: vec![dst],
|
|
|
|
|
effects: EffectMask::PURE.add(Effect::Io),
|
|
|
|
|
})?;
|
|
|
|
|
return Ok(dst);
|
|
|
|
|
} else {
|
|
|
|
|
super::utils::builder_debug_log("extract_string_literal FAIL");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
_ => {}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let value = self.build_expression(expression)?;
|
|
|
|
|
super::utils::builder_debug_log(&format!("fallback print value={}", value));
|
|
|
|
|
self.emit_instruction(MirInstruction::ExternCall {
|
|
|
|
|
dst: None,
|
|
|
|
|
iface_name: "env.console".to_string(),
|
|
|
|
|
method_name: "log".to_string(),
|
|
|
|
|
args: vec![value],
|
|
|
|
|
effects: EffectMask::PURE.add(Effect::Io),
|
|
|
|
|
})?;
|
|
|
|
|
Ok(value)
|
2025-09-03 01:37:38 +09:00
|
|
|
}
|
2025-09-03 05:04:56 +09:00
|
|
|
|
|
|
|
|
// Block: sequentially build statements and return last value or Void
|
2025-09-03 01:37:38 +09:00
|
|
|
pub(super) fn build_block(&mut self, statements: Vec<ASTNode>) -> Result<ValueId, String> {
|
2025-09-03 05:04:56 +09:00
|
|
|
let mut last_value = None;
|
2025-09-06 06:24:08 +09:00
|
|
|
for statement in statements {
|
|
|
|
|
last_value = Some(self.build_expression(statement)?);
|
|
|
|
|
// If the current block was terminated by this statement (e.g., return/throw),
|
|
|
|
|
// do not emit any further instructions for this block.
|
|
|
|
|
if self.is_current_block_terminated() {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-09-03 05:04:56 +09:00
|
|
|
Ok(last_value.unwrap_or_else(|| {
|
|
|
|
|
let void_val = self.value_gen.next();
|
2025-09-17 07:43:07 +09:00
|
|
|
self.emit_instruction(MirInstruction::Const {
|
|
|
|
|
dst: void_val,
|
|
|
|
|
value: ConstValue::Void,
|
|
|
|
|
})
|
|
|
|
|
.unwrap();
|
2025-09-03 05:04:56 +09:00
|
|
|
void_val
|
|
|
|
|
}))
|
2025-09-03 01:37:38 +09:00
|
|
|
}
|
2025-09-03 05:04:56 +09:00
|
|
|
|
|
|
|
|
// If: lower to Branch + Phi, bind reassigned var name if identical
|
|
|
|
|
pub(super) fn build_if_statement(
|
|
|
|
|
&mut self,
|
|
|
|
|
condition: ASTNode,
|
|
|
|
|
then_branch: ASTNode,
|
|
|
|
|
else_branch: Option<ASTNode>,
|
|
|
|
|
) -> Result<ValueId, String> {
|
|
|
|
|
let condition_val = self.build_expression(condition)?;
|
|
|
|
|
let then_block = self.block_gen.next();
|
|
|
|
|
let else_block = self.block_gen.next();
|
|
|
|
|
let merge_block = self.block_gen.next();
|
2025-09-17 07:43:07 +09:00
|
|
|
self.emit_instruction(MirInstruction::Branch {
|
|
|
|
|
condition: condition_val,
|
|
|
|
|
then_bb: then_block,
|
|
|
|
|
else_bb: else_block,
|
|
|
|
|
})?;
|
2025-09-03 05:04:56 +09:00
|
|
|
|
2025-09-14 19:16:32 +09:00
|
|
|
// Snapshot variable map before entering branches to avoid cross-branch pollution
|
|
|
|
|
let pre_if_var_map = self.variable_map.clone();
|
2025-09-06 06:24:08 +09:00
|
|
|
// Pre-analysis: detect then-branch assigned var and capture its pre-if value
|
|
|
|
|
let assigned_then_pre = extract_assigned_var(&then_branch);
|
|
|
|
|
let pre_then_var_value: Option<ValueId> = assigned_then_pre
|
|
|
|
|
.as_ref()
|
2025-09-14 19:16:32 +09:00
|
|
|
.and_then(|name| pre_if_var_map.get(name).copied());
|
2025-09-06 06:24:08 +09:00
|
|
|
|
2025-09-03 05:04:56 +09:00
|
|
|
// then
|
|
|
|
|
self.current_block = Some(then_block);
|
|
|
|
|
self.ensure_block_exists(then_block)?;
|
|
|
|
|
let then_ast_for_analysis = then_branch.clone();
|
2025-09-14 19:16:32 +09:00
|
|
|
// Build then with a clean snapshot of pre-if variables
|
|
|
|
|
self.variable_map = pre_if_var_map.clone();
|
|
|
|
|
let then_value_raw = self.build_expression(then_branch)?;
|
2025-09-17 16:11:01 +09:00
|
|
|
let then_exit_block = Self::current_block(self)?;
|
2025-09-14 19:16:32 +09:00
|
|
|
let then_var_map_end = self.variable_map.clone();
|
2025-09-17 07:43:07 +09:00
|
|
|
if !self.is_current_block_terminated() {
|
|
|
|
|
self.emit_instruction(MirInstruction::Jump {
|
|
|
|
|
target: merge_block,
|
|
|
|
|
})?;
|
|
|
|
|
}
|
2025-09-03 05:04:56 +09:00
|
|
|
|
|
|
|
|
// else
|
|
|
|
|
self.current_block = Some(else_block);
|
|
|
|
|
self.ensure_block_exists(else_block)?;
|
2025-09-14 19:16:32 +09:00
|
|
|
// Build else with a clean snapshot of pre-if variables
|
2025-09-18 13:35:38 +09:00
|
|
|
let (else_value_raw, else_ast_for_analysis, else_var_map_end_opt) =
|
2025-09-17 07:43:07 +09:00
|
|
|
if let Some(else_ast) = else_branch {
|
|
|
|
|
self.variable_map = pre_if_var_map.clone();
|
|
|
|
|
let val = self.build_expression(else_ast.clone())?;
|
|
|
|
|
(val, Some(else_ast), Some(self.variable_map.clone()))
|
|
|
|
|
} else {
|
|
|
|
|
let void_val = self.value_gen.next();
|
|
|
|
|
self.emit_instruction(MirInstruction::Const {
|
|
|
|
|
dst: void_val,
|
|
|
|
|
value: ConstValue::Void,
|
|
|
|
|
})?;
|
|
|
|
|
(void_val, None, None)
|
|
|
|
|
};
|
2025-09-17 16:11:01 +09:00
|
|
|
let else_exit_block = Self::current_block(self)?;
|
2025-09-17 07:43:07 +09:00
|
|
|
if !self.is_current_block_terminated() {
|
|
|
|
|
self.emit_instruction(MirInstruction::Jump {
|
|
|
|
|
target: merge_block,
|
|
|
|
|
})?;
|
|
|
|
|
}
|
2025-09-03 05:04:56 +09:00
|
|
|
|
|
|
|
|
// merge + phi
|
|
|
|
|
self.current_block = Some(merge_block);
|
|
|
|
|
self.ensure_block_exists(merge_block)?;
|
2025-09-16 01:54:00 +09:00
|
|
|
let result_val = self.normalize_if_else_phi(
|
|
|
|
|
then_block,
|
|
|
|
|
else_block,
|
2025-09-17 16:11:01 +09:00
|
|
|
Some(then_exit_block),
|
|
|
|
|
Some(else_exit_block),
|
2025-09-16 01:54:00 +09:00
|
|
|
then_value_raw,
|
|
|
|
|
else_value_raw,
|
|
|
|
|
&pre_if_var_map,
|
|
|
|
|
&then_ast_for_analysis,
|
|
|
|
|
&else_ast_for_analysis,
|
|
|
|
|
&then_var_map_end,
|
|
|
|
|
&else_var_map_end_opt,
|
|
|
|
|
pre_then_var_value,
|
|
|
|
|
)?;
|
2025-09-06 06:24:08 +09:00
|
|
|
|
2025-09-03 05:04:56 +09:00
|
|
|
Ok(result_val)
|
2025-09-03 01:37:38 +09:00
|
|
|
}
|
2025-09-03 05:04:56 +09:00
|
|
|
|
|
|
|
|
// Loop: delegate to LoopBuilder
|
2025-09-17 07:43:07 +09:00
|
|
|
pub(super) fn build_loop_statement(
|
|
|
|
|
&mut self,
|
|
|
|
|
condition: ASTNode,
|
|
|
|
|
body: Vec<ASTNode>,
|
|
|
|
|
) -> Result<ValueId, String> {
|
2025-09-03 05:04:56 +09:00
|
|
|
let mut loop_builder = LoopBuilder::new(self);
|
|
|
|
|
loop_builder.build_loop(condition, body)
|
2025-09-03 01:37:38 +09:00
|
|
|
}
|
2025-09-03 05:04:56 +09:00
|
|
|
|
|
|
|
|
// Try/Catch/Finally lowering with basic Extern semantics when disabled
|
|
|
|
|
pub(super) fn build_try_catch_statement(
|
|
|
|
|
&mut self,
|
|
|
|
|
try_body: Vec<ASTNode>,
|
|
|
|
|
catch_clauses: Vec<crate::ast::CatchClause>,
|
|
|
|
|
finally_body: Option<Vec<ASTNode>>,
|
|
|
|
|
) -> Result<ValueId, String> {
|
2025-09-17 07:43:07 +09:00
|
|
|
if std::env::var("NYASH_BUILDER_DISABLE_TRYCATCH")
|
|
|
|
|
.ok()
|
|
|
|
|
.as_deref()
|
|
|
|
|
== Some("1")
|
|
|
|
|
{
|
|
|
|
|
let try_ast = ASTNode::Program {
|
|
|
|
|
statements: try_body,
|
|
|
|
|
span: crate::ast::Span::unknown(),
|
|
|
|
|
};
|
2025-09-03 05:04:56 +09:00
|
|
|
let result = self.build_expression(try_ast)?;
|
|
|
|
|
return Ok(result);
|
|
|
|
|
}
|
|
|
|
|
let try_block = self.block_gen.next();
|
|
|
|
|
let catch_block = self.block_gen.next();
|
2025-09-17 07:43:07 +09:00
|
|
|
let finally_block = if finally_body.is_some() {
|
|
|
|
|
Some(self.block_gen.next())
|
|
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
};
|
2025-09-03 05:04:56 +09:00
|
|
|
let exit_block = self.block_gen.next();
|
|
|
|
|
|
|
|
|
|
if let Some(catch_clause) = catch_clauses.first() {
|
|
|
|
|
if std::env::var("NYASH_DEBUG_TRYCATCH").ok().as_deref() == Some("1") {
|
2025-09-17 07:43:07 +09:00
|
|
|
eprintln!(
|
|
|
|
|
"[BUILDER] Emitting catch handler for {:?}",
|
|
|
|
|
catch_clause.exception_type
|
|
|
|
|
);
|
2025-09-03 05:04:56 +09:00
|
|
|
}
|
|
|
|
|
let exception_value = self.value_gen.next();
|
2025-09-17 07:43:07 +09:00
|
|
|
self.emit_instruction(MirInstruction::Catch {
|
|
|
|
|
exception_type: catch_clause.exception_type.clone(),
|
|
|
|
|
exception_value,
|
|
|
|
|
handler_bb: catch_block,
|
|
|
|
|
})?;
|
2025-09-03 05:04:56 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
self.emit_instruction(MirInstruction::Jump { target: try_block })?;
|
|
|
|
|
self.start_new_block(try_block)?;
|
2025-09-17 07:43:07 +09:00
|
|
|
let try_ast = ASTNode::Program {
|
|
|
|
|
statements: try_body,
|
|
|
|
|
span: crate::ast::Span::unknown(),
|
|
|
|
|
};
|
2025-09-03 05:04:56 +09:00
|
|
|
let _try_result = self.build_expression(try_ast)?;
|
2025-09-17 07:43:07 +09:00
|
|
|
if !self.is_current_block_terminated() {
|
|
|
|
|
let next_target = finally_block.unwrap_or(exit_block);
|
|
|
|
|
self.emit_instruction(MirInstruction::Jump {
|
|
|
|
|
target: next_target,
|
|
|
|
|
})?;
|
|
|
|
|
}
|
2025-09-03 05:04:56 +09:00
|
|
|
|
|
|
|
|
self.start_new_block(catch_block)?;
|
2025-09-17 07:43:07 +09:00
|
|
|
if std::env::var("NYASH_DEBUG_TRYCATCH").ok().as_deref() == Some("1") {
|
|
|
|
|
eprintln!("[BUILDER] Enter catch block {:?}", catch_block);
|
|
|
|
|
}
|
2025-09-03 05:04:56 +09:00
|
|
|
if let Some(catch_clause) = catch_clauses.first() {
|
2025-09-17 07:43:07 +09:00
|
|
|
if std::env::var("NYASH_DEBUG_TRYCATCH").ok().as_deref() == Some("1") {
|
|
|
|
|
eprintln!(
|
|
|
|
|
"[BUILDER] Emitting catch handler for {:?}",
|
|
|
|
|
catch_clause.exception_type
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
let catch_ast = ASTNode::Program {
|
|
|
|
|
statements: catch_clause.body.clone(),
|
|
|
|
|
span: crate::ast::Span::unknown(),
|
|
|
|
|
};
|
2025-09-03 05:04:56 +09:00
|
|
|
self.build_expression(catch_ast)?;
|
|
|
|
|
}
|
2025-09-17 07:43:07 +09:00
|
|
|
if !self.is_current_block_terminated() {
|
|
|
|
|
let next_target = finally_block.unwrap_or(exit_block);
|
|
|
|
|
self.emit_instruction(MirInstruction::Jump {
|
|
|
|
|
target: next_target,
|
|
|
|
|
})?;
|
|
|
|
|
}
|
2025-09-03 05:04:56 +09:00
|
|
|
|
|
|
|
|
if let (Some(finally_block_id), Some(finally_statements)) = (finally_block, finally_body) {
|
|
|
|
|
self.start_new_block(finally_block_id)?;
|
2025-09-17 07:43:07 +09:00
|
|
|
let finally_ast = ASTNode::Program {
|
|
|
|
|
statements: finally_statements,
|
|
|
|
|
span: crate::ast::Span::unknown(),
|
|
|
|
|
};
|
2025-09-03 05:04:56 +09:00
|
|
|
self.build_expression(finally_ast)?;
|
|
|
|
|
self.emit_instruction(MirInstruction::Jump { target: exit_block })?;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
self.start_new_block(exit_block)?;
|
|
|
|
|
let result = self.value_gen.next();
|
2025-09-17 07:43:07 +09:00
|
|
|
self.emit_instruction(MirInstruction::Const {
|
|
|
|
|
dst: result,
|
|
|
|
|
value: ConstValue::Void,
|
|
|
|
|
})?;
|
2025-09-03 05:04:56 +09:00
|
|
|
Ok(result)
|
2025-09-03 01:37:38 +09:00
|
|
|
}
|
2025-09-03 05:04:56 +09:00
|
|
|
|
|
|
|
|
// Throw: emit Throw or fallback to env.debug.trace when disabled
|
2025-09-03 01:37:38 +09:00
|
|
|
pub(super) fn build_throw_statement(&mut self, expression: ASTNode) -> Result<ValueId, String> {
|
2025-09-03 05:04:56 +09:00
|
|
|
if std::env::var("NYASH_BUILDER_DISABLE_THROW").ok().as_deref() == Some("1") {
|
|
|
|
|
let v = self.build_expression(expression)?;
|
|
|
|
|
self.emit_instruction(MirInstruction::ExternCall {
|
|
|
|
|
dst: None,
|
|
|
|
|
iface_name: "env.debug".to_string(),
|
|
|
|
|
method_name: "trace".to_string(),
|
|
|
|
|
args: vec![v],
|
|
|
|
|
effects: EffectMask::PURE.add(Effect::Debug),
|
|
|
|
|
})?;
|
|
|
|
|
return Ok(v);
|
|
|
|
|
}
|
|
|
|
|
let exception_value = self.build_expression(expression)?;
|
2025-09-17 07:43:07 +09:00
|
|
|
self.emit_instruction(MirInstruction::Throw {
|
|
|
|
|
exception: exception_value,
|
|
|
|
|
effects: EffectMask::PANIC,
|
|
|
|
|
})?;
|
2025-09-03 05:04:56 +09:00
|
|
|
Ok(exception_value)
|
2025-09-03 01:37:38 +09:00
|
|
|
}
|
2025-09-03 05:04:56 +09:00
|
|
|
|
|
|
|
|
// Local declarations with optional initializers
|
|
|
|
|
pub(super) fn build_local_statement(
|
|
|
|
|
&mut self,
|
|
|
|
|
variables: Vec<String>,
|
|
|
|
|
initial_values: Vec<Option<Box<ASTNode>>>,
|
|
|
|
|
) -> Result<ValueId, String> {
|
|
|
|
|
let mut last_value = None;
|
|
|
|
|
for (i, var_name) in variables.iter().enumerate() {
|
|
|
|
|
let value_id = if i < initial_values.len() && initial_values[i].is_some() {
|
|
|
|
|
let init_expr = initial_values[i].as_ref().unwrap();
|
|
|
|
|
self.build_expression(*init_expr.clone())?
|
|
|
|
|
} else {
|
|
|
|
|
self.value_gen.next()
|
|
|
|
|
};
|
|
|
|
|
self.variable_map.insert(var_name.clone(), value_id);
|
|
|
|
|
last_value = Some(value_id);
|
|
|
|
|
}
|
|
|
|
|
Ok(last_value.unwrap_or_else(|| self.value_gen.next()))
|
2025-09-03 01:37:38 +09:00
|
|
|
}
|
2025-09-03 05:04:56 +09:00
|
|
|
|
|
|
|
|
// Return statement
|
2025-09-17 07:43:07 +09:00
|
|
|
pub(super) fn build_return_statement(
|
|
|
|
|
&mut self,
|
|
|
|
|
value: Option<Box<ASTNode>>,
|
|
|
|
|
) -> Result<ValueId, String> {
|
2025-09-03 05:04:56 +09:00
|
|
|
let return_value = if let Some(expr) = value {
|
|
|
|
|
self.build_expression(*expr)?
|
|
|
|
|
} else {
|
|
|
|
|
let void_dst = self.value_gen.next();
|
2025-09-17 07:43:07 +09:00
|
|
|
self.emit_instruction(MirInstruction::Const {
|
|
|
|
|
dst: void_dst,
|
|
|
|
|
value: ConstValue::Void,
|
|
|
|
|
})?;
|
2025-09-03 05:04:56 +09:00
|
|
|
void_dst
|
|
|
|
|
};
|
2025-09-17 07:43:07 +09:00
|
|
|
self.emit_instruction(MirInstruction::Return {
|
|
|
|
|
value: Some(return_value),
|
|
|
|
|
})?;
|
2025-09-03 05:04:56 +09:00
|
|
|
Ok(return_value)
|
2025-09-03 01:37:38 +09:00
|
|
|
}
|
2025-09-03 05:04:56 +09:00
|
|
|
|
|
|
|
|
// Nowait: prefer env.future.spawn_instance if method call; else FutureNew
|
2025-09-17 07:43:07 +09:00
|
|
|
pub(super) fn build_nowait_statement(
|
|
|
|
|
&mut self,
|
|
|
|
|
variable: String,
|
|
|
|
|
expression: ASTNode,
|
|
|
|
|
) -> Result<ValueId, String> {
|
|
|
|
|
if let ASTNode::MethodCall {
|
|
|
|
|
object,
|
|
|
|
|
method,
|
|
|
|
|
arguments,
|
|
|
|
|
..
|
|
|
|
|
} = expression.clone()
|
|
|
|
|
{
|
2025-09-03 05:04:56 +09:00
|
|
|
let recv_val = self.build_expression(*object)?;
|
|
|
|
|
let mname_id = self.value_gen.next();
|
2025-09-17 07:43:07 +09:00
|
|
|
self.emit_instruction(MirInstruction::Const {
|
|
|
|
|
dst: mname_id,
|
|
|
|
|
value: super::ConstValue::String(method.clone()),
|
|
|
|
|
})?;
|
2025-09-03 05:04:56 +09:00
|
|
|
let mut arg_vals: Vec<ValueId> = Vec::with_capacity(2 + arguments.len());
|
|
|
|
|
arg_vals.push(recv_val);
|
|
|
|
|
arg_vals.push(mname_id);
|
2025-09-17 07:43:07 +09:00
|
|
|
for a in arguments.into_iter() {
|
|
|
|
|
arg_vals.push(self.build_expression(a)?);
|
|
|
|
|
}
|
2025-09-03 05:04:56 +09:00
|
|
|
let future_id = self.value_gen.next();
|
|
|
|
|
self.emit_instruction(MirInstruction::ExternCall {
|
|
|
|
|
dst: Some(future_id),
|
|
|
|
|
iface_name: "env.future".to_string(),
|
|
|
|
|
method_name: "spawn_instance".to_string(),
|
|
|
|
|
args: arg_vals,
|
|
|
|
|
effects: crate::mir::effect::EffectMask::PURE.add(crate::mir::effect::Effect::Io),
|
|
|
|
|
})?;
|
|
|
|
|
self.variable_map.insert(variable.clone(), future_id);
|
|
|
|
|
return Ok(future_id);
|
|
|
|
|
}
|
|
|
|
|
let expression_value = self.build_expression(expression)?;
|
|
|
|
|
let future_id = self.value_gen.next();
|
2025-09-17 07:43:07 +09:00
|
|
|
self.emit_instruction(MirInstruction::FutureNew {
|
|
|
|
|
dst: future_id,
|
|
|
|
|
value: expression_value,
|
|
|
|
|
})?;
|
2025-09-03 05:04:56 +09:00
|
|
|
self.variable_map.insert(variable.clone(), future_id);
|
|
|
|
|
Ok(future_id)
|
2025-09-03 01:37:38 +09:00
|
|
|
}
|
2025-09-03 05:04:56 +09:00
|
|
|
|
|
|
|
|
// Await: insert Safepoint before/after and emit Await
|
2025-09-17 07:43:07 +09:00
|
|
|
pub(super) fn build_await_expression(
|
|
|
|
|
&mut self,
|
|
|
|
|
expression: ASTNode,
|
|
|
|
|
) -> Result<ValueId, String> {
|
2025-09-03 05:04:56 +09:00
|
|
|
let future_value = self.build_expression(expression)?;
|
|
|
|
|
self.emit_instruction(MirInstruction::Safepoint)?;
|
|
|
|
|
let result_id = self.value_gen.next();
|
2025-09-17 07:43:07 +09:00
|
|
|
self.emit_instruction(MirInstruction::Await {
|
|
|
|
|
dst: result_id,
|
|
|
|
|
future: future_value,
|
|
|
|
|
})?;
|
2025-09-03 05:04:56 +09:00
|
|
|
self.emit_instruction(MirInstruction::Safepoint)?;
|
|
|
|
|
Ok(result_id)
|
2025-09-03 01:37:38 +09:00
|
|
|
}
|
2025-09-03 05:04:56 +09:00
|
|
|
|
|
|
|
|
// me: resolve to param if present; else symbolic const (stable mapping)
|
2025-09-03 01:37:38 +09:00
|
|
|
pub(super) fn build_me_expression(&mut self) -> Result<ValueId, String> {
|
2025-09-17 07:43:07 +09:00
|
|
|
if let Some(id) = self.variable_map.get("me").cloned() {
|
|
|
|
|
return Ok(id);
|
|
|
|
|
}
|
2025-09-03 05:04:56 +09:00
|
|
|
let me_value = self.value_gen.next();
|
2025-09-17 07:43:07 +09:00
|
|
|
let me_tag = if let Some(ref cls) = self.current_static_box {
|
|
|
|
|
cls.clone()
|
|
|
|
|
} else {
|
|
|
|
|
"__me__".to_string()
|
|
|
|
|
};
|
|
|
|
|
self.emit_instruction(MirInstruction::Const {
|
|
|
|
|
dst: me_value,
|
|
|
|
|
value: ConstValue::String(me_tag),
|
|
|
|
|
})?;
|
2025-09-03 05:04:56 +09:00
|
|
|
self.variable_map.insert("me".to_string(), me_value);
|
|
|
|
|
Ok(me_value)
|
2025-09-03 01:37:38 +09:00
|
|
|
}
|
|
|
|
|
}
|
2025-09-17 16:11:01 +09:00
|
|
|
use crate::mir::loop_api::LoopBuilderApi; // for current_block()
|