Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion crates/oxc_formatter/src/service/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ pub fn get_parse_options() -> ParseOptions {
allow_v8_intrinsics: true,
// `oxc_formatter` expects this to be `false`, otherwise panics
preserve_parens: false,
collect_tokens: false,
}
}

Expand Down
166 changes: 166 additions & 0 deletions crates/oxc_parser/src/config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
// All methods are `#[inline(always)]` to ensure compiler removes dead code resulting from static values
#![expect(clippy::inline_always)]

use std::ops::Index;

use crate::lexer::{ByteHandler, ByteHandlers, byte_handler_tables};

/// Parser config.
///
/// The purpose of parser config (as opposed to `ParseOptions`) is to allow setting options at either
/// compile time or runtime.
///
/// 3 configs are provided:
/// * [`NoTokensParserConfig`]: Parse without tokens, static (default)
/// * [`TokensParserConfig`]: Parse with tokens, static
/// * [`RuntimeParserConfig`]: Parse with or without tokens, decided at runtime
///
/// The trade-off is:
///
/// * The 2 static configs will produce better performance, because compiler can remove code that relates
/// to the other option as dead code, and remove branches.
///
/// * The runtime config will produce a smaller binary than using 2 different configs in the same application,
/// which would cause 2 polymorphic variants of the parser to be compiled.
///
/// Advised usage:
/// * If your application uses only a specific set of options, use a static config.
/// * If your application uses multiple sets of options, probably a runtime config is preferable.
///
/// At present the only option controlled by `ParserConfig` is whether to parse with or without tokens.
/// Other options will be added in future.
///
/// You can also create your own config by implementing [`ParserConfig`] on a type.
pub trait ParserConfig: Default {
type LexerConfig: LexerConfig;

fn lexer_config(&self) -> Self::LexerConfig;
}

/// Parser config for parsing without tokens (default).
///
/// See [`ParserConfig`] for more details.
#[derive(Copy, Clone, Default)]
pub struct NoTokensParserConfig;

impl ParserConfig for NoTokensParserConfig {
type LexerConfig = NoTokensLexerConfig;

#[inline(always)]
fn lexer_config(&self) -> NoTokensLexerConfig {
NoTokensLexerConfig
}
}

/// Parser config for parsing with tokens.
///
/// See [`ParserConfig`] for more details.
#[derive(Copy, Clone, Default)]
pub struct TokensParserConfig;

impl ParserConfig for TokensParserConfig {
type LexerConfig = TokensLexerConfig;

#[inline(always)]
fn lexer_config(&self) -> TokensLexerConfig {
TokensLexerConfig
}
}

/// Parser config for parsing with/without tokens, decided at runtime.
///
/// See [`ParserConfig`] for more details.
#[derive(Copy, Clone, Default)]
#[repr(transparent)]
pub struct RuntimeParserConfig {
lexer_config: RuntimeLexerConfig,
}

impl RuntimeParserConfig {
#[inline(always)]
pub fn new(tokens: bool) -> Self {
Self { lexer_config: RuntimeLexerConfig::new(tokens) }
}
}

impl ParserConfig for RuntimeParserConfig {
type LexerConfig = RuntimeLexerConfig;

#[inline(always)]
fn lexer_config(&self) -> RuntimeLexerConfig {
self.lexer_config
}
}

/// Lexer config.
pub trait LexerConfig: Default {
type ByteHandlers: Index<usize, Output = ByteHandler<Self>>;

fn tokens(&self) -> bool;

fn byte_handlers(&self) -> &Self::ByteHandlers;
}

/// Lexer config for lexing without tokens.
#[derive(Copy, Clone, Default)]
pub struct NoTokensLexerConfig;

impl LexerConfig for NoTokensLexerConfig {
type ByteHandlers = ByteHandlers<Self>;

#[inline(always)]
fn tokens(&self) -> bool {
false
}

#[inline(always)]
fn byte_handlers(&self) -> &Self::ByteHandlers {
&byte_handler_tables::NO_TOKENS
}
}

/// Lexer config for parsing with tokens.
#[derive(Copy, Clone, Default)]
pub struct TokensLexerConfig;

