本页目录
Parser & AST
@skill-wiki/parser 是手写的递归下降 parser。约 1.5k 行代码、125 个测试,
除 typescript 以外零依赖。它产出一个带类型的 AST,工具链其它部分都吃这个。
Lexer
Lexer 读 .prime 源码,吐出一串 token。token 的种类有:关键字(每种 kind 一个)、
标点({ } [ ] : ,)、标识符(@scope/name)、
字符串、数字和注释。
// 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[] };
递归下降
parser 有 6 个入口,剩下都是直白的下降:
错误报告
解析报错带行号,加上一段位置区间,把出错的文本高亮出来:
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 为什么手写
parser 生成器(Tree-sitter、ANTLR、peg.js)都会拖一份运行时依赖,错误信息也含混。 Skill Wiki 的语法足够小(28 个关键字、14 个 verb 字段名、约 6 类标点), 递归下降比生成版本反而更短 —— 错误信息也更对作者友好。
性能
解析 frontend-design Prime(898 个原子,源码约 3 MB),M1 上约 140 ms, 每个原子约 150 µs。L1 检查器再加约 100 ms。 哪怕语料涨到现在的 10 倍,编译时间也不是瓶颈。