mirror of
https://github.com/danbulant/oxc
synced 2026-05-25 04:42:10 +00:00
refactor(parser): parse BigInt lazily (#1924)
This PR partially fixes #1803 and is part of #1880. BigInt is removed from the `Token` value, so that the token size can be reduced once we removed all the variants. `Token` is now also `Copy`, which removes all the `clone` and `drop` calls. This yields 5% performance improvement for the parser.
This commit is contained in:
parent
149f53edd6
commit
7eb2573178
4 changed files with 21 additions and 25 deletions
|
|
@ -236,7 +236,7 @@ impl<'a> Parser<'a> {
|
||||||
pub(crate) fn checkpoint(&self) -> ParserCheckpoint<'a> {
|
pub(crate) fn checkpoint(&self) -> ParserCheckpoint<'a> {
|
||||||
ParserCheckpoint {
|
ParserCheckpoint {
|
||||||
lexer: self.lexer.checkpoint(),
|
lexer: self.lexer.checkpoint(),
|
||||||
cur_token: self.token.clone(),
|
cur_token: self.token,
|
||||||
prev_span_end: self.prev_token_end,
|
prev_span_end: self.prev_token_end,
|
||||||
errors_pos: self.errors.len(),
|
errors_pos: self.errors.len(),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ use super::{
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
diagnostics,
|
diagnostics,
|
||||||
|
lexer::parse_big_int,
|
||||||
lexer::{Kind, TokenValue},
|
lexer::{Kind, TokenValue},
|
||||||
list::SeparatedList,
|
list::SeparatedList,
|
||||||
Context, Parser,
|
Context, Parser,
|
||||||
|
|
@ -306,12 +307,12 @@ impl<'a> Parser<'a> {
|
||||||
Kind::Hex => BigintBase::Hex,
|
Kind::Hex => BigintBase::Hex,
|
||||||
_ => return Err(self.unexpected()),
|
_ => return Err(self.unexpected()),
|
||||||
};
|
};
|
||||||
let value = match self.cur_kind() {
|
let token = self.cur_token();
|
||||||
kind if kind.is_number() => self.cur_token().value.as_bigint(),
|
let src = self.cur_src().strip_suffix('n').unwrap();
|
||||||
_ => return Err(self.unexpected()),
|
let value = parse_big_int(src, token.kind)
|
||||||
};
|
.map_err(|err| diagnostics::InvalidNumber(err, token.span()))?;
|
||||||
self.bump_any();
|
self.bump_any();
|
||||||
Ok(BigintLiteral { span: self.end_span(span), value, base })
|
Ok(self.ast.bigint_literal(self.end_span(span), value, base))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn parse_literal_regexp(&mut self) -> Result<RegExpLiteral> {
|
pub(crate) fn parse_literal_regexp(&mut self) -> Result<RegExpLiteral> {
|
||||||
|
|
|
||||||
|
|
@ -26,9 +26,9 @@ use oxc_syntax::{
|
||||||
};
|
};
|
||||||
pub use token::{RegExp, Token, TokenValue};
|
pub use token::{RegExp, Token, TokenValue};
|
||||||
|
|
||||||
pub use self::kind::Kind;
|
pub use self::{kind::Kind, number::parse_big_int};
|
||||||
use self::{
|
use self::{
|
||||||
number::{parse_big_int, parse_float, parse_int},
|
number::{parse_float, parse_int},
|
||||||
string_builder::AutoCow,
|
string_builder::AutoCow,
|
||||||
trivia_builder::TriviaBuilder,
|
trivia_builder::TriviaBuilder,
|
||||||
};
|
};
|
||||||
|
|
@ -105,7 +105,7 @@ impl<'a> Lexer<'a> {
|
||||||
pub fn checkpoint(&self) -> LexerCheckpoint<'a> {
|
pub fn checkpoint(&self) -> LexerCheckpoint<'a> {
|
||||||
LexerCheckpoint {
|
LexerCheckpoint {
|
||||||
chars: self.current.chars.clone(),
|
chars: self.current.chars.clone(),
|
||||||
token: self.current.token.clone(),
|
token: self.current.token,
|
||||||
errors_pos: self.errors.len(),
|
errors_pos: self.errors.len(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -178,7 +178,9 @@ impl<'a> Lexer<'a> {
|
||||||
self.current.token.kind = kind;
|
self.current.token.kind = kind;
|
||||||
self.current.token.end = self.offset();
|
self.current.token.end = self.offset();
|
||||||
debug_assert!(self.current.token.start <= self.current.token.end);
|
debug_assert!(self.current.token.start <= self.current.token.end);
|
||||||
std::mem::take(&mut self.current.token)
|
let token = self.current.token;
|
||||||
|
self.current.token = Token::default();
|
||||||
|
token
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Re-tokenize the current `/` or `/=` and return `RegExp`
|
/// Re-tokenize the current `/` or `/=` and return `RegExp`
|
||||||
|
|
@ -299,10 +301,11 @@ impl<'a> Lexer<'a> {
|
||||||
fn set_numeric_value(&mut self, kind: Kind, src: &'a str) {
|
fn set_numeric_value(&mut self, kind: Kind, src: &'a str) {
|
||||||
let value = match kind {
|
let value = match kind {
|
||||||
Kind::Decimal | Kind::Binary | Kind::Octal | Kind::Hex => {
|
Kind::Decimal | Kind::Binary | Kind::Octal | Kind::Hex => {
|
||||||
src.strip_suffix('n').map_or_else(
|
if src.ends_with('n') {
|
||||||
|| parse_int(src, kind).map(TokenValue::Number),
|
// BigInt is parsed lazily in the parser
|
||||||
|src| parse_big_int(src, kind).map(TokenValue::BigInt),
|
return;
|
||||||
)
|
}
|
||||||
|
parse_int(src, kind).map(TokenValue::Number)
|
||||||
}
|
}
|
||||||
Kind::Float | Kind::PositiveExponential | Kind::NegativeExponential => {
|
Kind::Float | Kind::PositiveExponential | Kind::NegativeExponential => {
|
||||||
parse_float(src).map(TokenValue::Number)
|
parse_float(src).map(TokenValue::Number)
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ use oxc_span::Span;
|
||||||
|
|
||||||
use super::kind::Kind;
|
use super::kind::Kind;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default)]
|
#[derive(Debug, Clone, Copy, Default)]
|
||||||
pub struct Token<'a> {
|
pub struct Token<'a> {
|
||||||
/// Token Kind
|
/// Token Kind
|
||||||
pub kind: Kind,
|
pub kind: Kind,
|
||||||
|
|
@ -38,16 +38,15 @@ impl<'a> Token<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub enum TokenValue<'a> {
|
pub enum TokenValue<'a> {
|
||||||
None,
|
None,
|
||||||
Number(f64),
|
Number(f64),
|
||||||
BigInt(num_bigint::BigInt),
|
|
||||||
String(&'a str),
|
String(&'a str),
|
||||||
RegExp(RegExp<'a>),
|
RegExp(RegExp<'a>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub struct RegExp<'a> {
|
pub struct RegExp<'a> {
|
||||||
pub pattern: &'a str,
|
pub pattern: &'a str,
|
||||||
pub flags: RegExpFlags,
|
pub flags: RegExpFlags,
|
||||||
|
|
@ -67,13 +66,6 @@ impl<'a> TokenValue<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_bigint(&self) -> num_bigint::BigInt {
|
|
||||||
match self {
|
|
||||||
Self::BigInt(s) => s.clone(),
|
|
||||||
_ => unreachable!("expected bigint!"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn as_regex(&self) -> &RegExp<'a> {
|
pub fn as_regex(&self) -> &RegExp<'a> {
|
||||||
match self {
|
match self {
|
||||||
Self::RegExp(regex) => regex,
|
Self::RegExp(regex) => regex,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue