MIR: lexical scoping + builder vars modules

This commit is contained in:
nyash-codex
2025-12-13 01:30:04 +09:00
parent 5c75506dcc
commit 1fae4f1648
16 changed files with 388 additions and 29 deletions

View File

@ -92,6 +92,12 @@ pub struct MirBuilder {
/// Phase 25.1: HashMap → BTreeMapPHI生成の決定性確保
pub(super) variable_map: BTreeMap<String, ValueId>,
/// Lexical scope stack for block-scoped `local` declarations.
///
/// This tracks per-block shadowing so `local x` inside `{...}` restores the
/// outer binding when the block ends.
lexical_scope_stack: Vec<vars::lexical_scope::LexicalScopeFrame>,
/// Pending phi functions to be inserted
#[allow(dead_code)]
pub(super) pending_phis: Vec<(BasicBlockId, ValueId, String)>,
@ -266,6 +272,7 @@ impl MirBuilder {
block_gen: BasicBlockIdGenerator::new(),
compilation_context: None, // 箱理論: デフォルトは従来モード
variable_map: BTreeMap::new(), // Phase 25.1: 決定性確保
lexical_scope_stack: Vec::new(),
pending_phis: Vec::new(),
value_origin_newbox: BTreeMap::new(), // Phase 25.1: 決定性確保
user_defined_boxes: HashSet::new(),
@ -546,37 +553,45 @@ impl MirBuilder {
if let Some(&value_id) = self.variable_map.get(&name) {
Ok(value_id)
} else {
// Enhance diagnostics using Using simple registry (Phase 1)
let mut msg = format!("Undefined variable: {}", name);
// Stage-3 keyword diagnostic (local/flow/try/catch/throw)
if name == "local" && !crate::config::env::parser_stage3_enabled() {
msg.push_str("\nHint: 'local' is a Stage-3 keyword. Prefer NYASH_FEATURES=stage3 (legacy: NYASH_PARSER_STAGE3=1 / HAKO_PARSER_STAGE3=1 for Stage-B).");
msg.push_str("\nFor AotPrep verification, use tools/hakorune_emit_mir.sh which sets these automatically.");
} else if (name == "flow" || name == "try" || name == "catch" || name == "throw")
&& !crate::config::env::parser_stage3_enabled()
{
msg.push_str(&format!("\nHint: '{}' is a Stage-3 keyword. Prefer NYASH_FEATURES=stage3 (legacy: NYASH_PARSER_STAGE3=1 / HAKO_PARSER_STAGE3=1 for Stage-B).", name));
}
let suggest = crate::using::simple_registry::suggest_using_for_symbol(&name);
if !suggest.is_empty() {
msg.push_str("\nHint: symbol appears in using module(s): ");
msg.push_str(&suggest.join(", "));
msg.push_str(
"\nConsider adding 'using <module> [as Alias]' or check nyash.toml [using].",
);
}
Err(msg)
Err(self.undefined_variable_message(&name))
}
}
pub(in crate::mir::builder) fn undefined_variable_message(&self, name: &str) -> String {
// Enhance diagnostics using Using simple registry (Phase 1)
let mut msg = format!("Undefined variable: {}", name);
// Stage-3 keyword diagnostic (local/flow/try/catch/throw)
if name == "local" && !crate::config::env::parser_stage3_enabled() {
msg.push_str("\nHint: 'local' is a Stage-3 keyword. Prefer NYASH_FEATURES=stage3 (legacy: NYASH_PARSER_STAGE3=1 / HAKO_PARSER_STAGE3=1 for Stage-B).");
msg.push_str("\nFor AotPrep verification, use tools/hakorune_emit_mir.sh which sets these automatically.");
} else if (name == "flow" || name == "try" || name == "catch" || name == "throw")
&& !crate::config::env::parser_stage3_enabled()
{
msg.push_str(&format!("\nHint: '{}' is a Stage-3 keyword. Prefer NYASH_FEATURES=stage3 (legacy: NYASH_PARSER_STAGE3=1 / HAKO_PARSER_STAGE3=1 for Stage-B).", name));
}
let suggest = crate::using::simple_registry::suggest_using_for_symbol(name);
if !suggest.is_empty() {
msg.push_str("\nHint: symbol appears in using module(s): ");
msg.push_str(&suggest.join(", "));
msg.push_str("\nConsider adding 'using <module> [as Alias]' or check nyash.toml [using].");
}
msg
}
/// Build assignment
pub(super) fn build_assignment(
&mut self,
var_name: String,
value: ASTNode,
) -> Result<ValueId, String> {
// SSOT (LANGUAGE_REFERENCE_2025 / syntax-cheatsheet):
// - Assignment to an undeclared name is an error.
// - Use `local name = ...` (or `local name; name = ...`) to declare.
vars::assignment_resolver::AssignmentResolverBox::ensure_declared(self, &var_name)?;
let value_id = self.build_expression(value)?;
// Step 5-5-E: FIX variable map corruption bug