refactor(es/parser): Improve readability (#9141)

This commit is contained in:
Donny/강동윤 2024-07-05 09:49:43 +09:00 committed by GitHub
parent 0d830ee3be
commit 9d9fe6625b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 110 additions and 77 deletions

View File

@ -745,7 +745,7 @@ impl<I: Tokens> Parser<I> {
}
trace_cur!(self, parse_class_member_with_is_static__normal_class_member);
let mut key = if readonly.is_some() && is_one_of!(self, '!', ':') {
let mut key = if readonly.is_some() && is!(self, '!' | ':') {
Key::Public(PropName::Ident(Ident::new(
"readonly".into(),
readonly.unwrap(),
@ -1155,8 +1155,8 @@ impl<I: Tokens> Parser<I> {
}
fn is_class_property(&mut self, asi: bool) -> bool {
(self.input.syntax().typescript() && is_one_of!(self, '!', ':'))
|| is_one_of!(self, '=', '}')
(self.input.syntax().typescript() && is!(self, '!' | ':'))
|| is!(self, '=' | '}')
|| if asi {
is!(self, ';')
} else {

View File

@ -82,7 +82,7 @@ impl<I: Tokens> Parser<I> {
let start = self.input.cur_span();
if self.input.syntax().typescript()
&& (is_one_of!(self, '<', JSXTagStart))
&& (is!(self, '<' | JSXTagStart))
&& (peeked_is!(self, IdentName) || peeked_is!(self, JSXName))
{
let ctx = Context {
@ -395,7 +395,7 @@ impl<I: Tokens> Parser<I> {
}
if is!(self, "let")
|| (self.input.syntax().typescript() && is_one_of!(self, IdentRef, "await"))
|| (self.input.syntax().typescript() && is!(self, IdentRef | "await"))
|| is!(self, IdentRef)
{
let ctx = self.ctx();
@ -1226,7 +1226,7 @@ impl<I: Tokens> Parser<I> {
)
.map(|expr| (Box::new(Expr::TaggedTpl(expr)), true))
.map(Some)
} else if is_one_of!(p, '=', "as") {
} else if is!(p, '=' | "as") {
Ok(Some((
Box::new(Expr::TsInstantiation(TsInstantiation {
span: span!(p, start),
@ -1258,7 +1258,7 @@ impl<I: Tokens> Parser<I> {
None
};
if obj.is_import() && !is_one_of!(self, '.', '(') {
if obj.is_import() && !is!(self, '.' | '(') {
unexpected!(self, "`.` or `(`")
}
@ -1597,7 +1597,7 @@ impl<I: Tokens> Parser<I> {
let callee = self.parse_new_expr()?;
return_if_arrow!(self, callee);
let type_args = if self.input.syntax().typescript() && is_one_of!(self, '<', "<<") {
let type_args = if self.input.syntax().typescript() && is!(self, '<' | "<<") {
self.try_parse_ts(|p| {
let type_args = p.parse_ts_type_args()?;
if is!(p, '(') {
@ -2145,18 +2145,44 @@ impl<I: Tokens> Parser<I> {
}
fn is_start_of_left_hand_side_expr(&mut self) -> PResult<bool> {
Ok(is_one_of!(
self, "this", "super", "null", "true", "false", Num, BigInt, Str, '`', '(', '[', '{',
"function", "class", "new", Regex, IdentRef
Ok(is!(
self,
"this"
| "super"
| "null"
| "true"
| "false"
| Num
| BigInt
| Str
| '`'
| '('
| '['
| '{'
| "function"
| "class"
| "new"
| Regex
| IdentRef
) || (is!(self, "import")
&& (peeked_is!(self, '(') || peeked_is!(self, '<') || peeked_is!(self, '.'))))
}
pub(super) fn is_start_of_expr(&mut self) -> PResult<bool> {
Ok(self.is_start_of_left_hand_side_expr()?
|| is_one_of!(
self, '+', '-', '~', '!', "delete", "typeof", "void", "++", "--", '<', "await",
"yield"
|| is!(
self,
'+' | '-'
| '~'
| '!'
| "delete"
| "typeof"
| "void"
| "++"
| "--"
| '<'
| "await"
| "yield"
)
|| (is!(self, '#') && peeked_is!(self, IdentName)))
}

View File

@ -281,7 +281,7 @@ impl<I: Tokens> Parser<I> {
}
// Parse unary expression
if is_one_of!(self, "delete", "void", "typeof", '+', '-', '~', '!') {
if is!(self, "delete" | "void" | "typeof" | '+' | '-' | '~' | '!') {
let op = match bump!(self) {
tok!("delete") => op!("delete"),
tok!("void") => op!("void"),
@ -341,7 +341,7 @@ impl<I: Tokens> Parser<I> {
return Ok(expr);
}
if is_one_of!(self, "++", "--") {
if is!(self, "++" | "--") {
self.check_assign_target(&expr, false);
let op = if bump!(self) == tok!("++") {
@ -378,7 +378,7 @@ impl<I: Tokens> Parser<I> {
let span = span!(self, start);
if is_one_of!(self, ')', ']', ';', ',') && !ctx.in_async {
if is!(self, ')' | ']' | ';' | ',') && !ctx.in_async {
if ctx.module {
self.emit_err(span, SyntaxError::InvalidIdentInAsync);
}

View File

@ -19,7 +19,7 @@ macro_rules! is {
($p:expr, BindingIdent) => {{
let ctx = $p.ctx();
match $p.input.cur() {
Some(&Word(ref w)) => !ctx.is_reserved(w),
Some(&crate::token::Word(ref w)) => !ctx.is_reserved(w),
_ => false,
}
}};
@ -27,14 +27,14 @@ macro_rules! is {
($p:expr, IdentRef) => {{
let ctx = $p.ctx();
match $p.input.cur() {
Some(&Word(ref w)) => !ctx.is_reserved(w),
Some(&crate::token::Word(ref w)) => !ctx.is_reserved(w),
_ => false,
}
}};
($p:expr,IdentName) => {{
match $p.input.cur() {
Some(&Word(..)) => true,
Some(&crate::token::Word(..)) => true,
_ => false,
}
}};
@ -77,6 +77,10 @@ macro_rules! is {
($p:expr, $t:tt) => {
is_exact!($p, $t)
};
($p:expr, $t:tt | $($rest:tt)*) => {{
is!($p, $t) || is!($p, $($rest)*)
}};
}
#[allow(unused)]
@ -84,7 +88,7 @@ macro_rules! peeked_is {
($p:expr, BindingIdent) => {{
let ctx = $p.ctx();
match peek!($p) {
Some(&Word(ref w)) => !ctx.is_reserved(w),
Some(&crate::token::Word(ref w)) => !ctx.is_reserved(w),
_ => false,
}
}};
@ -92,14 +96,14 @@ macro_rules! peeked_is {
($p:expr, IdentRef) => {{
let ctx = $p.ctx();
match peek!($p) {
Some(&Word(ref w)) => !ctx.is_reserved(w),
Some(&crate::token::Word(ref w)) => !ctx.is_reserved(w),
_ => false,
}
}};
($p:expr,IdentName) => {{
match peek!($p) {
Some(&Word(..)) => true,
Some(&crate::token::Word(..)) => true,
_ => false,
}
}};
@ -121,6 +125,10 @@ macro_rules! peeked_is {
_ => false,
}
};
($p:expr, $t:tt | $($rest:tt)*) => {
peeked_is!($p, $t) || peeked_is!($p, $($rest)*)
};
}
/// Returns true on eof.
@ -130,15 +138,6 @@ macro_rules! eof {
};
}
macro_rules! is_one_of {
($p:expr, $($t:tt),+) => {{
false
$(
|| is!($p, $t)
)*
}};
}
// This will panic if current != token
macro_rules! assert_and_bump {
($p:expr, $t:tt) => {{
@ -161,9 +160,6 @@ macro_rules! assert_and_bump {
/// if token has data like string.
macro_rules! eat {
($p:expr, ';') => {{
if cfg!(feature = "debug") {
tracing::trace!("eat(';'): cur={:?}", cur!($p, false));
}
match $p.input.cur() {
Some(&Token::Semi) => {
$p.input.bump();
@ -210,7 +206,11 @@ macro_rules! expect {
const TOKEN: &Token = &token_including_semi!($t);
if !eat!($p, $t) {
let cur = $p.input.dump_cur();
syntax_error!($p, $p.input.cur_span(), SyntaxError::Expected(TOKEN, cur))
syntax_error!(
$p,
$p.input.cur_span(),
crate::error::SyntaxError::Expected(TOKEN, cur)
)
}
}};
}
@ -220,7 +220,11 @@ macro_rules! expect_exact {
const TOKEN: &Token = &token_including_semi!($t);
if !eat_exact!($p, $t) {
let cur = $p.input.dump_cur();
syntax_error!($p, $p.input.cur_span(), SyntaxError::Expected(TOKEN, cur))
syntax_error!(
$p,
$p.input.cur_span(),
crate::error::SyntaxError::Expected(TOKEN, cur)
)
}
}};
}
@ -291,6 +295,9 @@ macro_rules! bump {
$p.input.knows_cur(),
"parser should not call bump() without knowing current token"
);
if cfg!(feature = "debug") {
tracing::info!("Bump: {:?}", $p.input.cur());
}
$p.input.bump()
}};
}
@ -377,16 +384,13 @@ macro_rules! syntax_error {
}
}
}
if cfg!(feature = "debug") {
tracing::error!(
"Syntax error called from {}:{}:{}\nCurrent token = {:?}",
file!(),
line!(),
column!(),
$p.input.cur()
);
}
tracing::error!(
"Syntax error called from {}:{}:{}\nCurrent token = {:?}",
file!(),
line!(),
column!(),
$p.input.cur()
);
return Err(err.into());
}};
}

View File

@ -183,7 +183,10 @@ impl<I: Tokens> ParseObject<Box<Expr>> for Parser<I> {
let key = self.parse_prop_name()?;
if self.input.syntax().typescript()
&& !is_one_of!(self, '(', '[', ':', ',', '?', '=', '*', IdentName, Str, Num)
&& !is!(
self,
'(' | '[' | ':' | ',' | '?' | '=' | '*' | IdentName | Str | Num
)
&& !(self.input.syntax().typescript() && is!(self, '<'))
&& !(is!(self, '}') && matches!(key, PropName::Ident(..)))
{
@ -242,7 +245,7 @@ impl<I: Tokens> ParseObject<Box<Expr>> for Parser<I> {
// `ident` from parse_prop_name is parsed as 'IdentifierName'
// It means we should check for invalid expressions like { for, }
if is_one_of!(self, '=', ',', '}') {
if is!(self, '=' | ',' | '}') {
let is_reserved_word = { self.ctx().is_reserved_word(&ident.sym) };
if is_reserved_word {
self.emit_err(ident.span, SyntaxError::ReservedWordInObjShorthandOrPat);

View File

@ -96,7 +96,7 @@ impl<'a, I: Tokens> Parser<I> {
let start = cur_pos!(self);
let decorators = self.parse_decorators(true)?;
if is_one_of!(self, "import", "export") {
if is!(self, "import" | "export") {
return self.handle_import_export(top_level, decorators);
}
@ -642,7 +642,7 @@ impl<'a, I: Tokens> Parser<I> {
};
self.with_ctx(ctx).parse_with(|p| {
while is_one_of!(p, "case", "default") {
while is!(p, "case" | "default") {
let mut cons = vec![];
let is_case = is!(p, "case");
let case_start = cur_pos!(p);
@ -659,7 +659,7 @@ impl<'a, I: Tokens> Parser<I> {
};
expect!(p, ':');
while !eof!(p) && !is_one_of!(p, "case", "default", '}') {
while !eof!(p) && !is!(p, "case" | "default" | '}') {
cons.push(p.parse_stmt_list_item(false)?);
}
@ -870,7 +870,7 @@ impl<'a, I: Tokens> Parser<I> {
let should_include_in = kind != VarDeclKind::Var || !for_loop;
if self.syntax().typescript() && for_loop {
let res = if is_one_of!(self, "in", "of") {
let res = if is!(self, "in" | "of") {
self.ts_look_ahead(|p| {
//
if !eat!(p, "of") && !eat!(p, "in") {
@ -1001,7 +1001,7 @@ impl<'a, I: Tokens> Parser<I> {
}
//FIXME: This is wrong. Should check in/of only on first loop.
let init = if !for_loop || !is_one_of!(self, "in", "of") {
let init = if !for_loop || !is!(self, "in" | "of") {
if eat!(self, '=') {
let expr = self.parse_assignment_expr()?;
let expr = self.verify_expr(expr)?;
@ -1245,13 +1245,13 @@ impl<'a, I: Tokens> Parser<I> {
fn parse_for_head(&mut self) -> PResult<TempForHead> {
let strict = self.ctx().strict;
if is_one_of!(self, "const", "var")
if is!(self, "const" | "var")
|| (is!(self, "let")
&& peek!(self).map_or(false, |v| v.kind().follows_keyword_let(strict)))
{
let decl = self.parse_var_stmt(true)?;
if is_one_of!(self, "of", "in") {
if is!(self, "of" | "in") {
if decl.decls.len() != 1 {
for d in decl.decls.iter().skip(1) {
self.emit_err(d.name.span(), SyntaxError::TooManyVarInForInHead);
@ -1344,7 +1344,7 @@ impl<'a, I: Tokens> Parser<I> {
}
// for (a of b)
if is_one_of!(self, "of", "in") {
if is!(self, "of" | "in") {
let is_in = is!(self, "in");
let pat = self.reparse_expr_as_pat(PatType::AssignPat, init)?;

View File

@ -85,7 +85,7 @@ impl<I: Tokens> Parser<I> {
let mut local = self.parse_imported_default_binding()?;
if self.input.syntax().typescript() && local.sym == "type" {
if is_one_of!(self, '*', '{') {
if is!(self, '*' | '{') {
type_only = true;
break 'import_maybe_ident;
}
@ -115,7 +115,7 @@ impl<I: Tokens> Parser<I> {
_ => unreachable!(),
};
if is_one_of!(self, '*', '{') {
if is!(self, '*' | '{') {
phase = new_phase;
break 'import_maybe_ident;
}

View File

@ -19,7 +19,10 @@ impl<I: Tokens> Parser<I> {
// hasLineBreakUpNext() method...
bump!(self);
Ok(!self.input.had_line_break_before_cur()
&& is_one_of!(self, '[', '{', '*', "...", '#', IdentName, Str, Num, BigInt))
&& is!(
self,
'[' | '{' | '*' | "..." | '#' | IdentName | Str | Num | BigInt
))
}
/// Parses a modifier matching one the given modifier names.
@ -578,13 +581,10 @@ impl<I: Tokens> Parser<I> {
self.try_parse_ts(|p| {
let type_args = p.parse_ts_type_args()?;
if is_one_of!(
p, '<', // invalid syntax
'>', '=', ">>", ">=", '+', '-', // becomes relational expression
/* these should be type arguments in function call or template,
* not instantiation expression */
'(', '`'
) {
// becomes relational expression
/* these should be type arguments in function call or template,
* not instantiation expression */
if is!(p, '<' | '>' | '=' | ">>" | ">=" | '+' | '-' | '(' | '`') {
Ok(None)
} else if p.input.had_line_break_before_cur()
|| matches!(cur!(p, false), Ok(Token::BinOp(..)))
@ -1216,13 +1216,13 @@ impl<I: Tokens> Parser<I> {
debug_assert!(self.input.syntax().typescript());
assert_and_bump!(self, '(');
if is_one_of!(self, ')', "...") {
if is!(self, ')' | "...") {
// ( )
// ( ...
return Ok(true);
}
if self.skip_ts_parameter_start()? {
if is_one_of!(self, ':', ',', '?', '=') {
if is!(self, ':' | ',' | '?' | '=') {
// ( xxx :
// ( xxx ,
// ( xxx ?
@ -1243,7 +1243,7 @@ impl<I: Tokens> Parser<I> {
let _ = self.eat_any_ts_modifier()?;
if is_one_of!(self, IdentName, "this") {
if is!(self, IdentName | "this") {
bump!(self);
return Ok(true);
}
@ -1320,7 +1320,7 @@ impl<I: Tokens> Parser<I> {
assert_and_bump!(self, '['); // Skip '['
// ',' is for error recovery
Ok(eat!(self, IdentRef) && is_one_of!(self, ':', ','))
Ok(eat!(self, IdentRef) && is!(self, ':' | ','))
}
/// `tsTryParseIndexSignature`
@ -1416,7 +1416,7 @@ impl<I: Tokens> Parser<I> {
let optional = eat!(self, '?');
if is_one_of!(self, '(', '<') {
if is!(self, '(' | '<') {
if readonly {
syntax_error!(self, SyntaxError::ReadOnlyMethod)
}
@ -1469,7 +1469,7 @@ impl<I: Tokens> Parser<I> {
Either::Right(e) => e.into(),
}
}
if is_one_of!(self, '(', '<') {
if is!(self, '(' | '<') {
return self
.parse_ts_signature_member(SignatureParsingMode::TSCallSignatureDeclaration)
.map(into_type_elem);
@ -1626,7 +1626,7 @@ impl<I: Tokens> Parser<I> {
let start = cur_pos!(self);
expect!(self, '{');
let mut readonly = None;
if is_one_of!(self, '+', '-') {
if is!(self, '+' | '-') {
readonly = Some(if is!(self, '+') {
TruePlusMinus::Plus
} else {
@ -1648,7 +1648,7 @@ impl<I: Tokens> Parser<I> {
expect!(self, ']');
let mut optional = None;
if is_one_of!(self, '+', '-') {
if is!(self, '+' | '-') {
optional = Some(if is!(self, '+') {
TruePlusMinus::Plus
} else {
@ -2443,7 +2443,7 @@ impl<I: Tokens> Parser<I> {
.map(From::from)
.map(Some);
}
if is_one_of!(p, "const", "var", "let") {
if is!(p, "const" | "var" | "let") {
return p
.parse_var_stmt(false)
.map(|decl| VarDecl {
@ -2606,7 +2606,7 @@ impl<I: Tokens> Parser<I> {
return Ok(Default::default());
}
let res = if is_one_of!(self, '<', JSXTagStart) {
let res = if is!(self, '<' | JSXTagStart) {
self.try_parse_ts(|p| {
let type_params = p.parse_ts_type_params(false, false)?;
// Don't use overloaded parseFunctionParams which would look for "<" again.