Parser 架构
Oxc 维护自建 AST 与 Parser,目前是 Rust 生态里速度与一致性表现最好的 JS/TS(含 JSX、TSX)解析器。
由于 Parser 经常是 JS 工具性能瓶颈, 任何微调都可能放大到下游链路;自研也让我们能系统性地尝试成熟性能手段。
AST 设计理念
诸多工具沿用 estree 形态,但它的节点往往含糊不清,开发时也更容易困惑。
Oxc AST 通过删除歧义节点、引入更清晰类型来改善这一点。 例如在 Identifier 上进一步拆成 BindingIdentifier、IdentifierReference、IdentifierName 等不同用途。
从而让 AST 语义更贴近 ECMAScript 条文,也方便工具作者理解。
AST 节点示例
rust
// Instead of generic Identifier
pub struct BindingIdentifier<'a> {
pub span: Span,
pub name: Atom<'a>,
}
pub struct IdentifierReference<'a> {
pub span: Span,
pub name: Atom<'a>,
pub reference_id: Cell<Option<ReferenceId>>,
}
pub struct IdentifierName<'a> {
pub span: Span,
pub name: Atom<'a>,
}语义清晰
三类用途区分如下:
BindingIdentifier:声明位置(如let x = 1)IdentifierReference:引用位置(如console.log(x))IdentifierName:属性名写法(如obj.property)
性能架构
为什么快
- 内存池:AST 存放在 memory arena(bumpalo) 以实现快速批量分配/回收。
- 字符串:短串通过 CompactString 内联。
- 堆分配:除了上述两类外尽量避免额外 malloc。
- 职责拆分:Scope、符号绑定与部分语法检查交给语义层处理,Parser 本体保持精炼。
Arena
rust
use oxc_allocator::Allocator;
// All AST nodes are allocated in this arena
let allocator = Allocator::default();
let ast_node = allocator.alloc(Expression::NumericLiteral(
allocator.alloc(NumericLiteral { value: 42.0, span: SPAN })
));优势:
- O(1) 分配:连续 bump pointer。
- O(1) 释放:整池释放即可。
- 缓存友好:连续内存布局、碎片少。
CompactString
rust
// Strings ≤ 24 bytes are stored inline (no heap allocation)
let short_name = CompactString::from("variableName"); // Stack allocated
let long_name = CompactString::from("a_very_long_variable_name_that_exceeds_limit"); // Heap allocated可显著减少对常见标识符/字面量的堆占用。
Parser 组成
两阶段流水线
- 解析阶段:只做结构建树,语义分析降到最低。
- 语义阶段:Scope/Symbol,以及更深入语法错误校验。
rust
// Phase 1: Parse to AST
let parser_result = Parser::new(&allocator, &source_text, source_type).parse();
// Phase 2: Semantic analysis
let semantic_result = SemanticBuilder::new()
.with_check_syntax_error(true)
.build(&parser_result.program);组件
Lexer
- 生成 Token
- SIMD 跳过空白提速
- 区分
/正则字面量与普通除法运算符
递归下降 Parser
- 手写实现以掌控性能上限
- 错误恢复并提供可读诊断
- 严格对齐 ECMAScript 条文
AST Builder
- 借用 Rust type system 守卫正确性
- 直接写入 arena
- Builder API 方便构造常用节点
兼容性策略
- Test262:ECMAScript 一致性通过率 100%
- Babel parser tests:≥99.6%
- TypeScript compiler tests:≥99.8%
诊断哲学
rust
pub struct OxcDiagnostic {
pub message: String,
pub span: Span,
pub severity: Severity,
pub help: Option<String>,
}目标是 精确定位、容错继续解析,以及给出 可行动的修复提示。
进阶特性概览
- TypeScript:
typestripping、experimental decorators、命名空间、*.tsx。 - 持续研究 SIMD 文本、
Zero-copy解析、缓存布局等方向。