Skip to content

feat(diagnostics): token and rule labels for expected-X messages - #73

Open
theoephraim wants to merge 1 commit into
johnsoncodehk:masterfrom
dmno-dev:feat/diagnostic-labels
Open

feat(diagnostics): token and rule labels for expected-X messages#73
theoephraim wants to merge 1 commit into
johnsoncodehk:masterfrom
dmno-dev:feat/diagnostic-labels

Conversation

@theoephraim

@theoephraim theoephraim commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Token and rule labels for expected … diagnostics

The emitted engine's $missing diagnostics name what was missing by its grammar name: a token NUM reads as expected 'NUM', a rule Value as expected Value. That is fine when grammar names are already words (Expr), and leaks internal identifiers to end users otherwise. We hit it porting env-spec (the dotenv dialect behind varlock): its tokens are things like DEC_VALUE_TEXT, and those names would be the text an editor shows on every keystroke.

token(pattern, { label: 'a number' }) and rule(fn, { label: 'an expression' }) substitute a display string in exactly those messages and nowhere else. Leaf tokenTypes, ruleNameOf, the CST, and every derived artifact keep the grammar name, so a grammar that adds labels parses byte-identically. A labelled token renders bare (expected a number); an unlabelled one keeps the quoted grammar name, so existing output is unchanged (the emitted tables gain RULE_LABELS and K_LABELS next to RULE_DISPLAY and K_NAMES; RULE_DISPLAY still drives node names).

Gate: test/diagnostic-labels.ts (registered in core). It covers the tiny-grammar token case, TypeScript's Expr rule relabelled (const a = ; reads expected an expression), tree identity across labels, the TextMate, tree-sitter, and language-configuration outputs byte-identical across labels, literal messages and related info unchanged, and the interpreter unaffected (it has no expected-X diagnostics). README gets one paragraph.

npm run check: 50/50.

The emitted engine's $missing diagnostics name what was missing by its
grammar name: a token NUM reads as "expected 'NUM'", a rule Value as
"expected Value". For a language whose grammar names are internal
identifiers (DEC_VALUE_TEXT) that text leaks straight to editor users.

token(pattern, { label }) and rule(fn, { label }) substitute a display
string in exactly those messages and nowhere else: leaf tokenTypes,
ruleNameOf, the CST, and every derived artifact keep the grammar name,
so a grammar that adds labels parses byte-identically. A labelled token
renders bare (expected a number); an unlabelled one keeps the quoted
name, so existing output is unchanged.

Gate: test/diagnostic-labels.ts (tiny grammar plus TypeScript's Expr
rule relabelled, tree identity across labels).
@theoephraim
theoephraim force-pushed the feat/diagnostic-labels branch from 6a143a7 to 95dd7f3 Compare September 8, 2026 04:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant