Skip to content

Commit 4304f91

Browse files
authored
perf(es/parser): Reduce query ops of current token (#10766)
1 parent 4124ac1 commit 4304f91

File tree

5 files changed

+108
-94
lines changed

5 files changed

+108
-94
lines changed

.changeset/clean-deers-ring.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
swc_ecma_lexer: patch
3+
swc_ecma_parser: patch
4+
swc_core: minor
5+
---
6+
7+
pref(ecma/parser): less query cur

crates/swc_ecma_lexer/src/common/parser/expr.rs

Lines changed: 22 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ use crate::{
2727
object::parse_object_expr,
2828
pat::{parse_paren_items_as_params, reparse_expr_as_pat},
2929
pat_type::PatType,
30+
token_and_span::TokenAndSpan,
3031
typescript::*,
3132
unwrap_ts_non_null,
3233
},
@@ -1499,12 +1500,16 @@ fn parse_bin_op_recursively_inner<'a, P: Parser<'a>>(
14991500
/// spec: 'UnaryExpression'
15001501
pub(crate) fn parse_unary_expr<'a, P: Parser<'a>>(p: &mut P) -> PResult<Box<Expr>> {
15011502
trace_cur!(p, parse_unary_expr);
1502-
let start = p.cur_pos();
15031503

1504-
if !p.input().syntax().jsx()
1505-
&& p.input().syntax().typescript()
1506-
&& p.input_mut().eat(&P::Token::LESS)
1507-
{
1504+
p.input_mut().cur();
1505+
let Some(token_and_span) = p.input().get_cur() else {
1506+
syntax_error!(p, p.input().cur_span(), SyntaxError::TS1109);
1507+
};
1508+
let start = token_and_span.span().lo;
1509+
let cur = token_and_span.token();
1510+
1511+
if !p.input().syntax().jsx() && p.input().syntax().typescript() && cur.is_less() {
1512+
p.bump(); // consume `<`
15081513
if p.input_mut().eat(&P::Token::CONST) {
15091514
expect!(p, &P::Token::GREATER);
15101515
let expr = p.parse_unary_expr()?;
@@ -1518,10 +1523,8 @@ pub(crate) fn parse_unary_expr<'a, P: Parser<'a>>(p: &mut P) -> PResult<Box<Expr
15181523
return parse_ts_type_assertion(p, start)
15191524
.map(Expr::from)
15201525
.map(Box::new);
1521-
}
1522-
1523-
// Parse update expression
1524-
if p.input_mut().is(&P::Token::PLUS_PLUS) || p.input_mut().is(&P::Token::MINUS_MINUS) {
1526+
} else if cur.is_plus_plus() || cur.is_minus_minus() {
1527+
// Parse update expression
15251528
let op = if p.bump() == P::Token::PLUS_PLUS {
15261529
op!("++")
15271530
} else {
@@ -1539,19 +1542,15 @@ pub(crate) fn parse_unary_expr<'a, P: Parser<'a>>(p: &mut P) -> PResult<Box<Expr
15391542
arg,
15401543
}
15411544
.into());
1542-
}
1543-
1544-
// Parse unary expression
1545-
1546-
if p.input_mut().cur().is_some_and(|cur| {
1547-
cur.is_delete()
1548-
|| cur.is_void()
1549-
|| cur.is_typeof()
1550-
|| cur.is_plus()
1551-
|| cur.is_minus()
1552-
|| cur.is_tilde()
1553-
|| cur.is_bang()
1554-
}) {
1545+
} else if cur.is_delete()
1546+
|| cur.is_void()
1547+
|| cur.is_typeof()
1548+
|| cur.is_plus()
1549+
|| cur.is_minus()
1550+
|| cur.is_tilde()
1551+
|| cur.is_bang()
1552+
{
1553+
// Parse unary expression
15551554
let cur = p.bump();
15561555
let op = if cur.is_delete() {
15571556
op!("delete")
@@ -1593,9 +1592,7 @@ pub(crate) fn parse_unary_expr<'a, P: Parser<'a>>(p: &mut P) -> PResult<Box<Expr
15931592
arg,
15941593
}
15951594
.into());
1596-
}
1597-
1598-
if p.input_mut().is(&P::Token::AWAIT) {
1595+
} else if cur.is_await() {
15991596
return parse_await_expr(p, None);
16001597
}
16011598

crates/swc_ecma_lexer/src/common/parser/ident.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@ use swc_ecma_ast::*;
55

66
use super::{buffer::Buffer, expr::parse_str_lit, PResult, Parser};
77
use crate::{
8-
common::{context::Context, lexer::token::TokenFactory, parser::eof_error},
8+
common::{
9+
context::Context,
10+
lexer::token::TokenFactory,
11+
parser::{eof_error, token_and_span::TokenAndSpan},
12+
},
913
error::SyntaxError,
1014
};
1115

@@ -27,10 +31,12 @@ pub fn parse_module_export_name<'a, P: Parser<'a>>(p: &mut P) -> PResult<ModuleE
2731
/// Use this when spec says "IdentifierName".
2832
/// This allows idents like `catch`.
2933
pub fn parse_ident_name<'a, P: Parser<'a>>(p: &mut P) -> PResult<IdentName> {
30-
let start = p.cur_pos();
31-
let Some(cur) = p.input_mut().cur() else {
34+
p.input_mut().cur();
35+
let Some(token_and_span) = p.input().get_cur() else {
3236
return Err(eof_error(p));
3337
};
38+
let start = token_and_span.span().lo;
39+
let cur = token_and_span.token();
3440
let w = if cur.is_word() {
3541
let t = p.bump();
3642
t.take_word(p.input_mut()).unwrap()

crates/swc_ecma_lexer/src/common/parser/stmt.rs

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1385,15 +1385,18 @@ pub(super) fn parse_block_body<'a, P: Parser<'a>, Type: IsDirective + From<Stmt>
13851385

13861386
let stmts = Arena::new();
13871387
while {
1388-
if p.input_mut().cur().is_none() && end.is_some() {
1389-
let eof_text = p.input_mut().dump_cur();
1390-
p.emit_err(
1391-
p.input().cur_span(),
1392-
SyntaxError::Expected(format!("{:?}", end.unwrap()), eof_text),
1393-
);
1394-
false
1395-
} else {
1396-
p.input_mut().cur() != end
1388+
match (p.input_mut().cur(), end) {
1389+
(Some(cur), Some(end)) => cur != end,
1390+
(Some(_), None) => true,
1391+
(None, None) => false,
1392+
(None, Some(_)) => {
1393+
let eof_text = p.input_mut().dump_cur();
1394+
p.emit_err(
1395+
p.input().cur_span(),
1396+
SyntaxError::Expected(format!("{:?}", end.unwrap()), eof_text),
1397+
);
1398+
false
1399+
}
13971400
}
13981401
} {
13991402
let stmt = parse_stmt_like(p, true, &handle_import_export)?;

crates/swc_ecma_parser/src/parser/expr.rs

Lines changed: 58 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,19 @@
11
use either::Either;
22
use swc_common::{BytePos, Span, Spanned};
33
use swc_ecma_lexer::{
4-
common::parser::{
5-
class_and_fn::parse_fn_expr,
6-
expr::{
7-
parse_array_lit, parse_await_expr, parse_lit, parse_member_expr_or_new_expr,
8-
parse_paren_expr_or_arrow_fn, parse_primary_expr_rest, parse_this_expr,
9-
try_parse_async_start, try_parse_regexp,
4+
common::{
5+
lexer::token::TokenFactory,
6+
parser::{
7+
class_and_fn::parse_fn_expr,
8+
expr::{
9+
parse_array_lit, parse_await_expr, parse_lit, parse_member_expr_or_new_expr,
10+
parse_paren_expr_or_arrow_fn, parse_primary_expr_rest, parse_this_expr,
11+
try_parse_async_start, try_parse_regexp,
12+
},
13+
object::parse_object_expr,
14+
token_and_span::TokenAndSpan,
15+
typescript::parse_ts_type_assertion,
1016
},
11-
object::parse_object_expr,
12-
typescript::parse_ts_type_assertion,
1317
},
1418
error::SyntaxError,
1519
};
@@ -34,41 +38,44 @@ impl<I: Tokens> Parser<I> {
3438

3539
pub(super) fn parse_unary_expr(&mut self) -> PResult<Box<Expr>> {
3640
trace_cur!(self, parse_unary_expr);
37-
let start = self.cur_pos();
38-
39-
if self.input_mut().cur().is_some_and(|cur| cur == &Token::Lt) {
40-
if self.input().syntax().typescript() && !self.input().syntax().jsx() {
41-
self.bump(); // consume `<`
42-
return if self.input_mut().eat(&Token::Const) {
43-
self.expect(&Token::Gt)?;
44-
let expr = self.parse_unary_expr()?;
45-
Ok(TsConstAssertion {
46-
span: self.span(start),
47-
expr,
48-
}
49-
.into())
50-
} else {
51-
parse_ts_type_assertion(self, start)
52-
.map(Expr::from)
53-
.map(Box::new)
54-
};
55-
} else if self.input().syntax().jsx()
56-
&& self.input_mut().peek().is_some_and(|peek| {
57-
(*peek).is_word() || peek == &Token::Gt || peek.should_rescan_into_gt_in_jsx()
58-
})
59-
{
60-
fn into_expr(e: Either<JSXFragment, JSXElement>) -> Box<Expr> {
61-
match e {
62-
Either::Left(l) => l.into(),
63-
Either::Right(r) => r.into(),
64-
}
41+
42+
self.input_mut().cur();
43+
let Some(token_and_span) = self.input().get_cur() else {
44+
syntax_error!(self, self.input().cur_span(), SyntaxError::TS1109);
45+
};
46+
let start = token_and_span.span().lo;
47+
let cur = *token_and_span.token();
48+
49+
if cur == Token::Lt && self.input().syntax().typescript() && !self.input().syntax().jsx() {
50+
self.bump(); // consume `<`
51+
return if self.input_mut().eat(&Token::Const) {
52+
self.expect(&Token::Gt)?;
53+
let expr = self.parse_unary_expr()?;
54+
Ok(TsConstAssertion {
55+
span: self.span(start),
56+
expr,
57+
}
58+
.into())
59+
} else {
60+
parse_ts_type_assertion(self, start)
61+
.map(Expr::from)
62+
.map(Box::new)
63+
};
64+
} else if cur == Token::Lt
65+
&& self.input().syntax().jsx()
66+
&& self.input_mut().peek().is_some_and(|peek| {
67+
(*peek).is_word() || peek == &Token::Gt || peek.should_rescan_into_gt_in_jsx()
68+
})
69+
{
70+
fn into_expr(e: Either<JSXFragment, JSXElement>) -> Box<Expr> {
71+
match e {
72+
Either::Left(l) => l.into(),
73+
Either::Right(r) => r.into(),
6574
}
66-
return self.parse_jsx_element(true).map(into_expr);
6775
}
68-
}
69-
70-
// Parse update expression
71-
if self.input_mut().is(&Token::PlusPlus) || self.input_mut().is(&Token::MinusMinus) {
76+
return self.parse_jsx_element(true).map(into_expr);
77+
} else if matches!(cur, Token::PlusPlus | Token::MinusMinus) {
78+
// Parse update expression
7279
let op = if self.bump() == Token::PlusPlus {
7380
op!("++")
7481
} else {
@@ -86,19 +93,15 @@ impl<I: Tokens> Parser<I> {
8693
arg,
8794
}
8895
.into());
89-
}
90-
91-
// Parse unary expression
92-
93-
if self.input_mut().cur().is_some_and(|cur| {
94-
cur == &Token::Delete
95-
|| cur == &Token::Void
96-
|| cur == &Token::TypeOf
97-
|| cur == &Token::Plus
98-
|| cur == &Token::Minus
99-
|| cur == &Token::Tilde
100-
|| cur == &Token::Bang
101-
}) {
96+
} else if cur == Token::Delete
97+
|| cur == Token::Void
98+
|| cur == Token::TypeOf
99+
|| cur == Token::Plus
100+
|| cur == Token::Minus
101+
|| cur == Token::Tilde
102+
|| cur == Token::Bang
103+
{
104+
// Parse unary expression
102105
let cur = self.bump();
103106
let op = if cur == Token::Delete {
104107
op!("delete")
@@ -140,9 +143,7 @@ impl<I: Tokens> Parser<I> {
140143
arg,
141144
}
142145
.into());
143-
}
144-
145-
if self.input_mut().is(&Token::Await) {
146+
} else if cur == Token::Await {
146147
return parse_await_expr(self, None);
147148
}
148149

0 commit comments

Comments
 (0)