impl LexerConfig for TokensLexerConfig {
type ByteHandlers = ByteHandlers<Self>;

#[inline(always)]
fn tokens(&self) -> bool {
true
}

#[inline(always)]
fn byte_handlers(&self) -> &Self::ByteHandlers {
&byte_handler_tables::WITH_TOKENS
}
}

/// Lexer config for lexing with/without tokens, decided at runtime.
#[derive(Copy, Clone, Default)]
#[repr(transparent)]
pub struct RuntimeLexerConfig {
tokens: bool,
}

impl RuntimeLexerConfig {
#[inline(always)]
pub fn new(tokens: bool) -> Self {
Self { tokens }
}
}

impl LexerConfig for RuntimeLexerConfig {
type ByteHandlers = ByteHandlers<Self>;

#[inline(always)]
fn tokens(&self) -> bool {
self.tokens
}

#[inline(always)]
fn byte_handlers(&self) -> &Self::ByteHandlers {
&byte_handler_tables::RUNTIME_TOKENS
}
}
8 changes: 4 additions & 4 deletions crates/oxc_parser/src/cursor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use oxc_diagnostics::OxcDiagnostic;
use oxc_span::{GetSpan, Span};

use crate::{
Context, ParserImpl, diagnostics,
Context, ParserConfig as Config, ParserImpl, diagnostics,
error_handler::FatalError,
lexer::{Kind, LexerCheckpoint, LexerContext, Token},
};
Expand All @@ -20,7 +20,7 @@ pub struct ParserCheckpoint<'a> {
fatal_error: Option<FatalError>,
}

