You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Extend the highlight-query generator to mirror more of gen-tm's per-position scope
inference. Every capture is derived from grammar SHAPE — never a hardcoded rule name:
- type parameters: identifiers inside a `< … >` binder rule -> @type
- member keys: the property-name rule (a pure name-form alternation) -> @Property
- type-object keys: the member-list element inside a type-context `{ … }` -> @Property
- property access: the `expr (expr) ident` tail, when the grammar has `.` access -> @Property
- declaration names, keyword-anchored: one decl rule is shared across kinds, so anchor
on the keyword token (`class`/`interface`/`type`/…) to give each kind its own capture
and to reach names with no `name` field (a bare type-alias name)
- enum-like value members: a rule whose every branch is `[nameRule, opt(…)]` overrides
the member-key -> @Property capture back to @variable (enum members are values)
Also skip `not` lookaheads between a keyword and its name in collectNameFields (a
type-alias parses as `type <not …> Ident`), which is what surfaces the alias name.
Graded through the same tsc oracle as the README bench, the derived tree-sitter
highlighter rises from 88.8% to 95.3% — above the official parsers (tree-sitter 92.7%,
Lezer 89.5%). The detectors stay grammar-agnostic (test/agnostic.ts: 5/5).
Add a `--miss-mts` bench diagnostic (misses grouped by role, flagging which ones the
official grammar gets right) that drove the work. Regenerate TS + JS artifacts.
<sub>Graded over 102 ambiguity-rich snippets ([`test/issue-cases.ts`](test/issue-cases.ts)) against tsc's own parse tree. The three parser-based highlighters (Monogram, tree-sitter, Lezer) cluster well above the hand-written TextMate grammar — that gap is the whole point. Per-engine vocabulary→family maps (frozen, auditable): [`test/highlight-engines.ts`](test/highlight-engines.ts). JavaScript: not yet on the bench. Regenerate: `npm run bench:readme`.</sub>
78
78
<!-- bench:end -->
79
79
80
-
> **Why the Monogram row is its *TextMate* output.** That's the one CI can rebuild on every commit. Monogram *also* derives a full **tree-sitter** grammar + query from the same definition; built locally to wasm and graded through this *same*`tsc` oracle, it scores **88.8%** — above both TextMate grammars (its own 87.6%, official 76.2%) and within range of the official parsers (tree-sitter 92.7%, Lezer 89.5%). The lift is *structural*: type references are captured by node position — `(type (ident) @type)` — not a hardcoded builtin list, so it never paints a value as a type. It's opt-in (needs a local wasm build), hence out of the CI chart: `MONOGRAM_TS_WASM=… node test/highlight-bench.ts --corpus adversarial --engines`. *(There is no Monogram-**Lezer** number: the grammar is expressive enough to trip Lezer's LR(1) shift/reduce wall — it parses under tree-sitter's GLR but won't build under Lezer.)*
80
+
> **Why the Monogram row is its *TextMate* output.** That's the one CI can rebuild on every commit. Monogram *also* derives a full **tree-sitter** grammar + query from the same definition; built locally to wasm and graded through this *same* `tsc` oracle, it scores **95.3%** — **above the official parsers** (tree-sitter 92.7%, Lezer 89.5%) and both TextMate grammars (its own 87.6%, official 76.2%). The lift is *structural*: every capture is derived from grammar shape — type references by node position (`(type (ident) @type)`), member keys from the member-name rule, type parameters from the `< … >` binder, declaration names keyword-anchored — never a hardcoded vocabulary, so it never paints a value as a type. It's opt-in (needs a local wasm build), hence out of the CI chart: `MONOGRAM_TS_WASM=… node test/highlight-bench.ts --corpus adversarial --engines`. *(There is no Monogram-**Lezer** number: the grammar is expressive enough to trip Lezer's LR(1) shift/reduce wall — it parses under tree-sitter's GLR but won't build under Lezer.)*
81
81
82
82
> **The other side of the ledger (honesty check).** On the *broad* TS parser-conformance corpus — not just the documented bugs — the two are now neck-and-neck: token-role accuracy is **tied at ~99%**, Monogram **leads on per-cell coverage** (100% of strict cells vs official's ~97%), and whole-file-perfect snippets are essentially level (~88% vs ~89%). The small residual is niche multiline type-annotation scoping, **not** the ambiguity class above. Clone the TS corpus to `/tmp/ts-repo` and run `node test/highlight-bench.ts` to see both corpora.
83
83
@@ -93,7 +93,7 @@ From one grammar definition (a small TypeScript combinator API), three outputs a
93
93
94
94
And — from the same grammar — generators for the rest of the ecosystem, at varying maturity:
95
95
96
-
-**tree-sitter** — `grammar.js` + a **structural**`queries/highlights.scm` + an external scanner for context-sensitive lexing. Builds end-to-end (tree-sitter's GLR absorbs the grammar; compiles to wasm) and the *derived* query scores **88.8%** through the same oracle as the chart above — above both TextMate grammars, just under the official parsers. Opt-in (needs a local wasm build), so it stays out of the CI chart.
96
+
-**tree-sitter** — `grammar.js` + a **structural**`queries/highlights.scm` + an external scanner for context-sensitive lexing. Builds end-to-end (tree-sitter's GLR absorbs the grammar; compiles to wasm) and the *derived* query scores **95.3%** through the same oracle as the chart above — **above the official parsers** (tree-sitter 92.7%, Lezer 89.5%). Opt-in (needs a local wasm build), so it stays out of the CI chart.
97
97
-**Lezer** — a CodeMirror 6 grammar + `styleTags` + a JS tokenizer. Does **not** build: the grammar trips Lezer's **LR(1) shift/reduce wall** (TypeScript's `<` type-vs-expression ambiguity, which `tsc` resolves with semantic information LR(1) lacks). That's a ceiling of Lezer's parser class rather than a gap in the grammar — so there is no derived Lezer highlighter number.
98
98
-**Monarch** — a Monaco (web) tokenizer (functional, bounded by JS-regex limits).
0 commit comments