feat(loop-phi): Add body-local variable PHI generation for Rust AST loops
Phase 25.1c/k: Fix ValueId undefined errors in loops with body-local variables **Problem:** - FuncScannerBox.scan_all_boxes/1 and BreakFinderBox._find_loops/2 had ValueId undefined errors for variables declared inside loop bodies - LoopFormBuilder only generated PHIs for preheader variables, missing body-locals - Example: `local ch = s.substring(i, i+1)` inside loop → undefined on next iteration **Solution:** 1. **Rust AST path** (src/mir/loop_builder.rs): - Detect body-local variables by comparing body_end_vars vs current_vars - Generate empty PHI nodes at loop header for body-local variables - Seal PHIs with latch + continue snapshot inputs after seal_phis() - Added HAKO_LOOP_PHI_TRACE=1 logging for debugging 2. **JSON v0 path** (already fixed in previous session): - src/runner/json_v0_bridge/lowering/loop_.rs handles body-locals - Uses same strategy but for JSON v0 bridge lowering **Results:** - ✅ FuncScannerBox.scan_all_boxes: 41 body-local PHIs generated - ✅ Main.main (demo harness): 23 body-local PHIs generated - ⚠️ Still some ValueId undefined errors remaining (exit PHI issue) **Files changed:** - src/mir/loop_builder.rs: body-local PHI generation logic - lang/src/compiler/entry/func_scanner.hako: debug logging - /tmp/stageb_funcscan_demo.hako: test harness 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@ -14,10 +14,10 @@ impl NyashParser {
|
||||
/// Parse declaration statement dispatch
|
||||
pub(super) fn parse_declaration_statement(&mut self) -> Result<ASTNode, ParseError> {
|
||||
match &self.current_token().token_type {
|
||||
TokenType::BOX => self.parse_box_declaration(),
|
||||
TokenType::FLOW => self.parse_box_declaration(), // flow is syntactic sugar for static box
|
||||
TokenType::BOX => crate::parser::declarations::box_def::parse_box_declaration(self),
|
||||
TokenType::FLOW => crate::parser::declarations::box_def::parse_box_declaration(self), // flow is syntactic sugar for static box
|
||||
TokenType::IMPORT => self.parse_import(),
|
||||
TokenType::INTERFACE => self.parse_interface_box_declaration(),
|
||||
TokenType::INTERFACE => crate::parser::declarations::box_def::parse_interface_box_declaration(self),
|
||||
TokenType::GLOBAL => self.parse_global_var(),
|
||||
TokenType::FUNCTION => self.parse_function_declaration(),
|
||||
TokenType::STATIC => self.parse_static_declaration(),
|
||||
|
||||
@ -73,17 +73,26 @@ impl NyashParser {
|
||||
let mut parts = vec![first.clone()];
|
||||
self.advance();
|
||||
while let TokenType::DOT = self.current_token().token_type {
|
||||
// consume '.' and the following IDENTIFIER
|
||||
// consume '.' and the following IDENTIFIER-like segment
|
||||
self.advance();
|
||||
if let TokenType::IDENTIFIER(seg) = &self.current_token().token_type {
|
||||
parts.push(seg.clone());
|
||||
self.advance();
|
||||
} else {
|
||||
return Err(ParseError::UnexpectedToken {
|
||||
found: self.current_token().token_type.clone(),
|
||||
expected: "identifier after '.'".to_string(),
|
||||
line: self.current_token().line,
|
||||
});
|
||||
match &self.current_token().token_type {
|
||||
TokenType::IDENTIFIER(seg) => {
|
||||
parts.push(seg.clone());
|
||||
self.advance();
|
||||
}
|
||||
// Allow `box` as a namespace segment (e.g. lang.compiler.parser.box)
|
||||
// even though it is a keyword at the statement level.
|
||||
TokenType::BOX => {
|
||||
parts.push("box".to_string());
|
||||
self.advance();
|
||||
}
|
||||
other => {
|
||||
return Err(ParseError::UnexpectedToken {
|
||||
found: other.clone(),
|
||||
expected: "identifier after '.'".to_string(),
|
||||
line: self.current_token().line,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
parts.join(".")
|
||||
|
||||
Reference in New Issue
Block a user