parse_js/parse/
expr.rs

1use super::class_or_object::ParseClassBodyResult;
2use super::class_or_object::ParseClassOrObjectMemberResult;
3use super::literal::normalise_literal_bigint;
4use super::literal::normalise_literal_string_or_template_inner;
5use super::pattern::is_valid_pattern_identifier;
6use super::pattern::ParsePatternRules;
7use super::ParseCtx;
8use super::Parser;
9use crate::ast::ArrayElement;
10use crate::ast::ArrayPatternElement;
11use crate::ast::ClassOrObjectMemberKey;
12use crate::ast::ClassOrObjectMemberValue;
13use crate::ast::LiteralTemplatePart;
14use crate::ast::Node;
15use crate::ast::ObjectMemberType;
16use crate::ast::Syntax;
17use crate::error::SyntaxErrorType;
18use crate::error::SyntaxResult;
19use crate::lex::lex_template_string_continue;
20use crate::lex::LexMode;
21use crate::lex::KEYWORDS_MAPPING;
22use crate::operator::Associativity;
23use crate::operator::OperatorName;
24use crate::operator::OPERATORS;
25use crate::parse::literal::normalise_literal_number;
26use crate::parse::literal::normalise_literal_string;
27use crate::parse::operator::MULTARY_OPERATOR_MAPPING;
28use crate::parse::operator::UNARY_OPERATOR_MAPPING;
29use crate::token::TokenType;
30
31pub struct Asi {
32  pub can_end_with_asi: bool,
33  pub did_end_with_asi: bool,
34}
35
36impl Asi {
37  pub fn can() -> Asi {
38    Asi {
39      can_end_with_asi: true,
40      did_end_with_asi: false,
41    }
42  }
43
44  pub fn no() -> Asi {
45    Asi {
46      can_end_with_asi: false,
47      did_end_with_asi: false,
48    }
49  }
50}
51
52fn is_chevron_right_or_slash(typ: TokenType) -> bool {
53  typ == TokenType::ChevronRight || typ == TokenType::Slash
54}
55
56fn jsx_tag_names_are_equal(a: Option<&Syntax>, b: Option<&Syntax>) -> bool {
57  let (Some(a), Some(b)) = (a, b) else {
58    return a.is_none() && b.is_none();
59  };
60  match (a, b) {
61    (
62      Syntax::JsxMemberExpression {
63        base: a_base,
64        path: a_path,
65      },
66      Syntax::JsxMemberExpression {
67        base: b_base,
68        path: b_path,
69      },
70    ) => a_base.as_ident() == b_base.as_ident() && a_path == b_path,
71    (
72      Syntax::JsxName {
73        name: a_name,
74        namespace: a_ns,
75      },
76      Syntax::JsxName {
77        name: b_name,
78        namespace: b_ns,
79      },
80    ) => a_ns == b_ns && a_name == b_name,
81    (Syntax::IdentifierExpr { name: a_name }, Syntax::IdentifierExpr { name: b_name }) => {
82      a_name == b_name
83    }
84    _ => false,
85  }
86}
87
88impl<'a> Parser<'a> {
89  /// Reinterprets an expression subtree as an assignment target.
90  fn transform_literal_expr_to_destructuring_pattern(
91    &self,
92    ctx: ParseCtx,
93    node: Node,
94  ) -> SyntaxResult<Node> {
95    let loc = node.loc;
96    match *node.stx {
97      Syntax::LiteralArrayExpr { elements } => {
98        let mut pat_elements = Vec::<Option<ArrayPatternElement>>::new();
99        let mut rest = None;
100        for element in elements {
101          if rest.is_some() {
102            return Err(loc.error(SyntaxErrorType::InvalidAssigmentTarget, None));
103          };
104          match element {
105            ArrayElement::Single(elem) => {
106              match *elem.stx {
107                Syntax::BinaryExpr {
108                  parenthesised,
109                  operator,
110                  left,
111                  right,
112                } => {
113                  if parenthesised || operator != OperatorName::Assignment {
114                    return Err(loc.error(SyntaxErrorType::InvalidAssigmentTarget, None));
115                  };
116                  pat_elements.push(Some(ArrayPatternElement {
117                    target: self.transform_literal_expr_to_destructuring_pattern(ctx, left)?,
118                    default_value: Some(right),
119                  }));
120                }
121                _ => pat_elements.push(Some(ArrayPatternElement {
122                  target: self.transform_literal_expr_to_destructuring_pattern(ctx, elem)?,
123                  default_value: None,
124                })),
125              };
126            }
127            ArrayElement::Rest(expr) => {
128              rest = Some(self.transform_literal_expr_to_destructuring_pattern(ctx, expr)?);
129            }
130            ArrayElement::Empty => pat_elements.push(None),
131          };
132        }
133        Ok(Node::new(loc, Syntax::ArrayPattern {
134          elements: pat_elements,
135          rest,
136        }))
137      }
138      Syntax::LiteralObjectExpr { members } => {
139        let mut properties = Vec::new();
140        let mut rest = None;
141        for member in members {
142          if rest.is_some() {
143            return Err(loc.error(SyntaxErrorType::InvalidAssigmentTarget, None));
144          };
145          match *member.stx {
146            Syntax::ObjectMember { typ } => match typ {
147              ObjectMemberType::Valued { key, value } => {
148                let (target, default_value) = match value {
149                  ClassOrObjectMemberValue::Property {
150                    initializer: Some(initializer),
151                  } => match *initializer.stx {
152                    Syntax::BinaryExpr {
153                      parenthesised,
154                      operator,
155                      left,
156                      right,
157                    } => {
158                      if parenthesised || operator != OperatorName::Assignment {
159                        return Err(loc.error(SyntaxErrorType::InvalidAssigmentTarget, None));
160                      };
161                      (
162                        self.transform_literal_expr_to_destructuring_pattern(ctx, left)?,
163                        Some(right),
164                      )
165                    }
166                    _ => (
167                      self.transform_literal_expr_to_destructuring_pattern(ctx, initializer)?,
168                      None,
169                    ),
170                  },
171                  _ => return Err(loc.error(SyntaxErrorType::InvalidAssigmentTarget, None)),
172                };
173                properties.push(Node::new(loc, Syntax::ObjectPatternProperty {
174                  key,
175                  target,
176                  default_value,
177                  shorthand: true,
178                }));
179              }
180              ObjectMemberType::Shorthand { identifier } => {
181                properties.push(Node::new(loc, Syntax::ObjectPatternProperty {
182                  key: ClassOrObjectMemberKey::Direct(self.string(identifier.loc)),
183                  target: Node::new(loc, Syntax::IdentifierPattern {
184                    name: self.string(identifier.loc),
185                  }),
186                  default_value: None,
187                  shorthand: true,
188                }));
189              }
190              ObjectMemberType::Rest { value } => {
191                rest = Some(self.transform_literal_expr_to_destructuring_pattern(ctx, value)?);
192              }
193            },
194            _ => unreachable!(),
195          };
196        }
197        Ok(Node::new(loc, Syntax::ObjectPattern { properties, rest }))
198      }
199      // It's possible to encounter an IdentifierPattern e.g. `{ a: b = 1 } = x`, where `b = 1` is already parsed as an assignment.
200      Syntax::IdentifierExpr { name } | Syntax::IdentifierPattern { name } => {
201        Ok(Node::new(loc, Syntax::IdentifierPattern {
202          name: name.clone(),
203        }))
204      }
205      _ => Err(loc.error(SyntaxErrorType::InvalidAssigmentTarget, None)),
206    }
207  }
208
209  // Trying to check if every object, array, or identifier expression operand is actually an assignment target first is too expensive and wasteful, so simply retroactively transform the LHS of a BinaryExpr with Assignment* operator into a target, raising an error if it can't (and is an invalid assignment target). A valid target is:
210  // - A chain of non-optional-chaining member, computed member, and call operators, not ending in a call.
211  // - A pattern.
212  fn convert_assignment_lhs_to_target(
213    &self,
214    ctx: ParseCtx,
215    lhs: Node,
216    operator_name: OperatorName,
217  ) -> SyntaxResult<Node> {
218    match lhs.stx.as_ref() {
219      e @ (Syntax::LiteralArrayExpr { .. }
220      | Syntax::LiteralObjectExpr { .. }
221      | Syntax::IdentifierExpr { .. }) => {
222        if operator_name != OperatorName::Assignment
223          && match e {
224            Syntax::IdentifierExpr { .. } => false,
225            _ => true,
226          }
227        {
228          return Err(lhs.error(SyntaxErrorType::InvalidAssigmentTarget));
229        }
230        // We must transform into a pattern.
231        let root = self.transform_literal_expr_to_destructuring_pattern(ctx, lhs)?;
232        Ok(root)
233      }
234      Syntax::ComputedMemberExpr {
235        optional_chaining, ..
236      }
237      | Syntax::MemberExpr {
238        optional_chaining, ..
239      } if !optional_chaining => {
240        // As long as the expression ends with ComputedMemberExpr or MemberExpr, it's valid e.g. `(a, b?.a ?? 3, c = d || {})[1] = x`. Note that this is after parsing, so `a + b.c = 3` is invalid because that parses to `(a + b.c) = 3`, with a LHS of BinaryExpr with Addition operator.
241        // TODO Technically there cannot be any optional chaining in the entire access/call path, not just in the last part (e.g. `a.b?.c.d = e` is invalid).
242        Ok(lhs)
243      }
244      _ => Err(lhs.error(SyntaxErrorType::InvalidAssigmentTarget)),
245    }
246  }
247
248  pub fn parse_jsx_name(&mut self, ctx: ParseCtx) -> SyntaxResult<Node> {
249    let start = self.require_with_mode(TokenType::Identifier, LexMode::JsxTag)?;
250    Ok(if self.consume_if(TokenType::Colon)?.is_match() {
251      let name = self.require_with_mode(TokenType::Identifier, LexMode::JsxTag)?;
252      Node::new(start.loc + name.loc, Syntax::JsxName {
253        namespace: Some(self.string(start.loc)),
254        name: self.string(name.loc),
255      })
256    } else {
257      Node::new(start.loc, Syntax::JsxName {
258        namespace: None,
259        name: self.string(start.loc),
260      })
261    })
262  }
263
264  pub fn parse_jsx_tag_name(&mut self, ctx: ParseCtx) -> SyntaxResult<Option<Node>> {
265    Ok(
266      match self
267        .maybe_with_mode(TokenType::Identifier, LexMode::JsxTag)?
268        .match_loc()
269      {
270        // Fragment.
271        None => None,
272        Some(start) => Some({
273          if self.consume_if(TokenType::Colon)?.is_match() {
274            // Namespaced name.
275            let name = self.require_with_mode(TokenType::Identifier, LexMode::JsxTag)?;
276            Node::new(start + name.loc, Syntax::JsxName {
277              namespace: Some(self.string(start)),
278              name: self.string(name.loc),
279            })
280          } else if self.peek()?.typ == TokenType::Dot && !self.str(start).contains('-') {
281            // Member name.
282            let mut path = Vec::new();
283            let mut loc = start;
284            while self.consume_if(TokenType::Dot)?.is_match() {
285              let l = self.require(TokenType::Identifier)?.loc;
286              path.push(self.string(l));
287              loc += l;
288            }
289            Node::new(loc, Syntax::JsxMemberExpression {
290              base: Node::new(start, Syntax::IdentifierExpr {
291                name: self.string(start),
292              }),
293              path,
294            })
295          } else if !self.bytes(start)[0].is_ascii_lowercase() {
296            // User-defined component.
297            Node::new(start, Syntax::IdentifierExpr {
298              name: self.string(start),
299            })
300          } else {
301            // Built-in component without namespace.
302            Node::new(start, Syntax::JsxName {
303              namespace: None,
304              name: self.string(start),
305            })
306          }
307        }),
308      },
309    )
310  }
311
312  // https://facebook.github.io/jsx/
313  pub fn parse_jsx_element(&mut self, ctx: ParseCtx) -> SyntaxResult<Node> {
314    let tag_start = self.require(TokenType::ChevronLeft)?;
315    let tag_name = self.parse_jsx_tag_name(ctx)?;
316
317    // Attributes.
318    let mut attributes = Vec::new();
319    if tag_name.is_some() {
320      loop {
321        if is_chevron_right_or_slash(self.peek()?.typ) {
322          break;
323        }
324        if self.consume_if(TokenType::BraceOpen)?.is_match() {
325          let start = self.require(TokenType::DotDotDot)?;
326          let value = self.parse_expr(ctx, TokenType::BraceClose)?;
327          let end = self.require(TokenType::BraceClose)?;
328          attributes.push(Node::new(start.loc + end.loc, Syntax::JsxSpreadAttribute {
329            value,
330          }));
331          continue;
332        }
333
334        let name = self.parse_jsx_name(ctx)?;
335        let value = if !self.consume_if(TokenType::Equals)?.is_match() {
336          None
337        } else {
338          // TODO JSXSpreadAttribute
339          // TODO Attr values can be an element or fragment directly e.g. `a=<div/>`.
340          Some(if self.consume_if(TokenType::BraceOpen)?.is_match() {
341            let value = self.parse_expr(ctx, TokenType::BraceClose)?;
342            let expr = Node::new(value.loc, Syntax::JsxExpressionContainer { value });
343            self.require(TokenType::BraceClose)?;
344            expr
345          } else {
346            let value = self.require(TokenType::LiteralString)?;
347            Node::new(value.loc, Syntax::JsxText {
348              value: self.string(value.loc),
349            })
350          })
351        };
352        attributes.push(Node::new(
353          name.loc.add_option(value.as_ref().map(|n| n.loc)),
354          Syntax::JsxAttribute { name, value },
355        ))
356      }
357    }
358
359    Ok(if self.consume_if(TokenType::Slash)?.is_match() {
360      // Self closing.
361      let end = self.require(TokenType::ChevronRight)?;
362      Node::new(tag_start.loc + end.loc, Syntax::JsxElement {
363        name: tag_name,
364        attributes,
365        children: Vec::new(),
366      })
367    } else {
368      self.require(TokenType::ChevronRight)?;
369
370      // Children.
371      let mut children = Vec::new();
372      let close_start = loop {
373        match self.peek()? {
374          t if t.typ == TokenType::ChevronLeftSlash => {
375            break self.consume_peeked();
376          }
377          t if t.typ == TokenType::EOF => {
378            return Err(t.error(SyntaxErrorType::UnexpectedEnd));
379          }
380          _ => {}
381        };
382        let text = self.require_with_mode(TokenType::JsxTextContent, LexMode::JsxTextContent)?;
383        if !text.loc.is_empty() {
384          children.push(Node::new(text.loc, Syntax::JsxText {
385            value: self.string(text.loc),
386          }));
387        };
388        if self.peek()?.typ == TokenType::ChevronLeft {
389          children.push(self.parse_jsx_element(ctx)?);
390        };
391        if self.consume_if(TokenType::BraceOpen)?.is_match() {
392          // TODO Allow empty expr.
393          let value = self.parse_expr(ctx, TokenType::BraceClose)?;
394          children.push(Node::new(value.loc, Syntax::JsxExpressionContainer {
395            value,
396          }));
397          self.require(TokenType::BraceClose)?;
398        };
399      };
400      let end_name = self.parse_jsx_tag_name(ctx)?;
401      if !jsx_tag_names_are_equal(
402        tag_name.as_ref().map(|n| n.stx.as_ref()),
403        end_name.as_ref().map(|n| n.stx.as_ref()),
404      ) {
405        return Err(close_start.error(SyntaxErrorType::JsxClosingTagMismatch));
406      };
407      let end = self.require(TokenType::ChevronRight)?;
408      Node::new(tag_start.loc + end.loc, Syntax::JsxElement {
409        name: tag_name,
410        attributes,
411        children,
412      })
413    })
414  }
415
416  pub fn parse_call_args(&mut self, ctx: ParseCtx) -> SyntaxResult<Vec<Node>> {
417    let mut args = Vec::new();
418    loop {
419      if self.peek()?.typ == TokenType::ParenthesisClose {
420        break;
421      };
422      let spread = self.consume_if(TokenType::DotDotDot)?.is_match();
423      let value =
424        self.parse_expr_until_either(ctx, TokenType::Comma, TokenType::ParenthesisClose)?;
425      args.push(Node::new(value.loc, Syntax::CallArg { spread, value }));
426      if !self.consume_if(TokenType::Comma)?.is_match() {
427        break;
428      };
429    }
430    Ok(args)
431  }
432
433  pub fn parse_expr(&mut self, ctx: ParseCtx, terminator: TokenType) -> SyntaxResult<Node> {
434    self.parse_expr_with_min_prec(ctx, 1, terminator, TokenType::_Dummy, false, &mut Asi::no())
435  }
436
437  pub fn parse_expr_with_asi(
438    &mut self,
439    ctx: ParseCtx,
440    terminator: TokenType,
441    asi: &mut Asi,
442  ) -> SyntaxResult<Node> {
443    self.parse_expr_with_min_prec(ctx, 1, terminator, TokenType::_Dummy, false, asi)
444  }
445
446  pub fn parse_expr_until_either(
447    &mut self,
448    ctx: ParseCtx,
449    terminator_a: TokenType,
450    terminator_b: TokenType,
451  ) -> SyntaxResult<Node> {
452    self.parse_expr_with_min_prec(ctx, 1, terminator_a, terminator_b, false, &mut Asi::no())
453  }
454
455  pub fn parse_expr_until_either_with_asi(
456    &mut self,
457    ctx: ParseCtx,
458    terminator_a: TokenType,
459    terminator_b: TokenType,
460    asi: &mut Asi,
461  ) -> SyntaxResult<Node> {
462    self.parse_expr_with_min_prec(ctx, 1, terminator_a, terminator_b, false, asi)
463  }
464
465  pub fn parse_grouping(&mut self, ctx: ParseCtx, asi: &mut Asi) -> SyntaxResult<Node> {
466    self.require(TokenType::ParenthesisOpen)?;
467    let expr = self.parse_expr_with_min_prec(
468      ctx,
469      1,
470      TokenType::ParenthesisClose,
471      TokenType::_Dummy,
472      true,
473      asi,
474    )?;
475    self.require(TokenType::ParenthesisClose)?;
476    Ok(expr)
477  }
478
479  pub fn parse_expr_array(&mut self, ctx: ParseCtx) -> SyntaxResult<Node> {
480    let loc_start = self.require(TokenType::BracketOpen)?.loc;
481    let mut elements = Vec::<ArrayElement>::new();
482    loop {
483      if self.consume_if(TokenType::Comma)?.is_match() {
484        elements.push(ArrayElement::Empty);
485        continue;
486      };
487      if self.peek()?.typ == TokenType::BracketClose {
488        break;
489      };
490      let rest = self.consume_if(TokenType::DotDotDot)?.is_match();
491      let value = self.parse_expr_until_either(ctx, TokenType::Comma, TokenType::BracketClose)?;
492      elements.push(if rest {
493        ArrayElement::Rest(value)
494      } else {
495        ArrayElement::Single(value)
496      });
497      if self.peek()?.typ == TokenType::BracketClose {
498        break;
499      };
500      self.require(TokenType::Comma)?;
501    }
502    let loc_end = self.require(TokenType::BracketClose)?.loc;
503    Ok(Node::new(loc_start + loc_end, Syntax::LiteralArrayExpr {
504      elements,
505    }))
506  }
507
508  pub fn parse_expr_object(&mut self, ctx: ParseCtx) -> SyntaxResult<Node> {
509    let loc_start = self.require(TokenType::BraceOpen)?.loc;
510    let mut members = Vec::<Node>::new();
511    loop {
512      if self.peek()?.typ == TokenType::BraceClose {
513        break;
514      };
515      let rest = self.consume_if(TokenType::DotDotDot)?.is_match();
516      if rest {
517        let value = self.parse_expr_until_either(ctx, TokenType::Comma, TokenType::BraceClose)?;
518        let loc = value.loc;
519        members.push(Node::new(loc, Syntax::ObjectMember {
520          typ: ObjectMemberType::Rest { value },
521        }));
522      } else {
523        let loc_checkpoint = self.checkpoint();
524        let ParseClassOrObjectMemberResult {
525          key,
526          key_loc,
527          value,
528          ..
529        } = self.parse_class_or_object_member(
530          ctx,
531          TokenType::Colon,
532          TokenType::Comma,
533          &mut Asi::no(),
534        )?;
535        members.push(Node::new(
536          self.since_checkpoint(loc_checkpoint),
537          Syntax::ObjectMember {
538            typ: match value {
539              ClassOrObjectMemberValue::Property { initializer: None } => {
540                ObjectMemberType::Shorthand {
541                  identifier: match key {
542                    ClassOrObjectMemberKey::Direct(key) => {
543                      Node::new(key_loc, Syntax::IdentifierExpr { name: key })
544                    }
545                    _ => unreachable!(),
546                  },
547                }
548              }
549              _ => ObjectMemberType::Valued { key, value },
550            },
551          },
552        ));
553      }
554      if self.peek()?.typ == TokenType::BraceClose {
555        break;
556      };
557      self.require(TokenType::Comma)?;
558    }
559    let loc_end = self.require(TokenType::BraceClose)?.loc;
560    Ok(Node::new(loc_start + loc_end, Syntax::LiteralObjectExpr {
561      members,
562    }))
563  }
564
565  pub fn parse_expr_arrow_function(
566    &mut self,
567    ctx: ParseCtx,
568    terminator_a: TokenType,
569    terminator_b: TokenType,
570  ) -> SyntaxResult<Node> {
571    let is_async = self.consume_if(TokenType::KeywordAsync)?.is_match();
572
573    let (parameters, arrow) = if !is_async
574      && is_valid_pattern_identifier(self.peek()?.typ, ParsePatternRules {
575        await_allowed: false,
576        yield_allowed: ctx.rules.yield_allowed,
577      }) {
578      // Single-unparenthesised-parameter arrow function.
579      // Parse arrow first for fast fail (and in case we are merely trying to parse as arrow function), before we mutate state by creating nodes and adding symbols.
580      let param_name = self.next()?.loc;
581      let arrow = self.require(TokenType::EqualsChevronRight)?;
582      let pattern = Node::new(param_name, Syntax::IdentifierPattern {
583        name: self.string(param_name),
584      });
585      let param = Node::new(param_name, Syntax::ParamDecl {
586        rest: false,
587        pattern,
588        default_value: None,
589      });
590      (vec![param], arrow)
591    } else {
592      let params = self.parse_function_parameters(ctx)?;
593      let arrow = self.require(TokenType::EqualsChevronRight)?;
594      (params, arrow)
595    };
596
597    if arrow.preceded_by_line_terminator {
598      // Illegal under Automatic Semicolon Insertion rules.
599      return Err(arrow.error(SyntaxErrorType::LineTerminatorAfterArrowFunctionParameters));
600    }
601    let fn_body_ctx = ctx.with_rules(ParsePatternRules {
602      await_allowed: !is_async && ctx.rules.await_allowed,
603      ..ctx.rules
604    });
605    let body = match self.peek()?.typ {
606      TokenType::BraceOpen => self.parse_function_body(fn_body_ctx)?,
607      _ => self.parse_expr_until_either_with_asi(
608        fn_body_ctx,
609        terminator_a,
610        terminator_b,
611        &mut Asi::can(),
612      )?,
613    };
614    Ok(Node::new(body.loc, Syntax::ArrowFunctionExpr {
615      parenthesised: false,
616      function: Node::new(body.loc, Syntax::Function {
617        arrow: true,
618        async_: is_async,
619        generator: false,
620        parameters,
621        body,
622      }),
623    }))
624  }
625
626  pub fn parse_expr_arrow_function_or_grouping(
627    &mut self,
628    ctx: ParseCtx,
629    terminator_a: TokenType,
630    terminator_b: TokenType,
631    asi: &mut Asi,
632  ) -> SyntaxResult<Node> {
633    // Try and parse as arrow function signature first.
634    // If we fail, backtrack and parse as grouping instead.
635    // After we see `=>`, we assume it's definitely an arrow function and do not backtrack.
636
637    // NOTE: We originally implemented conversion from parameters to expression to prevent the need
638    // for backtracking. However, this ended up being too complex for little performance gain,
639    // as most usages of grouping involve a non-comma binary operator (such as `+`) and so parsing
640    // as arrow function fails quickly. Complex patterns like `{a, b: { c: [d, e] } = f }` are
641    // unlikely to be used as operands in a grouping.
642
643    let cp = self.checkpoint();
644
645    match self.parse_expr_arrow_function(ctx, terminator_a, terminator_b) {
646      Ok(expr) => Ok(expr),
647      Err(err) if err.typ == SyntaxErrorType::LineTerminatorAfterArrowFunctionParameters => {
648        Err(err)
649      }
650      Err(_) => {
651        self.restore_checkpoint(cp);
652        self.parse_grouping(ctx, asi)
653      }
654    }
655  }
656
657  pub fn parse_expr_import(&mut self, ctx: ParseCtx) -> SyntaxResult<Node> {
658    let start = self.require(TokenType::KeywordImport)?;
659    if self.consume_if(TokenType::Dot)?.is_match() {
660      // import.meta
661      let prop = self.require(TokenType::Identifier)?;
662      if self.str(prop.loc) != "meta" {
663        return Err(prop.error(SyntaxErrorType::ExpectedSyntax("`meta` property")));
664      };
665      return Ok(Node::new(start.loc + prop.loc, Syntax::ImportMeta {}));
666    }
667    self.require(TokenType::ParenthesisOpen)?;
668    let module = self.parse_expr(ctx, TokenType::ParenthesisClose)?;
669    let end = self.require(TokenType::ParenthesisClose)?;
670    Ok(Node::new(start.loc + end.loc, Syntax::ImportExpr {
671      module,
672    }))
673  }
674
675  pub fn parse_expr_function(&mut self, ctx: ParseCtx) -> SyntaxResult<Node> {
676    let is_async = self.consume_if(TokenType::KeywordAsync)?.is_match();
677    let start = self.require(TokenType::KeywordFunction)?.loc;
678    let generator = self.consume_if(TokenType::Asterisk)?.is_match();
679    let name = match self.peek()? {
680      t if is_valid_pattern_identifier(t.typ, ctx.rules) => {
681        self.consume_peeked();
682        Some(Node::new(t.loc, Syntax::ClassOrFunctionName {
683          name: self.string(t.loc),
684        }))
685      }
686      _ => None,
687    };
688    let parameters = self.parse_function_parameters(ctx)?;
689    let fn_body_ctx = ctx.with_rules(ParsePatternRules {
690      await_allowed: !is_async && ctx.rules.await_allowed,
691      yield_allowed: !generator && ctx.rules.yield_allowed,
692    });
693    let body = self.parse_function_body(fn_body_ctx)?;
694    Ok(Node::new(start + body.loc, Syntax::FunctionExpr {
695      parenthesised: false,
696      name,
697      function: Node::new(start + body.loc, Syntax::Function {
698        arrow: false,
699        async_: is_async,
700        generator,
701        parameters,
702        body,
703      }),
704    }))
705  }
706
707  pub fn parse_expr_class(&mut self, ctx: ParseCtx) -> SyntaxResult<Node> {
708    let start = self.require(TokenType::KeywordClass)?.loc;
709    let name = match self.peek()? {
710      t if is_valid_pattern_identifier(t.typ, ctx.rules) => {
711        self.consume_peeked();
712        let name_node = Node::new(t.loc, Syntax::ClassOrFunctionName {
713          name: self.string(t.loc),
714        });
715        Some(name_node)
716      }
717      _ => None,
718    };
719    let extends = if self.consume_if(TokenType::KeywordExtends)?.is_match() {
720      Some(self.parse_expr(ctx, TokenType::BraceOpen)?)
721    } else {
722      None
723    };
724    let ParseClassBodyResult { end, members } = self.parse_class_body(ctx)?;
725    Ok(Node::new(start + end, Syntax::ClassExpr {
726      parenthesised: false,
727      name,
728      extends,
729      members,
730    }))
731  }
732
733  // NOTE: The next token must definitely be LiteralTemplatePartString{,End}.
734  fn parse_expr_literal_template_parts(
735    &mut self,
736    ctx: ParseCtx,
737  ) -> SyntaxResult<Vec<LiteralTemplatePart>> {
738    let t = self.next().unwrap();
739    let is_end = match t.typ {
740      TokenType::LiteralTemplatePartString => false,
741      TokenType::LiteralTemplatePartStringEnd => true,
742      _ => unreachable!(),
743    };
744
745    let mut loc = t.loc;
746    let mut parts = Vec::new();
747    parts.push(LiteralTemplatePart::String(
748      normalise_literal_string_or_template_inner(self.bytes(t.loc))
749        .ok_or_else(|| t.loc.error(SyntaxErrorType::InvalidCharacterEscape, None))?,
750    ));
751    if !is_end {
752      loop {
753        let substitution = self.parse_expr(ctx, TokenType::BraceClose)?;
754        self.require(TokenType::BraceClose)?;
755        parts.push(LiteralTemplatePart::Substitution(substitution));
756        let string = lex_template_string_continue(self.lexer_mut(), false)?;
757        loc.extend(string.loc);
758        parts.push(LiteralTemplatePart::String(
759          normalise_literal_string_or_template_inner(self.bytes(string.loc)).ok_or_else(|| {
760            string
761              .loc
762              .error(SyntaxErrorType::InvalidCharacterEscape, None)
763          })?,
764        ));
765        self.clear_buffered();
766        match string.typ {
767          TokenType::LiteralTemplatePartStringEnd => break,
768          _ => {}
769        };
770      }
771    };
772
773    Ok(parts)
774  }
775
776  fn parse_expr_operand(
777    &mut self,
778    ctx: ParseCtx,
779    terminator_a: TokenType,
780    terminator_b: TokenType,
781    asi: &mut Asi,
782  ) -> SyntaxResult<Node> {
783    let cp = self.checkpoint();
784    let t = self.next_with_mode(LexMode::SlashIsRegex)?;
785    let operand = match UNARY_OPERATOR_MAPPING.get(&t.typ) {
786      Some(operator)
787        if (
788          // TODO Is this correct? Should it be possible to use as operator or keyword depending on whether there is an operand following?
789          (operator.name != OperatorName::Await && operator.name != OperatorName::Yield)
790            || (operator.name == OperatorName::Await && !ctx.rules.await_allowed)
791            || (operator.name == OperatorName::Yield && !ctx.rules.yield_allowed)
792        ) =>
793      {
794        let operator = if operator.name == OperatorName::Yield
795          && self.consume_if(TokenType::Asterisk)?.is_match()
796        {
797          &OPERATORS[&OperatorName::YieldDelegated]
798        } else {
799          *operator
800        };
801        let next_min_prec =
802          operator.precedence + (operator.associativity == Associativity::Left) as u8;
803        let operand = self.parse_expr_with_min_prec(
804          ctx,
805          next_min_prec,
806          terminator_a,
807          terminator_b,
808          false,
809          asi,
810        )?;
811        Node::new(t.loc + operand.loc, Syntax::UnaryExpr {
812          parenthesised: false,
813          operator: operator.name,
814          argument: operand,
815        })
816      }
817      _ => {
818        match t.typ {
819          TokenType::BracketOpen => {
820            self.restore_checkpoint(cp);
821            self.parse_expr_array(ctx)?
822          }
823          TokenType::BraceOpen => {
824            self.restore_checkpoint(cp);
825            self.parse_expr_object(ctx)?
826          }
827          TokenType::ChevronLeft => {
828            self.restore_checkpoint(cp);
829            self.parse_jsx_element(ctx)?
830          }
831          // Check this before is_valid_pattern_identifier.
832          TokenType::KeywordAsync => {
833            match self.peek()?.typ {
834              TokenType::ParenthesisOpen => {
835                self.restore_checkpoint(cp);
836                self.parse_expr_arrow_function(ctx, terminator_a, terminator_b)?
837              }
838              TokenType::KeywordFunction => {
839                self.restore_checkpoint(cp);
840                self.parse_expr_function(ctx)?
841              }
842              _ => {
843                // `await` is being used as an identifier.
844                Node::new(t.loc, Syntax::IdentifierExpr {
845                  name: self.string(t.loc),
846                })
847              }
848            }
849          }
850          typ if is_valid_pattern_identifier(typ, ctx.rules) => {
851            if self.peek()?.typ == TokenType::EqualsChevronRight {
852              // Single-unparenthesised-parameter arrow function.
853              // NOTE: `await` is not allowed as an arrow function parameter, but we'll check this in parse_expr_arrow_function.
854              self.restore_checkpoint(cp);
855              self.parse_expr_arrow_function(ctx, terminator_a, terminator_b)?
856            } else {
857              Node::new(t.loc, Syntax::IdentifierExpr {
858                name: self.string(t.loc),
859              })
860            }
861          }
862          TokenType::KeywordClass => {
863            self.restore_checkpoint(cp);
864            self.parse_expr_class(ctx)?
865          }
866          TokenType::KeywordFunction => {
867            self.restore_checkpoint(cp);
868            self.parse_expr_function(ctx)?
869          }
870          TokenType::KeywordImport => {
871            self.restore_checkpoint(cp);
872            self.parse_expr_import(ctx)?
873          }
874          TokenType::KeywordSuper => Node::new(t.loc, Syntax::SuperExpr {}),
875          TokenType::KeywordThis => Node::new(t.loc, Syntax::ThisExpr {}),
876          TokenType::LiteralBigInt => Node::new(t.loc, Syntax::LiteralBigIntExpr {
877            value: normalise_literal_bigint(self.str(t.loc))
878              .ok_or_else(|| t.loc.error(SyntaxErrorType::MalformedLiteralBigInt, None))?,
879          }),
880          TokenType::LiteralTrue | TokenType::LiteralFalse => {
881            Node::new(t.loc, Syntax::LiteralBooleanExpr {
882              value: t.typ == TokenType::LiteralTrue,
883            })
884          }
885          TokenType::LiteralNull => Node::new(t.loc, Syntax::LiteralNull {}),
886          TokenType::LiteralNumber => Node::new(t.loc, Syntax::LiteralNumberExpr {
887            value: normalise_literal_number(self.str(t.loc))
888              .ok_or_else(|| t.loc.error(SyntaxErrorType::MalformedLiteralNumber, None))?,
889          }),
890          TokenType::LiteralRegex => Node::new(t.loc, Syntax::LiteralRegexExpr {
891            value: self.string(t.loc),
892          }),
893          TokenType::LiteralString => Node::new(t.loc, Syntax::LiteralStringExpr {
894            value: normalise_literal_string(self.str(t.loc))
895              .ok_or_else(|| t.loc.error(SyntaxErrorType::InvalidCharacterEscape, None))?,
896          }),
897          TokenType::LiteralTemplatePartString | TokenType::LiteralTemplatePartStringEnd => {
898            self.restore_checkpoint(cp);
899            let parts = self.parse_expr_literal_template_parts(ctx)?;
900            Node::new(t.loc, Syntax::LiteralTemplateExpr { parts })
901          }
902          TokenType::ParenthesisOpen => {
903            self.restore_checkpoint(cp);
904            self.parse_expr_arrow_function_or_grouping(ctx, terminator_a, terminator_b, asi)?
905          }
906          _ => return Err(t.error(SyntaxErrorType::ExpectedSyntax("expression operand"))),
907        }
908      }
909    };
910    Ok(operand)
911  }
912
913  pub fn parse_expr_with_min_prec(
914    &mut self,
915    ctx: ParseCtx,
916    min_prec: u8,
917    terminator_a: TokenType,
918    terminator_b: TokenType,
919    parenthesised: bool,
920    asi: &mut Asi,
921  ) -> SyntaxResult<Node> {
922    let mut left = self.parse_expr_operand(ctx, terminator_a, terminator_b, asi)?;
923
924    loop {
925      let cp = self.checkpoint();
926      let t = self.next()?;
927
928      if t.typ == terminator_a || t.typ == terminator_b {
929        self.restore_checkpoint(cp);
930        break;
931      };
932
933      match t.typ {
934        // Automatic Semicolon Insertion rules: no newline between operand and postfix operator.
935        TokenType::PlusPlus | TokenType::HyphenHyphen if !t.preceded_by_line_terminator => {
936          let operator_name = match t.typ {
937            TokenType::PlusPlus => OperatorName::PostfixIncrement,
938            TokenType::HyphenHyphen => OperatorName::PostfixDecrement,
939            _ => unreachable!(),
940          };
941          let operator = &OPERATORS[&operator_name];
942          if operator.precedence < min_prec {
943            self.restore_checkpoint(cp);
944            break;
945          };
946          left = Node::new(left.loc + t.loc, Syntax::UnaryPostfixExpr {
947            parenthesised: false,
948            operator: operator_name,
949            argument: left,
950          });
951          continue;
952        }
953        // Automatic Semicolon Insertion rules: no newline between operand and template literal.
954        TokenType::LiteralTemplatePartString | TokenType::LiteralTemplatePartStringEnd
955          if !t.preceded_by_line_terminator =>
956        {
957          let loc = t.loc;
958          self.restore_checkpoint(cp);
959          let parts = self.parse_expr_literal_template_parts(ctx)?;
960          left = Node::new(left.loc + loc, Syntax::TaggedTemplateExpr {
961            function: left,
962            parts,
963          });
964          continue;
965        }
966        _ => {}
967      };
968
969      match MULTARY_OPERATOR_MAPPING.get(&t.typ) {
970        None => {
971          if asi.can_end_with_asi
972            && (t.preceded_by_line_terminator
973              || t.typ == TokenType::BraceClose
974              || t.typ == TokenType::EOF)
975          {
976            // Automatic Semicolon Insertion.
977            // TODO Exceptions (e.g. for loop header).
978            self.restore_checkpoint(cp);
979            asi.did_end_with_asi = true;
980            break;
981          };
982          return Err(t.error(SyntaxErrorType::ExpectedSyntax("expression operator")));
983        }
984        Some(operator) => {
985          if operator.precedence < min_prec {
986            self.restore_checkpoint(cp);
987            break;
988          };
989
990          let next_min_prec =
991            operator.precedence + (operator.associativity == Associativity::Left) as u8;
992
993          left = match operator.name {
994            OperatorName::Call | OperatorName::OptionalChainingCall => {
995              let arguments = self.parse_call_args(ctx)?;
996              let end = self.require(TokenType::ParenthesisClose)?;
997              Node::new(left.loc + end.loc, Syntax::CallExpr {
998                parenthesised: false,
999                optional_chaining: match operator.name {
1000                  OperatorName::OptionalChainingCall => true,
1001                  _ => false,
1002                },
1003                arguments,
1004                callee: left,
1005              })
1006            }
1007            OperatorName::ComputedMemberAccess
1008            | OperatorName::OptionalChainingComputedMemberAccess => {
1009              let member = self.parse_expr(ctx, TokenType::BracketClose)?;
1010              let end = self.require(TokenType::BracketClose)?;
1011              Node::new(left.loc + end.loc, Syntax::ComputedMemberExpr {
1012                optional_chaining: match operator.name {
1013                  OperatorName::OptionalChainingComputedMemberAccess => true,
1014                  _ => false,
1015                },
1016                object: left,
1017                member,
1018              })
1019            }
1020            OperatorName::Conditional => {
1021              let consequent = self.parse_expr(ctx, TokenType::Colon)?;
1022              self.require(TokenType::Colon)?;
1023              let alternate = self.parse_expr_with_min_prec(
1024                ctx,
1025                OPERATORS[&OperatorName::ConditionalAlternate].precedence,
1026                terminator_a,
1027                terminator_b,
1028                false,
1029                asi,
1030              )?;
1031              Node::new(left.loc + alternate.loc, Syntax::ConditionalExpr {
1032                parenthesised: false,
1033                test: left,
1034                consequent,
1035                alternate,
1036              })
1037            }
1038            OperatorName::MemberAccess | OperatorName::OptionalChainingMemberAccess => {
1039              let right_tok = self.next()?;
1040              match right_tok.typ {
1041                TokenType::Identifier => {}
1042                TokenType::PrivateMember => {}
1043                t if KEYWORDS_MAPPING.contains_key(&t) => {}
1044                _ => {
1045                  return Err(
1046                    right_tok.error(SyntaxErrorType::ExpectedSyntax("member access property")),
1047                  )
1048                }
1049              };
1050              let right = right_tok.loc;
1051              Node::new(left.loc + right, Syntax::MemberExpr {
1052                parenthesised: false,
1053                optional_chaining: match operator.name {
1054                  OperatorName::OptionalChainingMemberAccess => true,
1055                  _ => false,
1056                },
1057                left,
1058                right: self.string(right),
1059              })
1060            }
1061            _ => {
1062              if operator.name.is_assignment() {
1063                left = self.convert_assignment_lhs_to_target(ctx, left, operator.name)?;
1064              };
1065              let right = self.parse_expr_with_min_prec(
1066                ctx,
1067                next_min_prec,
1068                terminator_a,
1069                terminator_b,
1070                false,
1071                asi,
1072              )?;
1073              Node::new(left.loc + right.loc, Syntax::BinaryExpr {
1074                parenthesised: false,
1075                operator: operator.name,
1076                left,
1077                right,
1078              })
1079            }
1080          };
1081        }
1082      };
1083    }
1084
1085    if parenthesised {
1086      match left.stx.as_mut() {
1087        Syntax::ArrowFunctionExpr { parenthesised, .. }
1088        | Syntax::BinaryExpr { parenthesised, .. }
1089        | Syntax::CallExpr { parenthesised, .. }
1090        | Syntax::ConditionalExpr { parenthesised, .. }
1091        | Syntax::FunctionExpr { parenthesised, .. }
1092        | Syntax::MemberExpr { parenthesised, .. }
1093        | Syntax::UnaryExpr { parenthesised, .. } => {
1094          *parenthesised = true;
1095        }
1096        _ => {}
1097      };
1098    };
1099
1100    Ok(left)
1101  }
1102}