2025-09-17 11:45:57 +09:00
|
|
|
use super::{EffectMask, FunctionSignature, MirFunction, MirInstruction, MirModule, MirType, ValueId};
|
2025-09-17 10:58:12 +09:00
|
|
|
use crate::ast::ASTNode;
|
|
|
|
|
|
|
|
|
|
// Lifecycle routines extracted from builder.rs
|
|
|
|
|
impl super::MirBuilder {
|
2025-09-26 03:30:59 +09:00
|
|
|
/// Unified declaration indexing (Phase A): collect symbols before lowering
|
|
|
|
|
/// - user_defined_boxes: non-static Box names (for NewBox birth() skip)
|
|
|
|
|
/// - static_method_index: name -> [(BoxName, arity)] (for bare-call fallback)
|
|
|
|
|
fn index_declarations(&mut self, node: &ASTNode) {
|
2025-09-25 10:23:14 +09:00
|
|
|
match node {
|
|
|
|
|
ASTNode::Program { statements, .. } => {
|
|
|
|
|
for st in statements {
|
2025-09-26 03:30:59 +09:00
|
|
|
self.index_declarations(st);
|
2025-09-25 10:23:14 +09:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
ASTNode::BoxDeclaration { name, methods, is_static, .. } => {
|
2025-09-26 03:30:59 +09:00
|
|
|
if !*is_static {
|
|
|
|
|
self.user_defined_boxes.insert(name.clone());
|
|
|
|
|
} else {
|
2025-09-25 10:23:14 +09:00
|
|
|
for (mname, mast) in methods {
|
|
|
|
|
if let ASTNode::FunctionDeclaration { params, .. } = mast {
|
|
|
|
|
self.static_method_index
|
|
|
|
|
.entry(mname.clone())
|
|
|
|
|
.or_insert_with(Vec::new)
|
|
|
|
|
.push((name.clone(), params.len()));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
_ => {}
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-09-17 10:58:12 +09:00
|
|
|
pub(super) fn prepare_module(&mut self) -> Result<(), String> {
|
|
|
|
|
let module = MirModule::new("main".to_string());
|
|
|
|
|
let main_signature = FunctionSignature {
|
|
|
|
|
name: "main".to_string(),
|
|
|
|
|
params: vec![],
|
|
|
|
|
return_type: MirType::Void,
|
|
|
|
|
effects: EffectMask::PURE,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let entry_block = self.block_gen.next();
|
|
|
|
|
let mut main_function = MirFunction::new(main_signature, entry_block);
|
|
|
|
|
main_function.metadata.is_entry_point = true;
|
|
|
|
|
|
|
|
|
|
self.current_module = Some(module);
|
|
|
|
|
self.current_function = Some(main_function);
|
|
|
|
|
self.current_block = Some(entry_block);
|
|
|
|
|
|
2025-09-20 05:44:57 +09:00
|
|
|
// Hint: scope enter at function entry (id=0 for main)
|
|
|
|
|
self.hint_scope_enter(0);
|
|
|
|
|
|
2025-09-17 10:58:12 +09:00
|
|
|
if std::env::var("NYASH_BUILDER_SAFEPOINT_ENTRY")
|
|
|
|
|
.ok()
|
|
|
|
|
.as_deref()
|
|
|
|
|
== Some("1")
|
|
|
|
|
{
|
|
|
|
|
self.emit_instruction(MirInstruction::Safepoint)?;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(super) fn lower_root(&mut self, ast: ASTNode) -> Result<ValueId, String> {
|
2025-09-25 10:23:14 +09:00
|
|
|
// Pre-index static methods to enable safe fallback for bare calls in using-prepended code
|
|
|
|
|
let snapshot = ast.clone();
|
2025-09-26 03:30:59 +09:00
|
|
|
// Phase A: collect declarations in one pass (symbols available to lowering)
|
|
|
|
|
self.index_declarations(&snapshot);
|
|
|
|
|
// Phase B: top-level program lowering with declaration-first pass
|
|
|
|
|
match ast {
|
|
|
|
|
ASTNode::Program { statements, .. } => {
|
|
|
|
|
use crate::ast::ASTNode as N;
|
|
|
|
|
// First pass: lower declarations (static boxes except Main, and instance boxes)
|
|
|
|
|
let mut main_static: Option<(String, std::collections::HashMap<String, ASTNode>)> = None;
|
|
|
|
|
for st in &statements {
|
|
|
|
|
if let N::BoxDeclaration {
|
|
|
|
|
name,
|
|
|
|
|
methods,
|
|
|
|
|
is_static,
|
|
|
|
|
fields,
|
|
|
|
|
constructors,
|
|
|
|
|
weak_fields,
|
|
|
|
|
..
|
|
|
|
|
} = st
|
|
|
|
|
{
|
|
|
|
|
if *is_static {
|
|
|
|
|
if name == "Main" {
|
|
|
|
|
main_static = Some((name.clone(), methods.clone()));
|
|
|
|
|
} else {
|
|
|
|
|
// Lower all static methods into standalone functions: BoxName.method/Arity
|
|
|
|
|
for (mname, mast) in methods.iter() {
|
|
|
|
|
if let N::FunctionDeclaration { params, body, .. } = mast {
|
|
|
|
|
let func_name = format!("{}.{}{}", name, mname, format!("/{}", params.len()));
|
|
|
|
|
self.lower_static_method_as_function(func_name, params.clone(), body.clone())?;
|
|
|
|
|
self.static_method_index
|
|
|
|
|
.entry(mname.clone())
|
|
|
|
|
.or_insert_with(Vec::new)
|
|
|
|
|
.push((name.clone(), params.len()));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// Instance box: register type and lower instance methods/ctors as functions
|
|
|
|
|
self.user_defined_boxes.insert(name.clone());
|
|
|
|
|
self.build_box_declaration(
|
|
|
|
|
name.clone(),
|
|
|
|
|
methods.clone(),
|
|
|
|
|
fields.clone(),
|
|
|
|
|
weak_fields.clone(),
|
|
|
|
|
)?;
|
|
|
|
|
for (ctor_key, ctor_ast) in constructors.iter() {
|
|
|
|
|
if let N::FunctionDeclaration { params, body, .. } = ctor_ast {
|
|
|
|
|
let func_name = format!("{}.{}", name, ctor_key);
|
|
|
|
|
self.lower_method_as_function(
|
|
|
|
|
func_name,
|
|
|
|
|
name.clone(),
|
|
|
|
|
params.clone(),
|
|
|
|
|
body.clone(),
|
|
|
|
|
)?;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for (mname, mast) in methods.iter() {
|
|
|
|
|
if let N::FunctionDeclaration { params, body, is_static, .. } = mast {
|
|
|
|
|
if !*is_static {
|
|
|
|
|
let func_name = format!("{}.{}{}", name, mname, format!("/{}", params.len()));
|
|
|
|
|
self.lower_method_as_function(
|
|
|
|
|
func_name,
|
|
|
|
|
name.clone(),
|
|
|
|
|
params.clone(),
|
|
|
|
|
body.clone(),
|
|
|
|
|
)?;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Second pass: lower Main.main body as Program (entry). If absent, fall back to sequential block.
|
|
|
|
|
if let Some((box_name, methods)) = main_static {
|
|
|
|
|
self.build_static_main_box(box_name, methods)
|
|
|
|
|
} else {
|
|
|
|
|
// Fallback: sequential lowering (keeps legacy behavior for scripts without Main)
|
|
|
|
|
self.cf_block(statements)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
other => self.build_expression(other),
|
|
|
|
|
}
|
2025-09-17 10:58:12 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(super) fn finalize_module(
|
|
|
|
|
&mut self,
|
|
|
|
|
result_value: ValueId,
|
|
|
|
|
) -> Result<MirModule, String> {
|
2025-09-20 05:44:57 +09:00
|
|
|
// Hint: scope leave at function end (id=0 for main)
|
|
|
|
|
self.hint_scope_leave(0);
|
2025-09-17 10:58:12 +09:00
|
|
|
if let Some(block_id) = self.current_block {
|
|
|
|
|
if let Some(ref mut function) = self.current_function {
|
|
|
|
|
if let Some(block) = function.get_block_mut(block_id) {
|
|
|
|
|
if !block.is_terminated() {
|
|
|
|
|
block.add_instruction(MirInstruction::Return {
|
|
|
|
|
value: Some(result_value),
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
if let Some(mt) = self.value_types.get(&result_value).cloned() {
|
|
|
|
|
function.signature.return_type = mt;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let mut module = self.current_module.take().unwrap();
|
|
|
|
|
let mut function = self.current_function.take().unwrap();
|
|
|
|
|
function.metadata.value_types = self.value_types.clone();
|
|
|
|
|
if matches!(
|
|
|
|
|
function.signature.return_type,
|
|
|
|
|
super::MirType::Void | super::MirType::Unknown
|
|
|
|
|
) {
|
|
|
|
|
let mut inferred: Option<super::MirType> = None;
|
|
|
|
|
'outer: for (_bid, bb) in function.blocks.iter() {
|
|
|
|
|
for inst in bb.instructions.iter() {
|
|
|
|
|
if let super::MirInstruction::Return { value: Some(v) } = inst {
|
|
|
|
|
if let Some(mt) = self.value_types.get(v).cloned() {
|
|
|
|
|
inferred = Some(mt);
|
|
|
|
|
break 'outer;
|
|
|
|
|
}
|
2025-09-25 10:23:14 +09:00
|
|
|
if let Some(mt) = crate::mir::phi_core::if_phi::infer_type_from_phi(
|
2025-09-17 10:58:12 +09:00
|
|
|
&function,
|
|
|
|
|
*v,
|
|
|
|
|
&self.value_types,
|
|
|
|
|
) {
|
|
|
|
|
inferred = Some(mt);
|
|
|
|
|
break 'outer;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if let Some(super::MirInstruction::Return { value: Some(v) }) = &bb.terminator {
|
|
|
|
|
if let Some(mt) = self.value_types.get(v).cloned() {
|
|
|
|
|
inferred = Some(mt);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2025-09-25 10:23:14 +09:00
|
|
|
if let Some(mt) = crate::mir::phi_core::if_phi::infer_type_from_phi(
|
2025-09-17 10:58:12 +09:00
|
|
|
&function,
|
|
|
|
|
*v,
|
|
|
|
|
&self.value_types,
|
|
|
|
|
) {
|
|
|
|
|
inferred = Some(mt);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if let Some(mt) = inferred {
|
|
|
|
|
function.signature.return_type = mt;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
module.add_function(function);
|
|
|
|
|
|
|
|
|
|
Ok(module)
|
|
|
|
|
}
|
|
|
|
|
}
|