impl<'a> ParserImpl<'a> {
impl<'a, C: Config> ParserImpl<'a, C> {
#[inline]
pub(crate) fn start_span(&self) -> u32 {
self.token.start()
Expand Down Expand Up @@ -327,7 +327,7 @@ impl<'a> ParserImpl<'a> {

pub(crate) fn try_parse<T>(
&mut self,
func: impl FnOnce(&mut ParserImpl<'a>) -> T,
func: impl FnOnce(&mut ParserImpl<'a, C>) -> T,
) -> Option<T> {
let checkpoint = self.checkpoint_with_error_recovery();
let ctx = self.ctx;
Expand All @@ -341,7 +341,7 @@ impl<'a> ParserImpl<'a> {
}
}

pub(crate) fn lookahead<U>(&mut self, predicate: impl Fn(&mut ParserImpl<'a>) -> U) -> U {
pub(crate) fn lookahead<U>(&mut self, predicate: impl Fn(&mut ParserImpl<'a, C>) -> U) -> U {
let checkpoint = self.checkpoint();
let answer = predicate(self);
self.rewind(checkpoint);
Expand Down
6 changes: 3 additions & 3 deletions crates/oxc_parser/src/error_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use oxc_allocator::Dummy;
use oxc_diagnostics::OxcDiagnostic;
use oxc_span::Span;

use crate::{ParserImpl, diagnostics, lexer::Kind};
use crate::{ParserConfig as Config, ParserImpl, diagnostics, lexer::Kind};

/// Fatal parsing error.
#[derive(Debug, Clone)]
Expand All @@ -15,7 +15,7 @@ pub struct FatalError {
pub errors_len: usize,
}

impl<'a> ParserImpl<'a> {
impl<'a, C: Config> ParserImpl<'a, C> {
#[cold]
pub(crate) fn set_unexpected(&mut self) {
// The lexer should have reported a more meaningful diagnostic
Expand Down Expand Up @@ -105,7 +105,7 @@ impl<'a> ParserImpl<'a> {
// error, we detect these patterns and provide helpful guidance on how to resolve the conflict.
//
// Inspired by rust-lang/rust#106242
impl ParserImpl<'_> {
impl<C: Config> ParserImpl<'_, C> {
/// Check if the current position looks like a merge conflict marker.
///
/// Detects the following Git conflict markers:
Expand Down
4 changes: 2 additions & 2 deletions crates/oxc_parser/src/js/arrow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use oxc_span::{FileExtension, GetSpan};
use oxc_syntax::precedence::Precedence;

use super::{FunctionKind, Tristate};
use crate::{Context, ParserImpl, diagnostics, lexer::Kind};
use crate::{Context, ParserConfig as Config, ParserImpl, diagnostics, lexer::Kind};

struct ArrowFunctionHead<'a> {
type_parameters: Option<Box<'a, TSTypeParameterDeclaration<'a>>>,
Expand All @@ -14,7 +14,7 @@ struct ArrowFunctionHead<'a> {
span: u32,
}

impl<'a> ParserImpl<'a> {
impl<'a, C: Config> ParserImpl<'a, C> {
pub(super) fn try_parse_parenthesized_arrow_function_expression(
&mut self,
allow_return_type_in_arrow_function: bool,
Expand Down
4 changes: 2 additions & 2 deletions crates/oxc_parser/src/js/binding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ use oxc_allocator::Box;
use oxc_ast::ast::*;
use oxc_span::GetSpan;

use crate::{Context, ParserImpl, diagnostics, lexer::Kind};
use crate::{Context, ParserConfig as Config, ParserImpl, diagnostics, lexer::Kind};

impl<'a> ParserImpl<'a> {
impl<'a, C: Config> ParserImpl<'a, C> {
/// `BindingElement`
/// `SingleNameBinding`
/// `BindingPattern`[?Yield, ?Await] `Initializer`[+In, ?Yield, ?Await]opt
Expand Down
4 changes: 2 additions & 2 deletions crates/oxc_parser/src/js/class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use oxc_ecmascript::PropName;
use oxc_span::{GetSpan, Span};

use crate::{
Context, ParserImpl, StatementContext, diagnostics,
Context, ParserConfig as Config, ParserImpl, StatementContext, diagnostics,
lexer::Kind,
modifiers::{ModifierFlags, ModifierKind, Modifiers},
};
Expand All @@ -14,7 +14,7 @@ use super::FunctionKind;
type ImplementsWithKeywordSpan<'a> = (Span, Vec<'a, TSClassImplements<'a>>);

/// Section 15.7 Class Definitions
impl<'a> ParserImpl<'a> {
impl<'a, C: Config> ParserImpl<'a, C> {
// `start_span` points at the start of all decoractors and `class` keyword.
pub(crate) fn parse_class_statement(
&mut self,
Expand Down
4 changes: 2 additions & 2 deletions crates/oxc_parser/src/js/declaration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ use oxc_ast::ast::*;
use oxc_span::GetSpan;

use super::VariableDeclarationParent;
use crate::{ParserImpl, StatementContext, diagnostics, lexer::Kind};
use crate::{ParserConfig as Config, ParserImpl, StatementContext, diagnostics, lexer::Kind};

impl<'a> ParserImpl<'a> {
impl<'a, C: Config> ParserImpl<'a, C> {
pub(crate) fn parse_let(&mut self, stmt_ctx: StatementContext) -> Statement<'a> {
let span = self.start_span();

Expand Down
4 changes: 2 additions & 2 deletions crates/oxc_parser/src/js/expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@ use super::{
},
};
use crate::{
Context, ParserImpl, diagnostics,
Context, ParserConfig as Config, ParserImpl, diagnostics,
lexer::{Kind, parse_big_int, parse_float, parse_int},
modifiers::Modifiers,
};

impl<'a> ParserImpl<'a> {
impl<'a, C: Config> ParserImpl<'a, C> {
pub(crate) fn parse_paren_expression(&mut self) -> Expression<'a> {
let opening_span = self.cur_token().span();
self.expect(Kind::LParen);
Expand Down
4 changes: 2 additions & 2 deletions crates/oxc_parser/src/js/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use oxc_span::{GetSpan, Span};

use super::FunctionKind;
use crate::{
Context, ParserImpl, StatementContext, diagnostics,
Context, ParserConfig as Config, ParserImpl, StatementContext, diagnostics,
lexer::Kind,
modifiers::{ModifierFlags, ModifierKind, Modifiers},
};
Expand All @@ -19,7 +19,7 @@ impl FunctionKind {
}
}

impl<'a> ParserImpl<'a> {
impl<'a, C: Config> ParserImpl<'a, C> {
pub(crate) fn at_function_with_async(&mut self) -> bool {
self.at(Kind::Function)
|| self.at(Kind::Async) && {
Expand Down
Loading
Loading