Enforce lexical literal constraints from grammar.md#73
Merged
StreamDemon merged 2 commits intoJul 2, 2026
Conversation
Four gaps between the lexer and the documented lexical constraints (docs/reference/grammar.md, section 16.1), found by the same review that drove the parser correctness wave: - Empty character literals (`''`) lexed as CharLit. CHAR_LIT requires exactly one Unicode scalar value; empty literals now error. - Bare base prefixes (`0x`, `0o`, `0b`) with no digits lexed as IntLit. hex_lit/oct_lit/bin_lit each require at least one digit; a bare prefix now errors with the base spelled out. - Integer suffixes on float literals (`3.14u32`, `1e10u8`) were silently kept as FloatLit. float_suffix is only `f32`/`f64`, so these now error, as does a float suffix on a based literal (`0b1f32`) — FLOAT_LIT only combines a float suffix with dec_lit. - Separator validation used is_ascii_hexdigit for neighbor checks regardless of base, so `1_e5`, `1e_5`, and `1.5_e3` passed in decimal literals (`e` is a hex digit character). Neighbor checks are now base-aware. Literal-overflow checking (also listed in grammar.md as a parse-time error) needs typed literals and stays deferred to semantic analysis; the crates/AGENTS.md subset contract now says so. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01H3CinyyqWL6SfCLrKGm3ja
There was a problem hiding this comment.
No issues found across 2 files
Confidence score: 5/5
- Automated review surfaced no issues in the provided summaries.
- No files require special attention.
Architecture diagram
sequenceDiagram
participant SOURCE as Source Text
participant LEX as Lexer
participant TOKENS as Token Stream
participant GRAMMAR as grammar.md Spec
Note over SOURCE,GRAMMAR: Lexer literal validation flow (§16.1)
LEX->>SOURCE: read next token
alt Character literal ('')
SOURCE-->>LEX: '' at position
LEX->>LEX: char_lit(): scan for scalar
LEX->>LEX: no scalar found after opening quote
Note over LEX: NEW: empty character literal
LEX->>LEX: error("empty character literal")
LEX-->>TOKENS: no token (error)
else Numeric literal with base prefix
SOURCE-->>LEX: 0x / 0o / 0b
LEX->>LEX: base = ident base(16/8/2)
LEX->>LEX: digits(base): no digits consumed
Note over LEX: NEW: bare base prefix
LEX->>LEX: error("{base} literal needs at least one digit")
LEX-->>TOKENS: no token (error)
else Float literal with int suffix
SOURCE-->>LEX: 3.14u32
LEX->>LEX: numeric_lit(): detect float kind
LEX->>LEX: suffix = u32
Note over LEX: NEW: int suffix on float literal
alt kind == FloatLit AND suffix starts with 'f'
LEX->>LEX: validate suffix (f32/f64)
else kind == FloatLit AND suffix doesn't start with 'f'
LEX->>LEX: error("float literals only accept `f32`/`f64` suffixes")
end
LEX-->>TOKENS: no token (error)
else Based literal with float suffix
SOURCE-->>LEX: 0b1f32
LEX->>LEX: numeric_lit(): base=2
LEX->>LEX: suffix = f32
Note over LEX: NEW: float suffix on based literal
alt suffix starts with 'f' AND base != 10
LEX->>LEX: error("float suffixes require a decimal literal")
end
LEX-->>TOKENS: no token (error)
else Numeric separator validation
SOURCE-->>LEX: 1_e5
LEX->>LEX: numeric_lit(): base=10
LEX->>LEX: digits(10) -> 1, then '_'
Note over LEX: NEW: base-aware separator check
LEX->>LEX: validate_numeric_body(start, base)
LEX->>LEX: check neighbor: valid_digit('e', base=10)? -> false
alt neighbor invalid digit for base
LEX->>LEX: error("numeric separators must appear between digits")
else neighbors valid (e.g., 0xF_F)
LEX->>LEX: continue
end
else Valid literal
SOURCE-->>LEX: 0xFF, 3.14f32, etc.
LEX->>LEX: scan token normally
LEX-->>TOKENS: token
end
Note over TOKENS,GRAMMAR: overflow checking deferred to semantic analysis
LEX->>GRAMMAR: references §16.1 rules
GRAMMAR-->>LEX: validates constraints
Auto-approved: Enforcing lexical literal constraints from grammar.md: empty chars, bare prefixes, suffix mismatches, base-aware separators. Low-risk spec compliance changes with tests.
Re-trigger cubic
6 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Four gaps between the lexer and the documented lexical constraints (§16.1, mirrored in
docs/reference/grammar.md), from the same review as PRs #70/#72 — all cases where the lexer silently accepted what the grammar calls a compile error:''lexed as aCharLit.CHAR_LITrequires exactly one Unicode scalar value — now "empty character literal".0x/0o/0bwith no digits lexed asIntLit.hex_lit/oct_lit/bin_liteach require at least one digit — now e.g. "hexadecimal literal needs at least one digit". (A prefix followed only by_was already caught by the separator rule and still is.)3.14u32,1e10u8) silently stayedFloatLit—float_suffixis onlyf32/f64, so these now error. The mirror case, a float suffix on a based literal (0b1f32,0o7f64), also errors —FLOAT_LITonly combines a float suffix withdec_lit. (0xFf32remains a hex int:f,3,2are hex digits, so there is no suffix to validate.)is_ascii_hexdigitregardless of base, so1_e5,1e_5, and1.5_e3passed in decimal literals (eis a hex-digit character but not a decimal digit). Neighbors are now checked with the literal's own base;0xF_F/0xd_estay legal.Deferred, now documented: grammar.md also lists literal overflow as a parse-time error; that needs typed literals, so it stays deferred to semantic analysis — the
crates/AGENTS.mdsubset contract now says so explicitly.Stacked-PR note: targets the integration branch
fix/parser-correctness-base(PR #69), notmain— sibling of #70/#72. Only overlap with the siblings is onecrates/AGENTS.mdlist insertion (keep-both at merge); the lexer crate itself is untouched by the other sub-PRs.Related Issue
None (review-driven; part of the parser correctness wave tracked in PR #69).
Spec Sections Affected
None changed — this PR implements §16.1's lexical constraints as documented in
docs/reference/grammar.md.Checklist
docs/pages (crates/AGENTS.md subset contract)Build Targets Tested
Test Plan
rejects_empty_char_literal(with' 'and'\''acceptance),rejects_bare_base_prefixes(all three bases, message names the base),rejects_int_suffix_on_float_literals,rejects_float_suffix_on_based_literals(incl. the0xFf32hex-digit-greediness case),separator_validation_is_base_aware(1_e5/1e_5/1.5_e3rejected;1_000.5e10,0xF_F,0xd_eaccepted).1_000u64in the corpus still lexes).cargo fmt --all -- --check,cargo clippy --workspace --all-targets -- -D warnings,cargo test --workspacegreen locally and viascripts/docker-check.ps1 -Build(Ubuntu parity).Summary by cubic
Enforces §16.1 literal rules from
docs/reference/grammar.mdin the lexer so invalid numeric and character literals now error with clear messages. Clarifies incrates/AGENTS.mdthat overflow checks are deferred to semantic analysis.Bug Fixes
'') with "empty character literal".0x/0o/0b; errors name the base.f32/f64and only allowed on decimal; based literals with float suffix error (e.g.,0b1f32), while0xFf32remains a hex int.1_e5/1e_5/1.5_e3; allow0xF_F/0xd_e.Migration
'', bare base prefixes, int suffixes on floats, or separators touching non-digits in decimal literals.crates/AGENTS.md).Written for commit b48f52a. Summary will update on new commits.