Skip to content

LABEL inside a nested block is silently dropped, producing a misleading 'GOTO target not found' error #2

@p0dalirius

Description

@p0dalirius

Summary

The parser accepts LABEL syntactically anywhere but only registers labels that appear at the top level of the script. A LABEL placed inside IF/ELSE/WHILE/REPEAT/DEF is silently discarded, and any subsequent GOTO to that label fails with a misleading GOTO target '<name>' not found error that points at the GOTO, not at the misplaced LABEL.

Location

  • File: src/script_parser.cpp
  • Lines / functions: ScriptParser::parse() at L155–L164 (label collection walks only root->children)
  • Related: L98–L101 (DEF is explicitly rejected inside blocks; LABEL is not)

Category

state-management

Severity

medium

Impact: scripts that mistakenly place LABEL inside a block fail at parse time with a confusing, misdirected error. The language reference (PROMPT.md) documents LABEL name / GOTO name (top-level only), so the constraint is intended but not enforced at the point it is violated.

Reproduction / Evidence

Verified by code analysis and runtime test:

ScriptParser parser;
auto r = parser.parse(
    "IF $X == \"1\"\n"
    "  LABEL inside\n"
    "ENDIF\n"
    "GOTO inside\n"
);
// r.errors: [ line 4: "GOTO target 'inside' not found" ]
// r.labels: empty

The LABEL node is appended to the enclosing block's children (parser.cpp L108–L114). Label resolution at L155–L164 iterates only root->children, so the nested LABEL is never added to result.labels. Validation at L170–L175 then flags the GOTO as dangling.

Expected Behavior

The parser should emit a clear error at the LABEL line stating that LABEL must be at the top level (matching the existing handling of DEF at L98–L101). No error should then be emitted against the GOTO, or — if it is — it should be evidently secondary.

Actual Behavior

Nested LABEL is silently dropped. The only error the user sees references the GOTO line, making the root cause hard to diagnose.

Root Cause

The label-collection loop only examines root->children and does not recurse; the grammar does not refuse LABEL inside a block at the point it is parsed.

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions