Summary
When a syntax error occurs in a trailing top-level statement (e.g. a stray statement after the last function in the file), the parser reports the error location as somewhere inside the first function/statement in the file, rather than at the actual offending line.
Reproduction
fn foo() {
let x: i32 = 1;
}
// some comments
// more comments
print("stray top level statement");
The actual problem is the bare print(...) call at top level (line 8) — top-level statements must be fn, let, or signal declarations. But the compiler reports:
Error[E101]: Unexpected token
Expected 'fn', 'let', or 'signal' at top level, found identifier at line 2, column 20
1 | fn foo() {
2 | let x: i32 = 1;
| ^ Only function or global variable declarations allowed at top level
3 | }
Line 2 is inside foo() and is entirely valid — the pointer and line number are both wrong. Verified against current main (v0.0.5) via a standalone repro using ferrisscript_compiler::compile().
Location
crates/compiler/src/parser.rs — likely in the top-level parsing loop's error-recovery/synchronization logic (see also synchronize() around line 160), which appears to retain a stale position when the actual error token is further down the file.
Why it matters
Wrong line numbers in error messages directly undermine the "helpful diagnostics" the compiler is built around, and would actively mislead anyone trying to fix a real syntax error. Also relevant to the span-tracking work landed in v0.0.5 (crates/compiler/src/span.rs) and any future LSP work that depends on accurate error ranges. Found during a broader technical-debt review of the v0.0.5 release, originally surfaced via the ferris-test integration corpus (godot_test/scripts/inspector_test.ferris).
Summary
When a syntax error occurs in a trailing top-level statement (e.g. a stray statement after the last function in the file), the parser reports the error location as somewhere inside the first function/statement in the file, rather than at the actual offending line.
Reproduction
The actual problem is the bare
print(...)call at top level (line 8) — top-level statements must befn,let, orsignaldeclarations. But the compiler reports:Line 2 is inside
foo()and is entirely valid — the pointer and line number are both wrong. Verified against currentmain(v0.0.5) via a standalone repro usingferrisscript_compiler::compile().Location
crates/compiler/src/parser.rs— likely in the top-level parsing loop's error-recovery/synchronization logic (see alsosynchronize()around line 160), which appears to retain a stale position when the actual error token is further down the file.Why it matters
Wrong line numbers in error messages directly undermine the "helpful diagnostics" the compiler is built around, and would actively mislead anyone trying to fix a real syntax error. Also relevant to the span-tracking work landed in v0.0.5 (
crates/compiler/src/span.rs) and any future LSP work that depends on accurate error ranges. Found during a broader technical-debt review of the v0.0.5 release, originally surfaced via theferris-testintegration corpus (godot_test/scripts/inspector_test.ferris).