fix(parser): Stage-B NEWLINE handling and test file corrections
**Stage-B Parser Improvements:**
- Add NEWLINE skipping before/after LOCAL keyword (variables.rs)
- Add NEWLINE skipping after '{' in block statements (mod.rs)
- Add safety valve for statement keywords in static_box.rs
**Test File Fixes:**
- Fix collect_empty_args_smoke.hako: static box → box (allow instantiation)
- Fix method calls: index_of_from() → me.index_of_from() (explicit receiver)
**Context:**
These changes support the PHI UseBeforeDef bug investigation and improve
Stage-B parser robustness for NEWLINE handling in method bodies.
**Test Results:**
✅ collect_prints() loop break handling verified
✅ ArrayBox.length() working correctly (after user fix)
✅ All existing loop smoke tests passing (loop_min_while, nested_loop_inner_break, etc.)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@ -69,6 +69,20 @@ impl NyashParser {
|
||||
self, &mut init_fields, &mut weak_fields,
|
||||
)? { continue; }
|
||||
|
||||
// 🔧 Safety valve: if we encounter statement keywords (LOCAL, RETURN, etc.) at member level,
|
||||
// it means we've likely exited a method body prematurely. Break to close the static box.
|
||||
match self.current_token().token_type {
|
||||
TokenType::LOCAL | TokenType::RETURN | TokenType::IF | TokenType::LOOP |
|
||||
TokenType::BREAK | TokenType::CONTINUE | TokenType::PRINT => {
|
||||
if std::env::var("NYASH_CLI_VERBOSE").ok().as_deref() == Some("1") {
|
||||
eprintln!("[parser][static-box][safety] encountered statement keyword {:?} at member level (line {}); assuming premature method body exit",
|
||||
self.current_token().token_type, self.current_token().line);
|
||||
}
|
||||
break;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
if let TokenType::IDENTIFIER(field_or_method) = &self.current_token().token_type {
|
||||
let field_or_method = field_or_method.clone();
|
||||
self.advance();
|
||||
|
||||
@ -91,6 +91,11 @@ impl NyashParser {
|
||||
);
|
||||
}
|
||||
self.consume(TokenType::LBRACE)?;
|
||||
|
||||
// Critical: Skip any leading NEWLINE tokens immediately after '{'
|
||||
// This ensures the first statement starts at the correct position
|
||||
while self.match_token(&TokenType::NEWLINE) { self.advance(); }
|
||||
|
||||
let mut statements = Vec::new();
|
||||
|
||||
// Be tolerant to blank lines within blocks: skip NEWLINE tokens between statements
|
||||
|
||||
@ -29,6 +29,17 @@ impl NyashParser {
|
||||
|
||||
/// Parse local variable declaration: local var1, var2, var3 or local x = 10
|
||||
pub(super) fn parse_local(&mut self) -> Result<ASTNode, ParseError> {
|
||||
let debug_parse_local = std::env::var("NYASH_DEBUG_PARSE_LOCAL").ok().as_deref() == Some("1");
|
||||
if debug_parse_local {
|
||||
eprintln!("[parse_local] entry: current_token={:?} at line {}",
|
||||
self.current_token().token_type, self.current_token().line);
|
||||
}
|
||||
|
||||
// Always skip leading NEWLINEs before consuming 'local' keyword
|
||||
while self.match_token(&TokenType::NEWLINE) {
|
||||
self.advance();
|
||||
}
|
||||
|
||||
if super::helpers::cursor_enabled() {
|
||||
let mut cursor = TokenCursor::new(&self.tokens);
|
||||
cursor.set_position(self.current);
|
||||
@ -37,6 +48,16 @@ impl NyashParser {
|
||||
}
|
||||
self.advance(); // consume 'local'
|
||||
|
||||
// Skip any NEWLINE tokens after 'local' keyword
|
||||
while self.match_token(&TokenType::NEWLINE) {
|
||||
self.advance();
|
||||
}
|
||||
|
||||
if debug_parse_local {
|
||||
eprintln!("[parse_local] after advance: current_token={:?} at line {}",
|
||||
self.current_token().token_type, self.current_token().line);
|
||||
}
|
||||
|
||||
let mut names = Vec::new();
|
||||
let mut initial_values = Vec::new();
|
||||
|
||||
@ -84,6 +105,20 @@ impl NyashParser {
|
||||
})
|
||||
}
|
||||
} else {
|
||||
// Enhanced error message for debugging
|
||||
if debug_parse_local {
|
||||
eprintln!("[parse_local] ERROR: Expected IDENTIFIER, found {:?} at line {}",
|
||||
self.current_token().token_type, self.current_token().line);
|
||||
eprintln!("[parse_local] ERROR: Previous 3 tokens:");
|
||||
for i in 1..=3 {
|
||||
if self.current >= i {
|
||||
let idx = self.current - i;
|
||||
if idx < self.tokens.len() {
|
||||
eprintln!(" [-{}] {:?}", i, self.tokens[idx].token_type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(ParseError::UnexpectedToken {
|
||||
found: self.current_token().token_type.clone(),
|
||||
expected: "identifier".to_string(),
|
||||
|
||||
Reference in New Issue
Block a user