On this page
Parser & AST
@skill-wiki/parser is a hand-written recursive-descent parser. ~1.5k
LOC; 125 tests; zero dependencies beyond typescript. It produces a
typed AST that the rest of the toolchain consumes.
Lexer
The lexer reads .prime source and emits a token stream. Tokens
include keywords (one per kind), punctuation ({ } [ ] : ,),
identifiers (@scope/name), strings, numbers, and comments.
// packages/parser/src/lexer.ts
export type Token =
| { kind: 'keyword'; value: string; line: number }
| { kind: 'identifier'; value: string; line: number }
| { kind: 'atom-id'; value: string; line: number } // "@scope/name"
| { kind: 'string'; value: string; line: number }
| { kind: 'number'; value: number; line: number }
| { kind: 'punct'; value: string; line: number }
| { kind: 'eof' }; AST
// packages/types/src/ast.ts
export interface PrimeAST {
atoms: AtomDeclaration[];
}
export interface AtomDeclaration {
kind: AtomKind; // one of 28
name: string; // PascalCase
fields: FieldNode[];
}
export interface FieldNode {
name: string; // "id" | "version" | "claim" | "requires" | ...
value: ValueNode;
line: number;
}
export type ValueNode =
| { type: 'string'; value: string }
| { type: 'number'; value: number }
| { type: 'bool'; value: boolean }
| { type: 'atom-id'; value: string } // "@scope/name"
| { type: 'list'; items: ValueNode[] }
| { type: 'object'; fields: FieldNode[] };
Recursive descent
The parser has 6 entry points; the rest is straightforward descent:
Error reporting
Parse errors carry line numbers + a span to highlight the offending text:
Error: expected ',' or '}' before end of object body
at primes/sources/@my/rule-x.prime:14:6
12 | severity: critical
13 | requires: [@my/term-x
14 | }
^^
|
+— missing comma after list item or closing bracket Why hand-written?
Parser generators (Tree-sitter, ANTLR, peg.js) all add a runtime dependency and obscure error messages. Skill Wiki's grammar is small enough (28 keywords, 14 verb field names, ~6 punctuation classes) that recursive descent is shorter than the generated alternative — and the error messages are author-friendly.
Performance
Parsing the frontend-design Prime (898 atoms, ~3 MB of source) takes ~140 ms on M1. Per-atom: ~150 µs. The L1 checker adds another ~100 ms total. Compile time is not a bottleneck even at 10× the current corpus.