Skill Wiki v0.1.0

文档 / implementation / parser

本页目录

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 倍,编译时间也不是瓶颈。