파서 아키텍처
Oxc는 자체 AST와 파서를 유지하며, Rust로 작성된 JavaScript·TypeScript(JSX·TSX 포함) 파서 중 가장 빠르고 스펙 준수도가 높은 편입니다.
파서는 JS 툴링에서 흔히 핵심 병목이라, 사소한 개선도 다운스트림 도구에 연쇄 효과가 납니다. 자체 파서를 개발함으로써 잘 연구된 성능 기법을 적용·실험할 수 있습니다.
AST 설계 철학
많은 기존 도구가 AST 명세로 estree를 쓰지만, 모호한 노드가 많다는 단점이 있습니다. estree로 개발할 때 그 모호함 때문에 혼란이 자주 생깁니다.
Oxc AST는 estree와 달리 모호한 노드를 없애고 구분된 타입을 둡니다. 예를 들어 일반적인 estree Identifier 대신 BindingIdentifier, IdentifierReference, IdentifierName 같은 구체 타입을 제공합니다.
이 구분은 ECMAScript 명세와 더 잘 맞아 개발 경험을 크게 개선합니다.
AST 노드 타입
rust
// 일반 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를 메모리 아레나에 할당해 빠른 할당·해제
- 문자열 최적화: 짧은 문자열은 CompactString으로 인라인
- 힙 사용 최소화: 위 두 가지 외 추가 힙 할당 없음
- 관심사 분리: 스코프 바인딩·심볼 해석·일부 구문 오류는 의미 분석기에 위임
메모리 관리 세부
아레나 할당
rust
use oxc_allocator::Allocator;
// 모든 AST 노드는 이 아레나에 할당
let allocator = Allocator::default();
let ast_node = allocator.alloc(Expression::NumericLiteral(
allocator.alloc(NumericLiteral { value: 42.0, span: SPAN })
));장점:
- O(1) 할당: 단순 포인터 범프
- O(1) 해제: 아레나 전체를 한 번에 드롭
- 캐시 친화: 선형 메모리 배치
- 단편화 없음: 연속적인 메모리 사용
CompactString 문자열 인터닝
rust
// 길이 ≤ 24바이트 문자열은 인라인 저장(힙 할당 없음)
let short_name = CompactString::from("variableName"); // 스택
let long_name = CompactString::from("a_very_long_variable_name_that_exceeds_limit"); // 힙대부분의 JavaScript 식별자·문자열 리터럴에 대한 할당을 줄입니다.
파서 아키텍처
2단계 설계
Oxc 파서는 2단계를 따릅니다.
- 파싱 단계: 최소한의 의미 분석으로 AST 구조 구축
- 의미 단계: 스코프 분석·심볼 해석·고급 오류 검사
rust
// 1단계: AST 파싱
let parser_result = Parser::new(&allocator, &source_text, source_type).parse();
// 2단계: 의미 분석
let semantic_result = SemanticBuilder::new()
// 파서가 수행하지 않는 추가 구문 검사
.with_check_syntax_error(true)
.build(&parser_result.program);파서 구성 요소
렉서(Lexer)
- 토큰 생성: 소스 텍스트를 구조화된 토큰으로 변환
- SIMD 최적화: 공백 건너뛰기에 SIMD 사용
- 문맥 인식: 정규식과 나눗셈 연산자 모호성 처리
재귀 하강 파서
- 수작 구현: 최대 성능을 위해 직접 작성
- 오류 복구: 의미 있는 메시지와 함께 고급 오류 처리
- 문법 준수: ECMAScript 명세를 정확히 따름
AST 빌더
- 타입 안전: Rust 타입 시스템으로 정확성 확보
- 메모리 효율: 아레나 직접 할당
- 빌더 패턴: 노드 구성을 편하게 하는 메서드
적합성 전략
테스트 스위트 커버리지
- Test262: ECMAScript 적합성 테스트 100% 통과
- Babel: Babel 파서 테스트와 99.62% 호환
- TypeScript: TypeScript 컴파일러 테스트와 99.86% 호환
오류 처리 철학
rust
// 소스 위치가 있는 의미 있는 오류 메시지
pub struct OxcDiagnostic {
pub message: String,
pub span: Span,
pub severity: Severity,
pub help: Option<String>,
}파서가 제공하는 것:
- 정확한 오류 위치: 정확한 소스 위치
- 복구 전략: 오류 후에도 파싱 계속
- 실행 가능한 제안: 행동 가능한 오류 메시지
고급 기능
TypeScript 지원
- 타입 제거: TypeScript 전용 구문 제거
- 데코레이터 파싱: 실험적 데코레이터 처리
- Namespace 지원: 모듈·네임스페이스 파싱
- JSX 통합: TypeScript + JSX(TSX)
연구 영역
- SIMD 텍스트 처리: 벡터화 문자열 연산
- 캐시 최적화: 메모리 접근 패턴 최소화
- 분기 예측: 핫 파싱 경로 최적화
- 제로카피 파싱: 불필요한 문자열 복사 제거