diff --git a/crates/swc_ecma_parser/src/parser/class_and_fn.rs b/crates/swc_ecma_parser/src/parser/class_and_fn.rs index 83573ecbcfc..95d754e0d9c 100644 --- a/crates/swc_ecma_parser/src/parser/class_and_fn.rs +++ b/crates/swc_ecma_parser/src/parser/class_and_fn.rs @@ -745,7 +745,7 @@ impl Parser { } 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 Parser { } 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 { diff --git a/crates/swc_ecma_parser/src/parser/expr.rs b/crates/swc_ecma_parser/src/parser/expr.rs index c1eb615e898..05fb21238ca 100644 --- a/crates/swc_ecma_parser/src/parser/expr.rs +++ b/crates/swc_ecma_parser/src/parser/expr.rs @@ -82,7 +82,7 @@ impl Parser { 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 Parser { } 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 Parser { ) .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 Parser { None }; - if obj.is_import() && !is_one_of!(self, '.', '(') { + if obj.is_import() && !is!(self, '.' | '(') { unexpected!(self, "`.` or `(`") } @@ -1597,7 +1597,7 @@ impl Parser { 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 Parser { } fn is_start_of_left_hand_side_expr(&mut self) -> PResult { - 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 { 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))) } diff --git a/crates/swc_ecma_parser/src/parser/expr/ops.rs b/crates/swc_ecma_parser/src/parser/expr/ops.rs index 344a4fb31ec..0aa23286050 100644 --- a/crates/swc_ecma_parser/src/parser/expr/ops.rs +++ b/crates/swc_ecma_parser/src/parser/expr/ops.rs @@ -281,7 +281,7 @@ impl Parser { } // 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 Parser { 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 Parser { 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); } diff --git a/crates/swc_ecma_parser/src/parser/macros.rs b/crates/swc_ecma_parser/src/parser/macros.rs index 78b52a93058..ee72def84a5 100644 --- a/crates/swc_ecma_parser/src/parser/macros.rs +++ b/crates/swc_ecma_parser/src/parser/macros.rs @@ -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()); }}; } diff --git a/crates/swc_ecma_parser/src/parser/object.rs b/crates/swc_ecma_parser/src/parser/object.rs index 0eea9a3aa7a..f24a5c96970 100644 --- a/crates/swc_ecma_parser/src/parser/object.rs +++ b/crates/swc_ecma_parser/src/parser/object.rs @@ -183,7 +183,10 @@ impl ParseObject> for Parser { 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 ParseObject> for Parser { // `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); diff --git a/crates/swc_ecma_parser/src/parser/stmt.rs b/crates/swc_ecma_parser/src/parser/stmt.rs index 1b6cbcc000e..9738fd0525a 100644 --- a/crates/swc_ecma_parser/src/parser/stmt.rs +++ b/crates/swc_ecma_parser/src/parser/stmt.rs @@ -96,7 +96,7 @@ impl<'a, I: Tokens> Parser { 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 { }; 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 { }; 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 { 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 { } //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 { fn parse_for_head(&mut self) -> PResult { 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 { } // 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)?; diff --git a/crates/swc_ecma_parser/src/parser/stmt/module_item.rs b/crates/swc_ecma_parser/src/parser/stmt/module_item.rs index c9af578bd20..4743966738e 100644 --- a/crates/swc_ecma_parser/src/parser/stmt/module_item.rs +++ b/crates/swc_ecma_parser/src/parser/stmt/module_item.rs @@ -85,7 +85,7 @@ impl Parser { 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 Parser { _ => unreachable!(), }; - if is_one_of!(self, '*', '{') { + if is!(self, '*' | '{') { phase = new_phase; break 'import_maybe_ident; } diff --git a/crates/swc_ecma_parser/src/parser/typescript.rs b/crates/swc_ecma_parser/src/parser/typescript.rs index d7a0ed5e0ad..18b57c36d22 100644 --- a/crates/swc_ecma_parser/src/parser/typescript.rs +++ b/crates/swc_ecma_parser/src/parser/typescript.rs @@ -19,7 +19,10 @@ impl Parser { // 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 Parser { 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 Parser { 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 Parser { 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 Parser { 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 Parser { let optional = eat!(self, '?'); - if is_one_of!(self, '(', '<') { + if is!(self, '(' | '<') { if readonly { syntax_error!(self, SyntaxError::ReadOnlyMethod) } @@ -1469,7 +1469,7 @@ impl Parser { 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 Parser { 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 Parser { 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 Parser { .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 Parser { 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.