1
0
Fork 0
mirror of https://github.com/imjasonh/nescript synced 2026-07-09 01:16:12 +00:00

Fix bugs found during code review

Issues found by systematic review of all compiler modules.
Each fix includes a regression test.

Parser fixes:
- Add EOF checks to function call arg parsing loops (lines 984, 1269)
  to prevent infinite loops on unterminated call expressions
- Fix span end positions: use .end instead of .start for 9 declaration
  span computations (var, const, fun, state, bank, sprite, palette,
  background, block)
- Add missing compound assignment operators (&= |= ^=) to
  parse_assign_op() for array element assignments

Codegen fix:
- Fix NOT operator: old code used EOR #$FF + AND #$01 which produced
  wrong results for non-boolean inputs (e.g., NOT 0x42 returned 1
  instead of 0). New code uses BEQ/branch to properly map any nonzero
  value to 0 and zero to 1.

Assembler fixes:
- Add branch offset range validation: assert offset is in -128..127
  range instead of silently wrapping on overflow
- Panic on unresolved labels instead of silently leaving placeholder
  0x00 bytes in the output

Verified non-issues (reviewer false positives):
- NMI P register: 6502 hardware pushes P automatically on NMI entry;
  RTI restores it. PHP/PLP not needed.
- Controller read buffer: 8 iterations of LSR+ROL fully replace all
  8 bits, so prior contents don't matter.
- advance() panic: tokens always has at least Eof from lexer.

4 new regression tests, 225 total.

https://claude.ai/code/session_01W6eQFStA66EuMKHUFo2rx3
This commit is contained in:
Claude 2026-04-12 01:00:27 +00:00
parent 07dd5bd7e8
commit bc165ed647
No known key found for this signature in database
5 changed files with 96 additions and 14 deletions

View file

@ -328,7 +328,7 @@ impl Parser {
var_type,
init,
placement,
span: Span::new(start.file_id, start.start, self.current_span().start),
span: Span::new(start.file_id, start.start, self.current_span().end),
})
}
@ -347,7 +347,7 @@ impl Parser {
name,
const_type,
value,
span: Span::new(start.file_id, start.start, self.current_span().start),
span: Span::new(start.file_id, start.start, self.current_span().end),
})
}
@ -395,7 +395,7 @@ impl Parser {
return_type,
body,
is_inline,
span: Span::new(start.file_id, start.start, self.current_span().start),
span: Span::new(start.file_id, start.start, self.current_span().end),
})
}
@ -458,7 +458,7 @@ impl Parser {
on_exit,
on_frame,
on_scanline,
span: Span::new(start.file_id, start.start, self.current_span().start),
span: Span::new(start.file_id, start.start, self.current_span().end),
})
}
@ -484,7 +484,7 @@ impl Parser {
Ok(BankDecl {
name,
bank_type,
span: Span::new(start.file_id, start.start, self.current_span().start),
span: Span::new(start.file_id, start.start, self.current_span().end),
})
}
@ -538,7 +538,7 @@ impl Parser {
Ok(SpriteDecl {
name,
chr_source,
span: Span::new(start.file_id, start.start, self.current_span().start),
span: Span::new(start.file_id, start.start, self.current_span().end),
})
}
@ -597,7 +597,7 @@ impl Parser {
Ok(PaletteDecl {
name,
colors,
span: Span::new(start.file_id, start.start, self.current_span().start),
span: Span::new(start.file_id, start.start, self.current_span().end),
})
}
@ -638,7 +638,7 @@ impl Parser {
Ok(BackgroundDecl {
name,
chr_source,
span: Span::new(start.file_id, start.start, self.current_span().start),
span: Span::new(start.file_id, start.start, self.current_span().end),
})
}
@ -715,7 +715,7 @@ impl Parser {
Ok(Block {
statements,
span: Span::new(start.file_id, start.start, self.current_span().start),
span: Span::new(start.file_id, start.start, self.current_span().end),
})
}
@ -981,7 +981,7 @@ impl Parser {
// Function call
self.advance();
let mut args = Vec::new();
while *self.peek() != TokenKind::RParen {
while *self.peek() != TokenKind::RParen && *self.peek() != TokenKind::Eof {
args.push(self.parse_expr()?);
if *self.peek() == TokenKind::Comma {
self.advance();
@ -1015,6 +1015,18 @@ impl Parser {
self.advance();
Ok(AssignOp::MinusAssign)
}
TokenKind::AmpAssign => {
self.advance();
Ok(AssignOp::AmpAssign)
}
TokenKind::PipeAssign => {
self.advance();
Ok(AssignOp::PipeAssign)
}
TokenKind::CaretAssign => {
self.advance();
Ok(AssignOp::CaretAssign)
}
_ => Err(Diagnostic::error(
ErrorCode::E0201,
format!("expected assignment operator, found '{}'", self.peek()),
@ -1266,7 +1278,7 @@ impl Parser {
if *self.peek() == TokenKind::LParen {
self.advance();
let mut args = Vec::new();
while *self.peek() != TokenKind::RParen {
while *self.peek() != TokenKind::RParen && *self.peek() != TokenKind::Eof {
args.push(self.parse_expr()?);
if *self.peek() == TokenKind::Comma {
self.advance();