Skip to content

Arquitetura do parser

O Oxc mantém AST e parser próprios — hoje são, em Rust, o conjunto mais rápido e alinhado à spec para JavaScript e TypeScript (incluindo JSX/TSX).

Como parser costuma ser gargalo, ganhos pequenos propagam ao restante da toolchain.

Filosofia do AST

Ferramentas costumam seguir estree, mas esse modelo mistura nós ambíguos.

O AST do Oxc remove ambiguidades e especializa tipos: em vez de um Identifier genérico, há BindingIdentifier, IdentifierReference, IdentifierName — bem mais próximo da ECMAScript.

Tipos de nó

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>,
}

Clareza semântica

  • BindingIdentifier — declaração (let x = 1)
  • IdentifierReference — uso (console.log(x))
  • IdentifierName — nome de propriedade (obj.property)

Performance

Por que é rápido

  • Arena de memória — AST na arena bumpalo
  • Strings curtas inlined via compact_str
  • Poucas alocações além dessas duas estratégias
  • Parser “fino”: escopo, resolução e parte dos erros vão ao analisador semântico

Arena

rust
use oxc_allocator::Allocator;

let allocator = Allocator::default();
let ast_node = allocator.alloc(Expression::NumericLiteral(
    allocator.alloc(NumericLiteral { value: 42.0, span: SPAN })
));
  • alocação O(1); liberação O(1) soltando a arena inteira
  • layout linear otimiza cache

Strings com CompactString

rust
let short_name = CompactString::from("variableName");
let long_name = CompactString::from("a_very_long_variable_name_that_exceeds_limit");

Maioria dos identificadores e literais sai sem heap extra.

Arquitetura de parsing

Duas fases

  1. Parse — árvore com semântica mínima
  2. Semântico — escopos, símbolos, checagens avançadas
rust
let parser_result = Parser::new(&allocator, &source_text, source_type).parse();

let semantic_result = SemanticBuilder::new()
    .with_check_syntax_error(true)
    .build(&parser_result.program);

Componentes

Lexer

  • texto → tokens
  • SIMD no salto de brancos
  • desambigua / contra regex

Parser recursivo

  • código manual
  • recuperação com mensagens úteis
  • em linha com a gramática oficial

Builder de AST

  • tipagem forte Rust
  • nós sempre na arena
  • métodos ergonômicos de montagem

Conformidade

  • Test262 ECMAScript
  • Babel — ~99.62% compat com testes de parser
  • TypeScript compiler — ~99.86%

Erros (OxcDiagnostic)

rust
pub struct OxcDiagnostic {
    pub message: String,
    pub span: Span,
    pub severity: Severity,
    pub help: Option<String>,
}

Posições exatas, continua mesmo com erro, sugestões.

Funcionalidades avançadas

TypeScript

  • remoção de tipos só na sintaxe
  • decorators experimentais
  • namespaces / módulos
  • JSX (TSX)

Pesquisa

SIMD em texto; cache locality; ramos quentes previsíveis; reduzir cópias de string para “zero-copy” onde possível