summaryrefslogtreecommitdiffstats
path: root/third_party/rust/jsparagus-generated-parser/src/ast_builder.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
commit36d22d82aa202bb199967e9512281e9a53db42c9 (patch)
tree105e8c98ddea1c1e4784a60a5a6410fa416be2de /third_party/rust/jsparagus-generated-parser/src/ast_builder.rs
parentInitial commit. (diff)
downloadfirefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz
firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/jsparagus-generated-parser/src/ast_builder.rs')
-rw-r--r--third_party/rust/jsparagus-generated-parser/src/ast_builder.rs4666
1 files changed, 4666 insertions, 0 deletions
diff --git a/third_party/rust/jsparagus-generated-parser/src/ast_builder.rs b/third_party/rust/jsparagus-generated-parser/src/ast_builder.rs
new file mode 100644
index 0000000000..321872d05b
--- /dev/null
+++ b/third_party/rust/jsparagus-generated-parser/src/ast_builder.rs
@@ -0,0 +1,4666 @@
+use crate::context_stack::{BindingKind, ContextMetadata, ControlInfo, LabelKind};
+use crate::early_error_checker::EarlyErrorChecker;
+use crate::error::{BoxedParseError, ParseError, Result};
+use crate::Token;
+use ast::{
+ arena,
+ source_atom_set::{CommonSourceAtomSetIndices, SourceAtomSet},
+ source_location_accessor::SourceLocationAccessor,
+ source_slice_list::SourceSliceList,
+ types::*,
+ SourceLocation,
+};
+use bumpalo::{vec, Bump};
+use std::cell::RefCell;
+use std::rc::Rc;
+
+pub struct AstBuilder<'alloc> {
+ pub allocator: &'alloc Bump,
+
+ context_metadata: ContextMetadata,
+
+ atoms: Rc<RefCell<SourceAtomSet<'alloc>>>,
+
+ slices: Rc<RefCell<SourceSliceList<'alloc>>>,
+}
+
+pub trait AstBuilderDelegate<'alloc> {
+ fn ast_builder_refmut(&mut self) -> &mut AstBuilder<'alloc>;
+}
+
+impl<'alloc> AstBuilder<'alloc> {
+ pub fn new(
+ allocator: &'alloc Bump,
+ atoms: Rc<RefCell<SourceAtomSet<'alloc>>>,
+ slices: Rc<RefCell<SourceSliceList<'alloc>>>,
+ ) -> Self {
+ Self {
+ allocator,
+ context_metadata: ContextMetadata::new(),
+ atoms,
+ slices,
+ }
+ }
+
+ pub fn alloc<T>(&self, value: T) -> arena::Box<'alloc, T> {
+ arena::alloc(self.allocator, value)
+ }
+
+ pub fn alloc_with<F, T>(&self, gen: F) -> arena::Box<'alloc, T>
+ where
+ F: FnOnce() -> T,
+ {
+ arena::alloc_with(self.allocator, gen)
+ }
+
+ pub fn alloc_str(&self, s: &str) -> &'alloc str {
+ arena::alloc_str(self.allocator, s)
+ }
+
+ fn new_vec<T>(&self) -> arena::Vec<'alloc, T> {
+ arena::Vec::new_in(self.allocator)
+ }
+
+ fn new_vec_single<T>(&self, value: T) -> arena::Vec<'alloc, T> {
+ vec![in self.allocator; value]
+ }
+
+ fn collect_vec_from_results<T, C>(&self, results: C) -> Result<'alloc, arena::Vec<'alloc, T>>
+ where
+ C: IntoIterator<Item = Result<'alloc, T>>,
+ {
+ let mut out = self.new_vec();
+ for result in results {
+ out.push(result?);
+ }
+ Ok(out)
+ }
+
+ fn push<T>(&self, list: &mut arena::Vec<'alloc, T>, value: T) {
+ list.push(value);
+ }
+
+ fn append<T>(&self, list: &mut arena::Vec<'alloc, T>, elements: &mut arena::Vec<'alloc, T>) {
+ list.append(elements);
+ }
+
+ // IdentifierReference : Identifier
+ pub fn identifier_reference(
+ &self,
+ token: arena::Box<'alloc, Token>,
+ ) -> Result<'alloc, arena::Box<'alloc, Identifier>> {
+ self.on_identifier_reference(&token)?;
+ Ok(self.alloc_with(|| self.identifier(token)))
+ }
+
+ // BindingIdentifier : Identifier
+ pub fn binding_identifier(
+ &mut self,
+ token: arena::Box<'alloc, Token>,
+ ) -> Result<'alloc, arena::Box<'alloc, BindingIdentifier>> {
+ self.on_binding_identifier(&token)?;
+ let loc = token.loc;
+ Ok(self.alloc_with(|| BindingIdentifier {
+ name: self.identifier(token),
+ loc,
+ }))
+ }
+
+ // BindingIdentifier : `yield`
+ pub fn binding_identifier_yield(
+ &mut self,
+ token: arena::Box<'alloc, Token>,
+ ) -> Result<'alloc, arena::Box<'alloc, BindingIdentifier>> {
+ self.on_binding_identifier(&token)?;
+ let loc = token.loc;
+ Ok(self.alloc_with(|| BindingIdentifier {
+ name: Identifier {
+ value: CommonSourceAtomSetIndices::yield_(),
+ loc,
+ },
+ loc,
+ }))
+ }
+
+ // BindingIdentifier : `await`
+ pub fn binding_identifier_await(
+ &mut self,
+ token: arena::Box<'alloc, Token>,
+ ) -> Result<'alloc, arena::Box<'alloc, BindingIdentifier>> {
+ self.on_binding_identifier(&token)?;
+ let loc = token.loc;
+ Ok(self.alloc_with(|| BindingIdentifier {
+ name: Identifier {
+ value: CommonSourceAtomSetIndices::await_(),
+ loc,
+ },
+ loc,
+ }))
+ }
+
+ // LabelIdentifier : Identifier
+ pub fn label_identifier(
+ &mut self,
+ token: arena::Box<'alloc, Token>,
+ ) -> Result<'alloc, arena::Box<'alloc, Label>> {
+ self.on_label_identifier(&token)?;
+ let loc = token.loc;
+ Ok(self.alloc_with(|| Label {
+ value: token.value.as_atom(),
+ loc,
+ }))
+ }
+
+ // PrimaryExpression : `this`
+ pub fn this_expr(
+ &self,
+ token: arena::Box<'alloc, Token>,
+ ) -> arena::Box<'alloc, Expression<'alloc>> {
+ let loc = token.loc;
+ self.alloc_with(|| Expression::ThisExpression { loc })
+ }
+
+ // PrimaryExpression : IdentifierReference
+ pub fn identifier_expr(
+ &self,
+ name: arena::Box<'alloc, Identifier>,
+ ) -> arena::Box<'alloc, Expression<'alloc>> {
+ let loc = name.loc;
+ self.alloc_with(|| {
+ Expression::IdentifierExpression(IdentifierExpression {
+ name: name.unbox(),
+ loc,
+ })
+ })
+ }
+
+ // PrimaryExpression : RegularExpressionLiteral
+ pub fn regexp_literal(
+ &self,
+ token: arena::Box<'alloc, Token>,
+ ) -> arena::Box<'alloc, Expression<'alloc>> {
+ let source = self.slices.borrow().get(token.value.as_slice());
+
+ debug_assert!(source.chars().nth(0).unwrap() == '/');
+
+ let end = source.rfind('/').unwrap();
+
+ let pattern = self.slices.borrow_mut().push(&source[1..end]);
+ let flags = &source[end + 1..];
+
+ let mut global: bool = false;
+ let mut ignore_case: bool = false;
+ let mut multi_line: bool = false;
+ let mut dot_all: bool = false;
+ let mut unicode: bool = false;
+ let mut sticky: bool = false;
+ for c in flags.chars() {
+ if c == 'g' {
+ global = true;
+ }
+ if c == 'i' {
+ ignore_case = true;
+ }
+ if c == 'm' {
+ multi_line = true;
+ }
+ if c == 's' {
+ dot_all = true;
+ }
+ if c == 'u' {
+ unicode = true;
+ }
+ if c == 'y' {
+ sticky = true;
+ }
+ }
+
+ let loc = token.loc;
+ self.alloc_with(|| Expression::LiteralRegExpExpression {
+ pattern,
+ global,
+ ignore_case,
+ multi_line,
+ dot_all,
+ sticky,
+ unicode,
+ loc,
+ })
+ }
+
+ // PrimaryExpression : TemplateLiteral
+ pub fn untagged_template_expr(
+ &self,
+ template_literal: arena::Box<'alloc, TemplateExpression<'alloc>>,
+ ) -> arena::Box<'alloc, Expression<'alloc>> {
+ self.alloc_with(|| Expression::TemplateExpression(template_literal.unbox()))
+ }
+
+ // PrimaryExpression : CoverParenthesizedExpressionAndArrowParameterList
+ pub fn uncover_parenthesized_expression(
+ &self,
+ parenthesized: arena::Box<'alloc, CoverParenthesized<'alloc>>,
+ ) -> Result<'alloc, arena::Box<'alloc, Expression<'alloc>>> {
+ match parenthesized.unbox() {
+ CoverParenthesized::Expression { expression, .. } => {
+ // TODO - does this need to rewalk the expression to look for
+ // invalid ObjectPattern or ArrayPattern syntax?
+ Ok(expression)
+ }
+ CoverParenthesized::Parameters(_parameters) => Err(ParseError::NotImplemented(
+ "parenthesized expression with `...` should be a syntax error",
+ )
+ .into()),
+ }
+ }
+
+ // CoverParenthesizedExpressionAndArrowParameterList : `(` Expression `)`
+ pub fn cover_parenthesized_expression(
+ &self,
+ open_token: arena::Box<'alloc, Token>,
+ expression: arena::Box<'alloc, Expression<'alloc>>,
+ close_token: arena::Box<'alloc, Token>,
+ ) -> arena::Box<'alloc, CoverParenthesized<'alloc>> {
+ self.alloc_with(|| CoverParenthesized::Expression {
+ expression,
+ loc: SourceLocation::from_parts(open_token.loc, close_token.loc),
+ })
+ }
+
+ // CoverParenthesizedExpressionAndArrowParameterList : `(` `)`
+ pub fn empty_parameter_list(&self) -> arena::Vec<'alloc, Parameter<'alloc>> {
+ self.new_vec()
+ }
+
+ /// Used when parsing `([a, b=2]=arr) =>` to reinterpret as parameter bindings
+ /// the snippets `a` and `b=2`, which were previously parsed as assignment targets.
+ fn assignment_target_maybe_default_to_binding(
+ &self,
+ target: AssignmentTargetMaybeDefault<'alloc>,
+ ) -> Result<'alloc, Parameter<'alloc>> {
+ match target {
+ AssignmentTargetMaybeDefault::AssignmentTarget(target) => Ok(Parameter::Binding(
+ self.assignment_target_to_binding(target)?,
+ )),
+
+ AssignmentTargetMaybeDefault::AssignmentTargetWithDefault(
+ AssignmentTargetWithDefault { binding, init, loc },
+ ) => Ok(Parameter::BindingWithDefault(BindingWithDefault {
+ binding: self.assignment_target_to_binding(binding)?,
+ init,
+ loc,
+ })),
+ }
+ }
+
+ fn assignment_target_property_to_binding_property(
+ &self,
+ target: AssignmentTargetProperty<'alloc>,
+ ) -> Result<'alloc, BindingProperty<'alloc>> {
+ Ok(match target {
+ AssignmentTargetProperty::AssignmentTargetPropertyIdentifier(
+ AssignmentTargetPropertyIdentifier {
+ binding: AssignmentTargetIdentifier { name, loc },
+ init,
+ loc: loc2,
+ },
+ ) => BindingProperty::BindingPropertyIdentifier(BindingPropertyIdentifier {
+ binding: BindingIdentifier { name, loc },
+ init,
+ loc: loc2,
+ }),
+
+ AssignmentTargetProperty::AssignmentTargetPropertyProperty(
+ AssignmentTargetPropertyProperty { name, binding, loc },
+ ) => BindingProperty::BindingPropertyProperty(BindingPropertyProperty {
+ name,
+ binding: self.assignment_target_maybe_default_to_binding(binding)?,
+ loc,
+ }),
+ })
+ }
+
+ /// Refine an AssignmentRestProperty into a BindingRestProperty.
+ fn assignment_rest_property_to_binding_identifier(
+ &self,
+ target: AssignmentTarget<'alloc>,
+ ) -> Result<'alloc, arena::Box<'alloc, BindingIdentifier>> {
+ match target {
+ // ({...x} = dv) => {}
+ AssignmentTarget::SimpleAssignmentTarget(
+ SimpleAssignmentTarget::AssignmentTargetIdentifier(AssignmentTargetIdentifier {
+ name,
+ loc,
+ }),
+ ) => Ok(self.alloc_with(|| BindingIdentifier { name, loc })),
+
+ // ({...x.y} = dv) => {}
+ _ => Err(ParseError::ObjectBindingPatternWithInvalidRest.into()),
+ }
+ }
+
+ /// Refine the left-hand side of `=` to a parameter binding. The spec says:
+ ///
+ /// > When the production *ArrowParameters* :
+ /// > *CoverParenthesizedExpressionAndArrowParameterList* is recognized,
+ /// > the following grammar is used to refine the interpretation of
+ /// > *CoverParenthesizedExpressionAndArrowParameterList*:
+ /// >
+ /// > *ArrowFormalParameters*\[Yield, Await\] :
+ /// > `(` *UniqueFormalParameters*\[?Yield, ?Await\] `)`
+ ///
+ /// Of course, rather than actually reparsing the arrow function parameters,
+ /// we work by refining the AST we already built.
+ ///
+ /// When parsing `(a = 1, [b, c] = obj) => {}`, the assignment targets `a`
+ /// and `[b, c]` are passed to this method.
+ fn assignment_target_to_binding(
+ &self,
+ target: AssignmentTarget<'alloc>,
+ ) -> Result<'alloc, Binding<'alloc>> {
+ match target {
+ // (a = dv) => {}
+ AssignmentTarget::SimpleAssignmentTarget(
+ SimpleAssignmentTarget::AssignmentTargetIdentifier(AssignmentTargetIdentifier {
+ name,
+ loc,
+ }),
+ ) => Ok(Binding::BindingIdentifier(BindingIdentifier { name, loc })),
+
+ // This case is always an early SyntaxError.
+ // (a.x = dv) => {}
+ // (a[i] = dv) => {}
+ AssignmentTarget::SimpleAssignmentTarget(
+ SimpleAssignmentTarget::MemberAssignmentTarget(_),
+ ) => Err(ParseError::InvalidParameter.into()),
+
+ // ([a, b] = dv) => {}
+ AssignmentTarget::AssignmentTargetPattern(
+ AssignmentTargetPattern::ArrayAssignmentTarget(ArrayAssignmentTarget {
+ elements,
+ rest,
+ loc,
+ }),
+ ) => {
+ let elements: arena::Vec<'alloc, Option<AssignmentTargetMaybeDefault<'alloc>>> =
+ elements;
+ let elements: arena::Vec<'alloc, Option<Parameter<'alloc>>> = self
+ .collect_vec_from_results(elements.into_iter().map(|maybe_target| {
+ maybe_target
+ .map(|target| self.assignment_target_maybe_default_to_binding(target))
+ .transpose()
+ }))?;
+ let rest: Option<Result<'alloc, arena::Box<'alloc, Binding<'alloc>>>> = rest.map(
+ |rest_target| -> Result<'alloc, arena::Box<'alloc, Binding<'alloc>>> {
+ Ok(self.alloc(self.assignment_target_to_binding(rest_target.unbox())?))
+ },
+ );
+ let rest: Option<arena::Box<'alloc, Binding<'alloc>>> = rest.transpose()?;
+ Ok(Binding::BindingPattern(BindingPattern::ArrayBinding(
+ ArrayBinding {
+ elements,
+ rest,
+ loc,
+ },
+ )))
+ }
+
+ // ({a, b: c} = dv) => {}
+ AssignmentTarget::AssignmentTargetPattern(
+ AssignmentTargetPattern::ObjectAssignmentTarget(ObjectAssignmentTarget {
+ properties,
+ rest,
+ loc,
+ }),
+ ) => {
+ let properties =
+ self.collect_vec_from_results(properties.into_iter().map(|target| {
+ self.assignment_target_property_to_binding_property(target)
+ }))?;
+
+ let rest = if let Some(rest_target) = rest {
+ Some(self.assignment_rest_property_to_binding_identifier(rest_target.unbox())?)
+ } else {
+ None
+ };
+ Ok(Binding::BindingPattern(BindingPattern::ObjectBinding(
+ ObjectBinding {
+ properties,
+ rest,
+ loc,
+ },
+ )))
+ }
+ }
+ }
+
+ fn object_property_to_binding_property(
+ &self,
+ op: ObjectProperty<'alloc>,
+ ) -> Result<'alloc, BindingProperty<'alloc>> {
+ match op {
+ ObjectProperty::NamedObjectProperty(NamedObjectProperty::DataProperty(
+ DataProperty {
+ property_name,
+ expression,
+ loc,
+ },
+ )) => Ok(BindingProperty::BindingPropertyProperty(
+ BindingPropertyProperty {
+ name: property_name,
+ binding: self.expression_to_parameter(expression.unbox())?,
+ loc,
+ },
+ )),
+
+ ObjectProperty::NamedObjectProperty(NamedObjectProperty::MethodDefinition(_)) => {
+ Err(ParseError::ObjectPatternWithMethod.into())
+ }
+
+ ObjectProperty::ShorthandProperty(ShorthandProperty {
+ name: IdentifierExpression { name, loc },
+ ..
+ }) => {
+ // TODO - CoverInitializedName can't be represented in an
+ // ObjectProperty, but we need it here.
+ Ok(BindingProperty::BindingPropertyIdentifier(
+ BindingPropertyIdentifier {
+ binding: BindingIdentifier { name, loc },
+ init: None,
+ loc,
+ },
+ ))
+ }
+
+ ObjectProperty::SpreadProperty(_expression) => {
+ Err(ParseError::ObjectPatternWithNonFinalRest.into())
+ }
+ }
+ }
+
+ /// Refine an instance of "*PropertyDefinition* : `...`
+ /// *AssignmentExpression*" into a *BindingRestProperty*.
+ fn spread_expression_to_rest_binding(
+ &self,
+ expression: arena::Box<'alloc, Expression<'alloc>>,
+ ) -> Result<'alloc, arena::Box<'alloc, BindingIdentifier>> {
+ Ok(match expression.unbox() {
+ Expression::IdentifierExpression(IdentifierExpression { name, loc }) => {
+ self.alloc_with(|| BindingIdentifier { name, loc })
+ }
+ _ => {
+ return Err(ParseError::ObjectBindingPatternWithInvalidRest.into());
+ }
+ })
+ }
+
+ fn pop_trailing_spread_property(
+ &self,
+ properties: &mut arena::Vec<'alloc, arena::Box<'alloc, ObjectProperty<'alloc>>>,
+ ) -> Option<arena::Box<'alloc, Expression<'alloc>>> {
+ // Check whether we want to pop a PropertyDefinition
+ match properties.last().map(|boxed| &**boxed) {
+ Some(ObjectProperty::SpreadProperty(_)) => {}
+ _ => return None,
+ }
+
+ // We do.
+ match properties.pop().unwrap().unbox() {
+ ObjectProperty::SpreadProperty(expression) => Some(expression),
+ _ => panic!("bug"), // can't happen: we just checked this above
+ }
+ }
+
+ /// Refine an *ObjectLiteral* into an *ObjectBindingPattern*.
+ fn object_expression_to_object_binding(
+ &self,
+ object: ObjectExpression<'alloc>,
+ ) -> Result<'alloc, ObjectBinding<'alloc>> {
+ let mut properties = object.properties;
+ let loc = object.loc;
+ let rest = self.pop_trailing_spread_property(&mut properties);
+ Ok(ObjectBinding {
+ properties: self.collect_vec_from_results(
+ properties
+ .into_iter()
+ .map(|prop| self.object_property_to_binding_property(prop.unbox())),
+ )?,
+ rest: rest
+ .map(|expression| self.spread_expression_to_rest_binding(expression))
+ .transpose()?,
+ loc,
+ })
+ }
+
+ fn array_elements_to_parameters(
+ &self,
+ elements: arena::Vec<'alloc, ArrayExpressionElement<'alloc>>,
+ ) -> Result<'alloc, arena::Vec<'alloc, Option<Parameter<'alloc>>>> {
+ self.collect_vec_from_results(elements.into_iter().map(|element| match element {
+ ArrayExpressionElement::Expression(expr) =>
+ Ok(Some(self.expression_to_parameter(expr.unbox())?)),
+ ArrayExpressionElement::SpreadElement(_expr) =>
+ // ([...a, b]) => {}
+ Err(ParseError::ArrayPatternWithNonFinalRest.into()),
+ ArrayExpressionElement::Elision { .. } => Ok(None),
+ }))
+ }
+
+ fn pop_trailing_spread_element(
+ &self,
+ elements: &mut arena::Vec<'alloc, ArrayExpressionElement<'alloc>>,
+ ) -> Option<arena::Box<'alloc, Expression<'alloc>>> {
+ // Check whether we want to pop an element.
+ match elements.last() {
+ Some(ArrayExpressionElement::SpreadElement(_)) => {}
+ _ => return None,
+ }
+
+ // We do.
+ match elements.pop() {
+ Some(ArrayExpressionElement::SpreadElement(expression)) => Some(expression),
+ _ => panic!("bug"), // can't happen: we just checked this above
+ }
+ }
+
+ fn expression_to_binding_no_default(
+ &self,
+ expression: Expression<'alloc>,
+ ) -> Result<'alloc, Binding<'alloc>> {
+ match expression {
+ Expression::IdentifierExpression(IdentifierExpression { name, loc }) => {
+ Ok(Binding::BindingIdentifier(BindingIdentifier { name, loc }))
+ }
+
+ Expression::ArrayExpression(ArrayExpression { mut elements, loc }) => {
+ let rest = self.pop_trailing_spread_element(&mut elements);
+ let elements = self.array_elements_to_parameters(elements)?;
+ let rest = rest
+ .map(|expr| match self.expression_to_parameter(expr.unbox())? {
+ Parameter::Binding(b) => Ok(self.alloc_with(|| b)),
+ Parameter::BindingWithDefault(_) => {
+ let err: BoxedParseError =
+ ParseError::ArrayBindingPatternWithInvalidRest.into();
+ Err(err)
+ }
+ })
+ .transpose()?;
+ Ok(Binding::BindingPattern(BindingPattern::ArrayBinding(
+ ArrayBinding {
+ elements,
+ rest,
+ loc,
+ },
+ )))
+ }
+
+ Expression::ObjectExpression(object) => Ok(Binding::BindingPattern(
+ BindingPattern::ObjectBinding(self.object_expression_to_object_binding(object)?),
+ )),
+
+ _ => Err(ParseError::InvalidParameter.into()),
+ }
+ }
+
+ fn expression_to_parameter(
+ &self,
+ expression: Expression<'alloc>,
+ ) -> Result<'alloc, Parameter<'alloc>> {
+ match expression {
+ Expression::AssignmentExpression {
+ binding,
+ expression,
+ loc,
+ } => Ok(Parameter::BindingWithDefault(BindingWithDefault {
+ binding: self.assignment_target_to_binding(binding)?,
+ init: expression,
+ loc,
+ })),
+
+ other => Ok(Parameter::Binding(
+ self.expression_to_binding_no_default(other)?,
+ )),
+ }
+ }
+
+ // CoverParenthesizedExpressionAndArrowParameterList : `(` Expression `,` `)`
+ // CoverParenthesizedExpressionAndArrowParameterList : `(` Expression `,` `...` BindingIdentifier `)`
+ // CoverParenthesizedExpressionAndArrowParameterList : `(` Expression `,` `...` BindingPattern `)`
+ pub fn expression_to_parameter_list(
+ &self,
+ expression: arena::Box<'alloc, Expression<'alloc>>,
+ ) -> Result<'alloc, arena::Vec<'alloc, Parameter<'alloc>>> {
+ // When the production
+ // *ArrowParameters* `:` *CoverParenthesizedExpressionAndArrowParameterList*
+ // is recognized the following grammar is used to refine the
+ // interpretation of
+ // *CoverParenthesizedExpressionAndArrowParameterList*:
+ //
+ // ArrowFormalParameters[Yield, Await]:
+ // `(` UniqueFormalParameters[?Yield, ?Await] `)`
+ match expression.unbox() {
+ Expression::BinaryExpression {
+ operator: BinaryOperator::Comma { .. },
+ left,
+ right,
+ ..
+ } => {
+ let mut parameters = self.expression_to_parameter_list(left)?;
+ self.push(
+ &mut parameters,
+ self.expression_to_parameter(right.unbox())?,
+ );
+ Ok(parameters)
+ }
+ other => Ok(self.new_vec_single(self.expression_to_parameter(other)?)),
+ }
+ }
+
+ /// Used to convert `async(x, y, ...z)` from a *CallExpression* to async
+ /// arrow function parameters.
+ fn arguments_to_parameter_list(
+ &self,
+ arguments: Arguments<'alloc>,
+ ) -> Result<'alloc, arena::Box<'alloc, FormalParameters<'alloc>>> {
+ let loc = arguments.loc;
+ let mut items = self.new_vec();
+ let mut rest: Option<Binding<'alloc>> = None;
+ for arg in arguments.args {
+ if rest.is_some() {
+ return Err(ParseError::ArrowParametersWithNonFinalRest.into());
+ }
+ match arg {
+ Argument::Expression(expr) => {
+ self.push(&mut items, self.expression_to_parameter(expr.unbox())?);
+ }
+ Argument::SpreadElement(spread_expr) => {
+ rest = Some(self.expression_to_binding_no_default(spread_expr.unbox())?);
+ }
+ }
+ }
+ Ok(self.alloc_with(|| FormalParameters { items, rest, loc }))
+ }
+
+ // CoverParenthesizedExpressionAndArrowParameterList : `(` `)`
+ // CoverParenthesizedExpressionAndArrowParameterList : `(` `...` BindingIdentifier `)`
+ // CoverParenthesizedExpressionAndArrowParameterList : `(` `...` BindingPattern `)`
+ // CoverParenthesizedExpressionAndArrowParameterList : `(` Expression `,` `...` BindingIdentifier `)`
+ // CoverParenthesizedExpressionAndArrowParameterList : `(` Expression `,` `...` BindingPattern `)`
+ pub fn cover_arrow_parameter_list(
+ &self,
+ open_token: arena::Box<'alloc, Token>,
+ parameters: arena::Vec<'alloc, Parameter<'alloc>>,
+ rest: Option<arena::Box<'alloc, Binding<'alloc>>>,
+ close_token: arena::Box<'alloc, Token>,
+ ) -> arena::Box<'alloc, CoverParenthesized<'alloc>> {
+ self.alloc_with(|| {
+ CoverParenthesized::Parameters(self.alloc_with(|| FormalParameters {
+ items: parameters,
+ rest: rest.map(|boxed| boxed.unbox()),
+ loc: SourceLocation::from_parts(open_token.loc, close_token.loc),
+ }))
+ })
+ }
+
+ // Literal : NullLiteral
+ pub fn null_literal(
+ &self,
+ token: arena::Box<'alloc, Token>,
+ ) -> arena::Box<'alloc, Expression<'alloc>> {
+ let loc = token.loc;
+ self.alloc_with(|| Expression::LiteralNullExpression { loc })
+ }
+
+ // Literal : BooleanLiteral
+ pub fn boolean_literal(
+ &self,
+ token: arena::Box<'alloc, Token>,
+ ) -> arena::Box<'alloc, Expression<'alloc>> {
+ let loc = token.loc;
+ let s = token.value.as_atom();
+ assert!(
+ s == CommonSourceAtomSetIndices::true_() || s == CommonSourceAtomSetIndices::false_()
+ );
+
+ self.alloc_with(|| Expression::LiteralBooleanExpression {
+ value: s == CommonSourceAtomSetIndices::true_(),
+ loc,
+ })
+ }
+
+ fn numeric_literal_value(token: arena::Box<'alloc, Token>) -> f64 {
+ token.unbox().value.as_number()
+ }
+
+ // Literal : NumericLiteral
+ pub fn numeric_literal(
+ &self,
+ token: arena::Box<'alloc, Token>,
+ ) -> Result<'alloc, arena::Box<'alloc, Expression<'alloc>>> {
+ let loc = token.loc;
+ Ok(self.alloc_with(|| {
+ Expression::LiteralNumericExpression(NumericLiteral {
+ value: Self::numeric_literal_value(token),
+ loc,
+ })
+ }))
+ }
+
+ // Literal : NumericLiteral
+ //
+ // where NumericLiteral is either:
+ // * DecimalBigIntegerLiteral
+ // * NonDecimalIntegerLiteralBigIntLiteralSuffix
+ pub fn bigint_literal(
+ &self,
+ _token: arena::Box<'alloc, Token>,
+ ) -> Result<'alloc, arena::Box<'alloc, Expression<'alloc>>> {
+ Err(ParseError::NotImplemented("BigInt").into())
+ }
+
+ // Literal : StringLiteral
+ pub fn string_literal(
+ &self,
+ token: arena::Box<'alloc, Token>,
+ ) -> Result<'alloc, arena::Box<'alloc, Expression<'alloc>>> {
+ let loc = token.loc;
+ // Hack: Prevent emission for scripts with "use strict"
+ // directive.
+ let value = token.value.as_atom();
+ if value == CommonSourceAtomSetIndices::use_strict() {
+ return Err(ParseError::NotImplemented("use strict directive").into());
+ }
+
+ Ok(self.alloc_with(|| Expression::LiteralStringExpression { value, loc }))
+ }
+
+ // ArrayLiteral : `[` Elision? `]`
+ pub fn array_literal_empty(
+ &self,
+ open_token: arena::Box<'alloc, Token>,
+ elision: Option<arena::Box<'alloc, ArrayExpression<'alloc>>>,
+ close_token: arena::Box<'alloc, Token>,
+ ) -> arena::Box<'alloc, Expression<'alloc>> {
+ self.alloc_with(|| {
+ Expression::ArrayExpression(match elision {
+ None => ArrayExpression {
+ elements: self.new_vec(),
+ loc: SourceLocation::from_parts(open_token.loc, close_token.loc),
+ },
+ Some(mut array) => {
+ array.loc.set_range(open_token.loc, close_token.loc);
+ array.unbox()
+ }
+ })
+ })
+ }
+
+ // ArrayLiteral : `[` ElementList `]`
+ pub fn array_literal(
+ &self,
+ open_token: arena::Box<'alloc, Token>,
+ mut array: arena::Box<'alloc, ArrayExpression<'alloc>>,
+ close_token: arena::Box<'alloc, Token>,
+ ) -> arena::Box<'alloc, Expression<'alloc>> {
+ array.loc.set_range(open_token.loc, close_token.loc);
+ self.alloc_with(|| Expression::ArrayExpression(array.unbox()))
+ }
+
+ // ArrayLiteral : `[` ElementList `,` Elision? `]`
+ pub fn array_literal_with_trailing_elision(
+ &self,
+ open_token: arena::Box<'alloc, Token>,
+ mut array: arena::Box<'alloc, ArrayExpression<'alloc>>,
+ elision: Option<arena::Box<'alloc, ArrayExpression<'alloc>>>,
+ close_token: arena::Box<'alloc, Token>,
+ ) -> arena::Box<'alloc, Expression<'alloc>> {
+ if let Some(mut more) = elision {
+ self.append(&mut array.elements, &mut more.elements);
+ }
+ array.loc.set_range(open_token.loc, close_token.loc);
+ self.alloc_with(|| Expression::ArrayExpression(array.unbox()))
+ }
+
+ // ElementList : Elision? AssignmentExpression
+ pub fn element_list_first(
+ &self,
+ elision: Option<arena::Box<'alloc, ArrayExpression<'alloc>>>,
+ element: arena::Box<'alloc, Expression<'alloc>>,
+ ) -> arena::Box<'alloc, ArrayExpression<'alloc>> {
+ let mut array = elision.unwrap_or_else(|| {
+ self.alloc_with(|| ArrayExpression {
+ elements: self.new_vec(),
+ // This will be overwritten once the enclosing array gets
+ // parsed.
+ loc: SourceLocation::default(),
+ })
+ });
+ self.push(
+ &mut array.elements,
+ ArrayExpressionElement::Expression(element),
+ );
+ array
+ }
+
+ // ElementList : Elision? SpreadElement
+ pub fn element_list_first_spread(
+ &self,
+ elision: Option<arena::Box<'alloc, ArrayExpression<'alloc>>>,
+ spread_element: arena::Box<'alloc, Expression<'alloc>>,
+ ) -> arena::Box<'alloc, ArrayExpression<'alloc>> {
+ let mut array = elision.unwrap_or_else(|| {
+ self.alloc_with(|| ArrayExpression {
+ elements: self.new_vec(),
+ // This will be overwritten once the enclosing array gets
+ // parsed.
+ loc: SourceLocation::default(),
+ })
+ });
+ self.push(
+ &mut array.elements,
+ ArrayExpressionElement::SpreadElement(spread_element),
+ );
+ array
+ }
+
+ // ElementList : ElementList `,` Elision? AssignmentExpression
+ pub fn element_list_append(
+ &self,
+ mut array: arena::Box<'alloc, ArrayExpression<'alloc>>,
+ elision: Option<arena::Box<'alloc, ArrayExpression<'alloc>>>,
+ element: arena::Box<'alloc, Expression<'alloc>>,
+ ) -> arena::Box<'alloc, ArrayExpression<'alloc>> {
+ if let Some(mut elision) = elision {
+ self.append(&mut array.elements, &mut elision.elements);
+ }
+ self.push(
+ &mut array.elements,
+ ArrayExpressionElement::Expression(element),
+ );
+ array
+ }
+
+ // ElementList : ElementList `,` Elision? SpreadElement
+ pub fn element_list_append_spread(
+ &self,
+ mut array: arena::Box<'alloc, ArrayExpression<'alloc>>,
+ elision: Option<arena::Box<'alloc, ArrayExpression<'alloc>>>,
+ spread_element: arena::Box<'alloc, Expression<'alloc>>,
+ ) -> arena::Box<'alloc, ArrayExpression<'alloc>> {
+ if let Some(mut elision) = elision {
+ self.append(&mut array.elements, &mut elision.elements);
+ }
+ self.push(
+ &mut array.elements,
+ ArrayExpressionElement::SpreadElement(spread_element),
+ );
+ array
+ }
+
+ // Elision : `,`
+ pub fn elision_single(
+ &self,
+ token: arena::Box<'alloc, Token>,
+ ) -> arena::Box<'alloc, ArrayExpression<'alloc>> {
+ let loc = token.loc;
+ self.alloc_with(|| ArrayExpression {
+ elements: self.new_vec_single(ArrayExpressionElement::Elision { loc }),
+ // This will be overwritten once the enclosing array gets parsed.
+ loc: SourceLocation::default(),
+ })
+ }
+
+ // Elision : Elision `,`
+ pub fn elision_append(
+ &self,
+ mut array: arena::Box<'alloc, ArrayExpression<'alloc>>,
+ token: arena::Box<'alloc, Token>,
+ ) -> arena::Box<'alloc, ArrayExpression<'alloc>> {
+ let loc = token.loc;
+ self.push(&mut array.elements, ArrayExpressionElement::Elision { loc });
+ array
+ }
+
+ // SpreadElement : `...` AssignmentExpression
+ pub fn spread_element(
+ &self,
+ expr: arena::Box<'alloc, Expression<'alloc>>,
+ ) -> arena::Box<'alloc, Expression<'alloc>> {
+ expr
+ }
+
+ // ObjectLiteral : `{` `}`
+ pub fn object_literal_empty(
+ &self,
+ open_token: arena::Box<'alloc, Token>,
+ close_token: arena::Box<'alloc, Token>,
+ ) -> arena::Box<'alloc, Expression<'alloc>> {
+ self.alloc_with(|| {
+ Expression::ObjectExpression(ObjectExpression {
+ properties: self.new_vec(),
+ loc: SourceLocation::from_parts(open_token.loc, close_token.loc),
+ })
+ })
+ }
+
+ // ObjectLiteral : `{` PropertyDefinitionList `}`
+ // ObjectLiteral : `{` PropertyDefinitionList `,` `}`
+ pub fn object_literal(
+ &self,
+ open_token: arena::Box<'alloc, Token>,
+ mut object: arena::Box<'alloc, ObjectExpression<'alloc>>,
+ close_token: arena::Box<'alloc, Token>,
+ ) -> arena::Box<'alloc, Expression<'alloc>> {
+ object.loc.set_range(open_token.loc, close_token.loc);
+ self.alloc_with(|| Expression::ObjectExpression(object.unbox()))
+ }
+
+ // PropertyDefinitionList : PropertyDefinition
+ pub fn property_definition_list_single(
+ &self,
+ property: arena::Box<'alloc, ObjectProperty<'alloc>>,
+ ) -> arena::Box<'alloc, ObjectExpression<'alloc>> {
+ self.alloc_with(|| ObjectExpression {
+ properties: self.new_vec_single(property),
+ // This will be overwritten once the enclosing object gets parsed.
+ loc: SourceLocation::default(),
+ })
+ }
+
+ // PropertyDefinitionList : PropertyDefinitionList `,` PropertyDefinition
+ pub fn property_definition_list_append(
+ &self,
+ mut object: arena::Box<'alloc, ObjectExpression<'alloc>>,
+ property: arena::Box<'alloc, ObjectProperty<'alloc>>,
+ ) -> arena::Box<'alloc, ObjectExpression<'alloc>> {
+ self.push(&mut object.properties, property);
+ object
+ }
+
+ // PropertyDefinition : IdentifierReference
+ pub fn shorthand_property(
+ &self,
+ name: arena::Box<'alloc, Identifier>,
+ ) -> arena::Box<'alloc, ObjectProperty<'alloc>> {
+ let loc = name.loc;
+ self.alloc_with(|| {
+ ObjectProperty::ShorthandProperty(ShorthandProperty {
+ name: IdentifierExpression {
+ name: name.unbox(),
+ loc,
+ },
+ loc,
+ })
+ })
+ }
+
+ // PropertyDefinition : PropertyName `:` AssignmentExpression
+ pub fn property_definition(
+ &self,
+ name: arena::Box<'alloc, PropertyName<'alloc>>,
+ expression: arena::Box<'alloc, Expression<'alloc>>,
+ ) -> arena::Box<'alloc, ObjectProperty<'alloc>> {
+ let name_loc = name.get_loc();
+ let expression_loc = expression.get_loc();
+ self.alloc_with(|| {
+ ObjectProperty::NamedObjectProperty(NamedObjectProperty::DataProperty(DataProperty {
+ property_name: name.unbox(),
+ expression,
+ loc: SourceLocation::from_parts(name_loc, expression_loc),
+ }))
+ })
+ }
+
+ // PropertyDefinition : MethodDefinition
+ pub fn property_definition_method(
+ &self,
+ method: arena::Box<'alloc, MethodDefinition<'alloc>>,
+ ) -> arena::Box<'alloc, ObjectProperty<'alloc>> {
+ self.alloc_with(|| {
+ ObjectProperty::NamedObjectProperty(NamedObjectProperty::MethodDefinition(
+ method.unbox(),
+ ))
+ })
+ }
+
+ // PropertyDefinition : `...` AssignmentExpression
+ pub fn property_definition_spread(
+ &self,
+ spread: arena::Box<'alloc, Expression<'alloc>>,
+ ) -> arena::Box<'alloc, ObjectProperty<'alloc>> {
+ self.alloc_with(|| ObjectProperty::SpreadProperty(spread))
+ }
+
+ // LiteralPropertyName : IdentifierName
+ pub fn property_name_identifier(
+ &self,
+ token: arena::Box<'alloc, Token>,
+ ) -> Result<'alloc, arena::Box<'alloc, PropertyName<'alloc>>> {
+ let value = token.value.as_atom();
+ if value == CommonSourceAtomSetIndices::__proto__() {
+ return Err(ParseError::NotImplemented("__proto__ as property name").into());
+ }
+
+ let loc = token.loc;
+ Ok(self.alloc_with(|| PropertyName::StaticPropertyName(StaticPropertyName { value, loc })))
+ }
+
+ // LiteralPropertyName : StringLiteral
+ pub fn property_name_string(
+ &self,
+ token: arena::Box<'alloc, Token>,
+ ) -> Result<'alloc, arena::Box<'alloc, PropertyName<'alloc>>> {
+ let value = token.value.as_atom();
+ if value == CommonSourceAtomSetIndices::__proto__() {
+ return Err(ParseError::NotImplemented("__proto__ as property name").into());
+ }
+
+ let loc = token.loc;
+ Ok(self.alloc_with(|| PropertyName::StaticPropertyName(StaticPropertyName { value, loc })))
+ }
+
+ // LiteralPropertyName : NumericLiteral
+ pub fn property_name_numeric(
+ &self,
+ token: arena::Box<'alloc, Token>,
+ ) -> Result<'alloc, arena::Box<'alloc, PropertyName<'alloc>>> {
+ let loc = token.loc;
+ let value = Self::numeric_literal_value(token);
+ Ok(self
+ .alloc_with(|| PropertyName::StaticNumericPropertyName(NumericLiteral { value, loc })))
+ }
+
+ // LiteralPropertyName : NumericLiteral
+ //
+ // where NumericLiteral is either:
+ // * DecimalBigIntegerLiteral
+ // * NonDecimalIntegerLiteralBigIntLiteralSuffix
+ pub fn property_name_bigint(
+ &self,
+ _token: arena::Box<'alloc, Token>,
+ ) -> Result<'alloc, arena::Box<'alloc, PropertyName<'alloc>>> {
+ Err(ParseError::NotImplemented("BigInt").into())
+ }
+
+ // ComputedPropertyName : `[` AssignmentExpression `]`
+ pub fn computed_property_name(
+ &self,
+ open_token: arena::Box<'alloc, Token>,
+ expression: arena::Box<'alloc, Expression<'alloc>>,
+ close_token: arena::Box<'alloc, Token>,
+ ) -> arena::Box<'alloc, PropertyName<'alloc>> {
+ self.alloc_with(|| {
+ PropertyName::ComputedPropertyName(ComputedPropertyName {
+ expression,
+ loc: SourceLocation::from_parts(open_token.loc, close_token.loc),
+ })
+ })
+ }
+
+ // CoverInitializedName : IdentifierReference Initializer
+ pub fn cover_initialized_name(
+ &self,
+ _name: arena::Box<'alloc, Identifier>,
+ _initializer: arena::Box<'alloc, Expression<'alloc>>,
+ ) -> Result<'alloc, arena::Box<'alloc, ObjectProperty<'alloc>>> {
+ // Awkward. This needs to be stored somehow until we reach an enclosing
+ // context where it can be reinterpreted as a default value in an
+ // object destructuring assignment pattern.
+ Err(ParseError::NotImplemented("default initializers in object patterns").into())
+ }
+
+ // TemplateLiteral : NoSubstitutionTemplate
+ pub fn template_literal(
+ &self,
+ token: arena::Box<'alloc, Token>,
+ ) -> arena::Box<'alloc, TemplateExpression<'alloc>> {
+ let loc = token.loc;
+ self.alloc_with(|| TemplateExpression {
+ tag: None,
+ elements: self.new_vec_single(TemplateExpressionElement::TemplateElement(
+ TemplateElement {
+ raw_value: token.value.as_atom(),
+ loc,
+ },
+ )),
+ loc,
+ })
+ }
+
+ // SubstitutionTemplate : TemplateHead Expression TemplateSpans
+ pub fn substitution_template(
+ &self,
+ _head: arena::Box<'alloc, Token>,
+ _expression: arena::Box<'alloc, Expression<'alloc>>,
+ _spans: arena::Box<'alloc, Void>,
+ ) -> Result<'alloc, arena::Box<'alloc, TemplateExpression<'alloc>>> {
+ Err(ParseError::NotImplemented("template strings").into())
+ }
+
+ // TemplateSpans : TemplateTail
+ // TemplateSpans : TemplateMiddleList TemplateTail
+ pub fn template_spans(
+ &self,
+ _middle_list: Option<arena::Box<'alloc, Void>>,
+ _tail: arena::Box<'alloc, Token>,
+ ) -> Result<'alloc, arena::Box<'alloc, Void>> {
+ Err(ParseError::NotImplemented("template strings").into())
+ }
+
+ // TemplateMiddleList : TemplateMiddle Expression
+ pub fn template_middle_list_single(
+ &self,
+ _middle: arena::Box<'alloc, Token>,
+ _expression: arena::Box<'alloc, Expression<'alloc>>,
+ ) -> Result<'alloc, arena::Box<'alloc, Void>> {
+ Err(ParseError::NotImplemented("template strings").into())
+ }
+
+ // TemplateMiddleList : TemplateMiddleList TemplateMiddle Expression
+ pub fn template_middle_list_append(
+ &self,
+ _middle_list: arena::Box<'alloc, Void>,
+ _middle: arena::Box<'alloc, Token>,
+ _expression: arena::Box<'alloc, Expression<'alloc>>,
+ ) -> Result<'alloc, arena::Box<'alloc, Void>> {
+ Err(ParseError::NotImplemented("template strings").into())
+ }
+
+ // MemberExpression : MemberExpression `[` Expression `]`
+ // CallExpression : CallExpression `[` Expression `]`
+ pub fn computed_member_expr(
+ &self,
+ object: arena::Box<'alloc, Expression<'alloc>>,
+ expression: arena::Box<'alloc, Expression<'alloc>>,
+ close_token: arena::Box<'alloc, Token>,
+ ) -> arena::Box<'alloc, Expression<'alloc>> {
+ let object_loc = object.get_loc();
+ self.alloc_with(|| {
+ Expression::MemberExpression(MemberExpression::ComputedMemberExpression(
+ ComputedMemberExpression {
+ object: ExpressionOrSuper::Expression(object),
+ expression,
+ loc: SourceLocation::from_parts(object_loc, close_token.loc),
+ },
+ ))
+ })
+ }
+
+ // OptionalExpression : MemberExpression OptionalChain
+ // OptionalExpression : CallExpression OptionalChain
+ // OptionalExpression : OptionalExpression OptionalChain
+ pub fn optional_expr(
+ &self,
+ object: arena::Box<'alloc, Expression<'alloc>>,
+ tail: arena::Box<'alloc, Expression<'alloc>>,
+ ) -> arena::Box<'alloc, Expression<'alloc>> {
+ let object_loc = object.get_loc();
+ let expression_loc = tail.get_loc();
+ self.alloc_with(|| Expression::OptionalExpression {
+ object: ExpressionOrSuper::Expression(object),
+ tail,
+ loc: SourceLocation::from_parts(object_loc, expression_loc),
+ })
+ }
+
+ // OptionalChain : `?.` `[` Expression `]`
+ pub fn optional_computed_member_expr_tail(
+ &self,
+ start_token: arena::Box<'alloc, Token>,
+ expression: arena::Box<'alloc, Expression<'alloc>>,
+ close_token: arena::Box<'alloc, Token>,
+ ) -> arena::Box<'alloc, Expression<'alloc>> {
+ self.alloc_with(|| {
+ Expression::OptionalChain(OptionalChain::ComputedMemberExpressionTail {
+ expression,
+ loc: SourceLocation::from_parts(start_token.loc, close_token.loc),
+ })
+ })
+ }
+
+ // OptionalChain : `?.` Expression
+ pub fn optional_static_member_expr_tail(
+ &self,
+ start_token: arena::Box<'alloc, Token>,
+ identifier_token: arena::Box<'alloc, Token>,
+ ) -> arena::Box<'alloc, Expression<'alloc>> {
+ let identifier_token_loc = identifier_token.loc;
+ self.alloc_with(|| {
+ Expression::OptionalChain(OptionalChain::StaticMemberExpressionTail {
+ property: self.identifier_name(identifier_token),
+ loc: SourceLocation::from_parts(start_token.loc, identifier_token_loc),
+ })
+ })
+ }
+
+ // OptionalChain : `?.` PrivateIdentifier
+ pub fn optional_private_field_member_expr_tail(
+ &self,
+ start_token: arena::Box<'alloc, Token>,
+ private_identifier: arena::Box<'alloc, Token>,
+ ) -> Result<'alloc, arena::Box<'alloc, Expression<'alloc>>> {
+ let private_identifier_loc = private_identifier.loc;
+ let field = self.private_identifier(private_identifier)?;
+ Ok(self.alloc_with(|| {
+ Expression::OptionalChain(OptionalChain::PrivateFieldExpressionTail {
+ field,
+ loc: SourceLocation::from_parts(start_token.loc, private_identifier_loc),
+ })
+ }))
+ }
+
+ // OptionalChain : `?.` Arguments
+ pub fn optional_call_expr_tail(
+ &self,
+ start_token: arena::Box<'alloc, Token>,
+ arguments: arena::Box<'alloc, Arguments<'alloc>>,
+ ) -> arena::Box<'alloc, Expression<'alloc>> {
+ let arguments_loc = arguments.loc;
+ self.alloc_with(|| {
+ Expression::OptionalChain(OptionalChain::CallExpressionTail {
+ arguments: arguments.unbox(),
+ loc: SourceLocation::from_parts(start_token.loc, arguments_loc),
+ })
+ })
+ }
+
+ // OptionalChain : `?.` TemplateLiteral
+ pub fn error_optional_chain_with_template(
+ &self,
+ ) -> Result<'alloc, arena::Box<'alloc, Expression<'alloc>>> {
+ Err(ParseError::IllegalCharacter('`').into())
+ }
+
+ // OptionalChain : OptionalChain `[` Expression `]`
+ pub fn optional_computed_member_expr(
+ &self,
+ object: arena::Box<'alloc, Expression<'alloc>>,
+ expression: arena::Box<'alloc, Expression<'alloc>>,
+ close_token: arena::Box<'alloc, Token>,
+ ) -> arena::Box<'alloc, Expression<'alloc>> {
+ let object_loc = object.get_loc();
+ self.alloc_with(|| {
+ Expression::OptionalChain(OptionalChain::ComputedMemberExpression(
+ ComputedMemberExpression {
+ object: ExpressionOrSuper::Expression(object),
+ expression,
+ loc: SourceLocation::from_parts(object_loc, close_token.loc),
+ },
+ ))
+ })
+ }
+
+ // OptionalChain : OptionalChain `.` Expression
+ pub fn optional_static_member_expr(
+ &self,
+ object: arena::Box<'alloc, Expression<'alloc>>,
+ identifier_token: arena::Box<'alloc, Token>,
+ ) -> arena::Box<'alloc, Expression<'alloc>> {
+ let object_loc = object.get_loc();
+ let identifier_token_loc = identifier_token.loc;
+ self.alloc_with(|| {
+ Expression::OptionalChain(OptionalChain::StaticMemberExpression(
+ StaticMemberExpression {
+ object: ExpressionOrSuper::Expression(object),
+ property: self.identifier_name(identifier_token),
+ loc: SourceLocation::from_parts(object_loc, identifier_token_loc),
+ },
+ ))
+ })
+ }
+
+ // OptionalChain : OptionalChain `.` PrivateIdentifier
+ pub fn optional_private_field_member_expr(
+ &self,
+ object: arena::Box<'alloc, Expression<'alloc>>,
+ private_identifier: arena::Box<'alloc, Token>,
+ ) -> Result<'alloc, arena::Box<'alloc, Expression<'alloc>>> {
+ let object_loc = object.get_loc();
+ let private_identifier_loc = private_identifier.loc;
+ let field = self.private_identifier(private_identifier)?;
+ Ok(self.alloc_with(|| {
+ Expression::OptionalChain(OptionalChain::PrivateFieldExpression(
+ PrivateFieldExpression {
+ object: ExpressionOrSuper::Expression(object),
+ field,
+ loc: SourceLocation::from_parts(object_loc, private_identifier_loc),
+ },
+ ))
+ }))
+ }
+
+ // OptionalChain : OptionalChain Arguments
+ pub fn optional_call_expr(
+ &self,
+ callee: arena::Box<'alloc, Expression<'alloc>>,
+ arguments: arena::Box<'alloc, Arguments<'alloc>>,
+ ) -> arena::Box<'alloc, Expression<'alloc>> {
+ let callee_loc = callee.get_loc();
+ let arguments_loc = arguments.loc;
+ self.alloc_with(|| {
+ Expression::OptionalChain(OptionalChain::CallExpression(CallExpression {
+ callee: ExpressionOrSuper::Expression(callee),
+ arguments: arguments.unbox(),
+ loc: SourceLocation::from_parts(callee_loc, arguments_loc),
+ }))
+ })
+ }
+
+ fn identifier(&self, token: arena::Box<'alloc, Token>) -> Identifier {
+ Identifier {
+ value: token.value.as_atom(),
+ loc: token.loc,
+ }
+ }
+
+ fn identifier_name(&self, token: arena::Box<'alloc, Token>) -> IdentifierName {
+ IdentifierName {
+ value: token.value.as_atom(),
+ loc: token.loc,
+ }
+ }
+
+ fn private_identifier(
+ &self,
+ _token: arena::Box<'alloc, Token>,
+ ) -> Result<'alloc, PrivateIdentifier> {
+ Err(ParseError::NotImplemented(
+ "private fields depends on shell switch, that is not supported",
+ )
+ .into())
+ /*
+ PrivateIdentifier {
+ value: token.value.as_atom(),
+ loc: token.loc,
+ }
+ */
+ }
+
+ // MemberExpression : MemberExpression `.` IdentifierName
+ // CallExpression : CallExpression `.` IdentifierName
+ pub fn static_member_expr(
+ &self,
+ object: arena::Box<'alloc, Expression<'alloc>>,
+ identifier_token: arena::Box<'alloc, Token>,
+ ) -> arena::Box<'alloc, Expression<'alloc>> {
+ let object_loc = object.get_loc();
+ let identifier_token_loc = identifier_token.loc;
+ self.alloc_with(|| {
+ Expression::MemberExpression(MemberExpression::StaticMemberExpression(
+ StaticMemberExpression {
+ object: ExpressionOrSuper::Expression(object),
+ property: self.identifier_name(identifier_token),
+ loc: SourceLocation::from_parts(object_loc, identifier_token_loc),
+ },
+ ))
+ })
+ }
+
+ // MemberExpression : MemberExpression TemplateLiteral
+ // CallExpression : CallExpression TemplateLiteral
+ pub fn tagged_template_expr(
+ &self,
+ tag: arena::Box<'alloc, Expression<'alloc>>,
+ mut template_literal: arena::Box<'alloc, TemplateExpression<'alloc>>,
+ ) -> arena::Box<'alloc, Expression<'alloc>> {
+ template_literal.tag = Some(tag);
+ self.alloc_with(|| Expression::TemplateExpression(template_literal.unbox()))
+ }
+
+ // MemberExpression : `new` MemberExpression Arguments
+ pub fn new_expr_with_arguments(
+ &self,
+ new_token: arena::Box<'alloc, Token>,
+ callee: arena::Box<'alloc, Expression<'alloc>>,
+ arguments: arena::Box<'alloc, Arguments<'alloc>>,
+ ) -> arena::Box<'alloc, Expression<'alloc>> {
+ let arguments_loc = arguments.loc;
+ self.alloc_with(|| Expression::NewExpression {
+ callee,
+ arguments: arguments.unbox(),
+ loc: SourceLocation::from_parts(new_token.loc, arguments_loc),
+ })
+ }
+
+ // MemberExpression : MemberExpression `.` PrivateIdentifier
+ pub fn private_field_expr(
+ &self,
+ object: arena::Box<'alloc, Expression<'alloc>>,
+ private_identifier: arena::Box<'alloc, Token>,
+ ) -> Result<'alloc, arena::Box<'alloc, Expression<'alloc>>> {
+ let object_loc = object.get_loc();
+ let field_loc = private_identifier.loc;
+ let field = self.private_identifier(private_identifier)?;
+ Ok(self.alloc_with(|| {
+ Expression::MemberExpression(MemberExpression::PrivateFieldExpression(
+ PrivateFieldExpression {
+ object: ExpressionOrSuper::Expression(object),
+ field,
+ loc: SourceLocation::from_parts(object_loc, field_loc),
+ },
+ ))
+ }))
+ }
+
+ // SuperProperty : `super` `[` Expression `]`
+ pub fn super_property_computed(
+ &self,
+ super_token: arena::Box<'alloc, Token>,
+ expression: arena::Box<'alloc, Expression<'alloc>>,
+ close_token: arena::Box<'alloc, Token>,
+ ) -> Result<'alloc, arena::Box<'alloc, Expression<'alloc>>> {
+ self.check_super()?;
+
+ let super_loc = super_token.loc;
+ Ok(self.alloc_with(|| {
+ Expression::MemberExpression(MemberExpression::ComputedMemberExpression(
+ ComputedMemberExpression {
+ object: ExpressionOrSuper::Super { loc: super_loc },
+ expression: expression,
+ loc: SourceLocation::from_parts(super_loc, close_token.loc),
+ },
+ ))
+ }))
+ }
+
+ // SuperProperty : `super` `.` IdentifierName
+ pub fn super_property_static(
+ &self,
+ super_token: arena::Box<'alloc, Token>,
+ identifier_token: arena::Box<'alloc, Token>,
+ ) -> Result<'alloc, arena::Box<'alloc, Expression<'alloc>>> {
+ self.check_super()?;
+
+ let super_loc = super_token.loc;
+ let identifier_loc = identifier_token.loc;
+ Ok(self.alloc_with(|| {
+ Expression::MemberExpression(MemberExpression::StaticMemberExpression(
+ StaticMemberExpression {
+ object: ExpressionOrSuper::Super { loc: super_loc },
+ property: self.identifier_name(identifier_token),
+ loc: SourceLocation::from_parts(super_loc, identifier_loc),
+ },
+ ))
+ }))
+ }
+
+ // NewTarget : `new` `.` `target`
+ pub fn new_target_expr(
+ &self,
+ new_token: arena::Box<'alloc, Token>,
+ target_token: arena::Box<'alloc, Token>,
+ ) -> arena::Box<'alloc, Expression<'alloc>> {
+ return self.alloc_with(|| Expression::NewTargetExpression {
+ loc: SourceLocation::from_parts(new_token.loc, target_token.loc),
+ });
+ }
+
+ // NewExpression : `new` NewExpression
+ pub fn new_expr_without_arguments(
+ &self,
+ new_token: arena::Box<'alloc, Token>,
+ callee: arena::Box<'alloc, Expression<'alloc>>,
+ ) -> arena::Box<'alloc, Expression<'alloc>> {
+ let callee_loc = callee.get_loc();
+ self.alloc_with(|| Expression::NewExpression {
+ callee,
+ arguments: Arguments {
+ args: self.new_vec(),
+ loc: SourceLocation::new(callee_loc.end, callee_loc.end),
+ },
+ loc: SourceLocation::from_parts(new_token.loc, callee_loc),
+ })
+ }
+
+ // CallExpression : CallExpression Arguments
+ // CoverCallExpressionAndAsyncArrowHead : MemberExpression Arguments
+ // CallMemberExpression : MemberExpression Arguments
+ pub fn call_expr(
+ &self,
+ callee: arena::Box<'alloc, Expression<'alloc>>,
+ arguments: arena::Box<'alloc, Arguments<'alloc>>,
+ ) -> arena::Box<'alloc, Expression<'alloc>> {
+ let callee_loc = callee.get_loc();
+ let arguments_loc = arguments.loc;
+ self.alloc_with(|| {
+ Expression::CallExpression(CallExpression {
+ callee: ExpressionOrSuper::Expression(callee),
+ arguments: arguments.unbox(),
+ loc: SourceLocation::from_parts(callee_loc, arguments_loc),
+ })
+ })
+ }
+
+ // SuperCall : `super` Arguments
+ pub fn super_call(
+ &self,
+ super_token: arena::Box<'alloc, Token>,
+ arguments: arena::Box<'alloc, Arguments<'alloc>>,
+ ) -> Result<'alloc, arena::Box<'alloc, Expression<'alloc>>> {
+ self.check_super()?;
+
+ let super_loc = super_token.loc;
+ let arguments_loc = arguments.loc;
+ Ok(self.alloc_with(|| {
+ Expression::CallExpression(CallExpression {
+ callee: ExpressionOrSuper::Super { loc: super_loc },
+ arguments: arguments.unbox(),
+ loc: SourceLocation::from_parts(super_loc, arguments_loc),
+ })
+ }))
+ }
+
+ // ImportCall : `import` `(` AssignmentExpression `)`
+ pub fn import_call(
+ &self,
+ import_token: arena::Box<'alloc, Token>,
+ argument: arena::Box<'alloc, Expression<'alloc>>,
+ close_token: arena::Box<'alloc, Token>,
+ ) -> arena::Box<'alloc, Expression<'alloc>> {
+ self.alloc_with(|| Expression::ImportCallExpression {
+ argument,
+ loc: SourceLocation::from_parts(import_token.loc, close_token.loc),
+ })
+ }
+
+ // Arguments : `(` `)`
+ pub fn arguments_empty(
+ &self,
+ open_token: arena::Box<'alloc, Token>,
+ close_token: arena::Box<'alloc, Token>,
+ ) -> arena::Box<'alloc, Arguments<'alloc>> {
+ self.alloc_with(|| Arguments {
+ args: self.new_vec(),
+ loc: SourceLocation::from_parts(open_token.loc, close_token.loc),
+ })
+ }
+
+ pub fn arguments_single(
+ &self,
+ expression: arena::Box<'alloc, Expression<'alloc>>,
+ ) -> arena::Box<'alloc, Arguments<'alloc>> {
+ self.alloc_with(|| Arguments {
+ args: self.new_vec_single(Argument::Expression(expression)),
+ // This will be overwritten once the enclosing arguments gets
+ // parsed.
+ loc: SourceLocation::default(),
+ })
+ }
+
+ pub fn arguments_spread_single(
+ &self,
+ expression: arena::Box<'alloc, Expression<'alloc>>,
+ ) -> arena::Box<'alloc, Arguments<'alloc>> {
+ self.alloc_with(|| Arguments {
+ args: self.new_vec_single(Argument::SpreadElement(expression)),
+ // This will be overwritten once the enclosing arguments gets
+ // parsed.
+ loc: SourceLocation::default(),
+ })
+ }
+
+ pub fn arguments(
+ &self,
+ open_token: arena::Box<'alloc, Token>,
+ mut arguments: arena::Box<'alloc, Arguments<'alloc>>,
+ close_token: arena::Box<'alloc, Token>,
+ ) -> arena::Box<'alloc, Arguments<'alloc>> {
+ arguments.loc.set_range(open_token.loc, close_token.loc);
+ arguments
+ }
+
+ // ArgumentList : AssignmentExpression
+ // ArgumentList : ArgumentList `,` AssignmentExpression
+ pub fn arguments_append(
+ &self,
+ mut arguments: arena::Box<'alloc, Arguments<'alloc>>,
+ expression: arena::Box<'alloc, Expression<'alloc>>,
+ ) -> arena::Box<'alloc, Arguments<'alloc>> {
+ self.push(&mut arguments.args, Argument::Expression(expression));
+ arguments
+ }
+
+ // ArgumentList : `...` AssignmentExpression
+ // ArgumentList : ArgumentList `,` `...` AssignmentExpression
+ pub fn arguments_append_spread(
+ &self,
+ mut arguments: arena::Box<'alloc, Arguments<'alloc>>,
+ expression: arena::Box<'alloc, Expression<'alloc>>,
+ ) -> arena::Box<'alloc, Arguments<'alloc>> {
+ self.push(&mut arguments.args, Argument::SpreadElement(expression));
+ arguments
+ }
+
+ // UpdateExpression : LeftHandSideExpression `++`
+ pub fn post_increment_expr(
+ &self,
+ operand: arena::Box<'alloc, Expression<'alloc>>,
+ operator_token: arena::Box<'alloc, Token>,
+ ) -> Result<'alloc, arena::Box<'alloc, Expression<'alloc>>> {
+ let operand = self.expression_to_simple_assignment_target(operand)?;
+ let operand_loc = operand.get_loc();
+ Ok(self.alloc_with(|| Expression::UpdateExpression {
+ is_prefix: false,
+ operator: UpdateOperator::Increment {
+ loc: operator_token.loc,
+ },
+ operand,
+ loc: SourceLocation::from_parts(operand_loc, operator_token.loc),
+ }))
+ }
+
+ // UpdateExpression : LeftHandSideExpression `--`
+ pub fn post_decrement_expr(
+ &self,
+ operand: arena::Box<'alloc, Expression<'alloc>>,
+ operator_token: arena::Box<'alloc, Token>,
+ ) -> Result<'alloc, arena::Box<'alloc, Expression<'alloc>>> {
+ let operand = self.expression_to_simple_assignment_target(operand)?;
+ let operand_loc = operand.get_loc();
+ Ok(self.alloc_with(|| Expression::UpdateExpression {
+ is_prefix: false,
+ operator: UpdateOperator::Decrement {
+ loc: operator_token.loc,
+ },
+ operand,
+ loc: SourceLocation::from_parts(operand_loc, operator_token.loc),
+ }))
+ }
+
+ // UpdateExpression : `++` UnaryExpression
+ pub fn pre_increment_expr(
+ &self,
+ operator_token: arena::Box<'alloc, Token>,
+ operand: arena::Box<'alloc, Expression<'alloc>>,
+ ) -> Result<'alloc, arena::Box<'alloc, Expression<'alloc>>> {
+ let operand = self.expression_to_simple_assignment_target(operand)?;
+ let operand_loc = operand.get_loc();
+ Ok(self.alloc_with(|| Expression::UpdateExpression {
+ is_prefix: true,
+ operator: UpdateOperator::Increment {
+ loc: operator_token.loc,
+ },
+ operand,
+ loc: SourceLocation::from_parts(operator_token.loc, operand_loc),
+ }))
+ }
+
+ // UpdateExpression : `--` UnaryExpression
+ pub fn pre_decrement_expr(
+ &self,
+ operator_token: arena::Box<'alloc, Token>,
+ operand: arena::Box<'alloc, Expression<'alloc>>,
+ ) -> Result<'alloc, arena::Box<'alloc, Expression<'alloc>>> {
+ let operand = self.expression_to_simple_assignment_target(operand)?;
+ let operand_loc = operand.get_loc();
+ Ok(self.alloc_with(|| Expression::UpdateExpression {
+ is_prefix: true,
+ operator: UpdateOperator::Decrement {
+ loc: operator_token.loc,
+ },
+ operand,
+ loc: SourceLocation::from_parts(operator_token.loc, operand_loc),
+ }))
+ }
+
+ // UnaryExpression : `delete` UnaryExpression
+ pub fn delete_expr(
+ &self,
+ operator_token: arena::Box<'alloc, Token>,
+ operand: arena::Box<'alloc, Expression<'alloc>>,
+ ) -> arena::Box<'alloc, Expression<'alloc>> {
+ let operand_loc = operand.get_loc();
+ self.alloc_with(|| Expression::UnaryExpression {
+ operator: UnaryOperator::Delete {
+ loc: operator_token.loc,
+ },
+ operand,
+ loc: SourceLocation::from_parts(operator_token.loc, operand_loc),
+ })
+ }
+
+ // UnaryExpression : `void` UnaryExpression
+ pub fn void_expr(
+ &self,
+ operator_token: arena::Box<'alloc, Token>,
+ operand: arena::Box<'alloc, Expression<'alloc>>,
+ ) -> arena::Box<'alloc, Expression<'alloc>> {
+ let operand_loc = operand.get_loc();
+ self.alloc_with(|| Expression::UnaryExpression {
+ operator: UnaryOperator::Void {
+ loc: operator_token.loc,
+ },
+ operand,
+ loc: SourceLocation::from_parts(operator_token.loc, operand_loc),
+ })
+ }
+
+ // UnaryExpression : `typeof` UnaryExpression
+ pub fn typeof_expr(
+ &self,
+ operator_token: arena::Box<'alloc, Token>,
+ operand: arena::Box<'alloc, Expression<'alloc>>,
+ ) -> arena::Box<'alloc, Expression<'alloc>> {
+ let operand_loc = operand.get_loc();
+ self.alloc_with(|| Expression::UnaryExpression {
+ operator: UnaryOperator::Typeof {
+ loc: operator_token.loc,
+ },
+ operand,
+ loc: SourceLocation::from_parts(operator_token.loc, operand_loc),
+ })
+ }
+
+ // UnaryExpression : `+` UnaryExpression
+ pub fn unary_plus_expr(
+ &self,
+ operator_token: arena::Box<'alloc, Token>,
+ operand: arena::Box<'alloc, Expression<'alloc>>,
+ ) -> arena::Box<'alloc, Expression<'alloc>> {
+ let operand_loc = operand.get_loc();
+ self.alloc_with(|| Expression::UnaryExpression {
+ operator: UnaryOperator::Plus {
+ loc: operator_token.loc,
+ },
+ operand,
+ loc: SourceLocation::from_parts(operator_token.loc, operand_loc),
+ })
+ }
+
+ // UnaryExpression : `-` UnaryExpression
+ pub fn unary_minus_expr(
+ &self,
+ operator_token: arena::Box<'alloc, Token>,
+ operand: arena::Box<'alloc, Expression<'alloc>>,
+ ) -> arena::Box<'alloc, Expression<'alloc>> {
+ let operand_loc = operand.get_loc();
+ self.alloc_with(|| Expression::UnaryExpression {
+ operator: UnaryOperator::Minus {
+ loc: operator_token.loc,
+ },
+ operand,
+ loc: SourceLocation::from_parts(operator_token.loc, operand_loc),
+ })
+ }
+
+ // UnaryExpression : `~` UnaryExpression
+ pub fn bitwise_not_expr(
+ &self,
+ operator_token: arena::Box<'alloc, Token>,
+ operand: arena::Box<'alloc, Expression<'alloc>>,
+ ) -> arena::Box<'alloc, Expression<'alloc>> {
+ let operand_loc = operand.get_loc();
+ self.alloc_with(|| Expression::UnaryExpression {
+ operator: UnaryOperator::BitwiseNot {
+ loc: operator_token.loc,
+ },
+ operand,
+ loc: SourceLocation::from_parts(operator_token.loc, operand_loc),
+ })
+ }
+
+ // UnaryExpression : `!` UnaryExpression
+ pub fn logical_not_expr(
+ &self,
+ operator_token: arena::Box<'alloc, Token>,
+ operand: arena::Box<'alloc, Expression<'alloc>>,
+ ) -> arena::Box<'alloc, Expression<'alloc>> {
+ let operand_loc = operand.get_loc();
+ self.alloc_with(|| Expression::UnaryExpression {
+ operator: UnaryOperator::LogicalNot {
+ loc: operator_token.loc,
+ },
+ operand,
+ loc: SourceLocation::from_parts(operator_token.loc, operand_loc),
+ })
+ }
+
+ pub fn equals_op(&self, token: arena::Box<'alloc, Token>) -> BinaryOperator {
+ BinaryOperator::Equals { loc: token.loc }
+ }
+ pub fn not_equals_op(&self, token: arena::Box<'alloc, Token>) -> BinaryOperator {
+ BinaryOperator::NotEquals { loc: token.loc }
+ }
+ pub fn strict_equals_op(&self, token: arena::Box<'alloc, Token>) -> BinaryOperator {
+ BinaryOperator::StrictEquals { loc: token.loc }
+ }
+ pub fn strict_not_equals_op(&self, token: arena::Box<'alloc, Token>) -> BinaryOperator {
+ BinaryOperator::StrictNotEquals { loc: token.loc }
+ }
+ pub fn less_than_op(&self, token: arena::Box<'alloc, Token>) -> BinaryOperator {
+ BinaryOperator::LessThan { loc: token.loc }
+ }
+ pub fn less_than_or_equal_op(&self, token: arena::Box<'alloc, Token>) -> BinaryOperator {
+ BinaryOperator::LessThanOrEqual { loc: token.loc }
+ }
+ pub fn greater_than_op(&self, token: arena::Box<'alloc, Token>) -> BinaryOperator {
+ BinaryOperator::GreaterThan { loc: token.loc }
+ }
+ pub fn greater_than_or_equal_op(&self, token: arena::Box<'alloc, Token>) -> BinaryOperator {
+ BinaryOperator::GreaterThanOrEqual { loc: token.loc }
+ }
+ pub fn in_op(&self, token: arena::Box<'alloc, Token>) -> BinaryOperator {
+ BinaryOperator::In { loc: token.loc }
+ }
+ pub fn instanceof_op(&self, token: arena::Box<'alloc, Token>) -> BinaryOperator {
+ BinaryOperator::Instanceof { loc: token.loc }
+ }
+ pub fn left_shift_op(&self, token: arena::Box<'alloc, Token>) -> BinaryOperator {
+ BinaryOperator::LeftShift { loc: token.loc }
+ }
+ pub fn right_shift_op(&self, token: arena::Box<'alloc, Token>) -> BinaryOperator {
+ BinaryOperator::RightShift { loc: token.loc }
+ }
+ pub fn right_shift_ext_op(&self, token: arena::Box<'alloc, Token>) -> BinaryOperator {
+ BinaryOperator::RightShiftExt { loc: token.loc }
+ }
+ pub fn add_op(&self, token: arena::Box<'alloc, Token>) -> BinaryOperator {
+ BinaryOperator::Add { loc: token.loc }
+ }
+ pub fn sub_op(&self, token: arena::Box<'alloc, Token>) -> BinaryOperator {
+ BinaryOperator::Sub { loc: token.loc }
+ }
+ pub fn mul_op(&self, token: arena::Box<'alloc, Token>) -> BinaryOperator {
+ BinaryOperator::Mul { loc: token.loc }
+ }
+ pub fn div_op(&self, token: arena::Box<'alloc, Token>) -> BinaryOperator {
+ BinaryOperator::Div { loc: token.loc }
+ }
+ pub fn mod_op(&self, token: arena::Box<'alloc, Token>) -> BinaryOperator {
+ BinaryOperator::Mod { loc: token.loc }
+ }
+ pub fn pow_op(&self, token: arena::Box<'alloc, Token>) -> BinaryOperator {
+ BinaryOperator::Pow { loc: token.loc }
+ }
+ pub fn comma_op(&self, token: arena::Box<'alloc, Token>) -> BinaryOperator {
+ BinaryOperator::Comma { loc: token.loc }
+ }
+ pub fn coalesce_op(&self, token: arena::Box<'alloc, Token>) -> BinaryOperator {
+ BinaryOperator::Coalesce { loc: token.loc }
+ }
+ pub fn logical_or_op(&self, token: arena::Box<'alloc, Token>) -> BinaryOperator {
+ BinaryOperator::LogicalOr { loc: token.loc }
+ }
+ pub fn logical_and_op(&self, token: arena::Box<'alloc, Token>) -> BinaryOperator {
+ BinaryOperator::LogicalAnd { loc: token.loc }
+ }
+ pub fn bitwise_or_op(&self, token: arena::Box<'alloc, Token>) -> BinaryOperator {
+ BinaryOperator::BitwiseOr { loc: token.loc }
+ }
+ pub fn bitwise_xor_op(&self, token: arena::Box<'alloc, Token>) -> BinaryOperator {
+ BinaryOperator::BitwiseXor { loc: token.loc }
+ }
+ pub fn bitwise_and_op(&self, token: arena::Box<'alloc, Token>) -> BinaryOperator {
+ BinaryOperator::BitwiseAnd { loc: token.loc }
+ }
+
+ // Due to limitations of the current parser generator,
+ // MultiplicativeOperators and CompoundAssignmentOperators currently get
+ // boxed.
+ pub fn box_op(&self, op: BinaryOperator) -> arena::Box<'alloc, BinaryOperator> {
+ self.alloc_with(|| op)
+ }
+
+ // MultiplicativeExpression : MultiplicativeExpression MultiplicativeOperator ExponentiationExpression
+ pub fn multiplicative_expr(
+ &self,
+ left: arena::Box<'alloc, Expression<'alloc>>,
+ operator: arena::Box<'alloc, BinaryOperator>,
+ right: arena::Box<'alloc, Expression<'alloc>>,
+ ) -> arena::Box<'alloc, Expression<'alloc>> {
+ self.binary_expr(operator.unbox(), left, right)
+ }
+
+ // ExponentiationExpression : UpdateExpression `**` ExponentiationExpression
+ // AdditiveExpression : AdditiveExpression `+` MultiplicativeExpression
+ // AdditiveExpression : AdditiveExpression `-` MultiplicativeExpression
+ // ShiftExpression : ShiftExpression `<<` AdditiveExpression
+ // ShiftExpression : ShiftExpression `>>` AdditiveExpression
+ // ShiftExpression : ShiftExpression `>>>` AdditiveExpression
+ // RelationalExpression : RelationalExpression `<` ShiftExpression
+ // RelationalExpression : RelationalExpression `>` ShiftExpression
+ // RelationalExpression : RelationalExpression `<=` ShiftExpression
+ // RelationalExpression : RelationalExpression `>=` ShiftExpression
+ // RelationalExpression : RelationalExpression `instanceof` ShiftExpression
+ // RelationalExpression : [+In] RelationalExpression `in` ShiftExpression
+ // EqualityExpression : EqualityExpression `==` RelationalExpression
+ // EqualityExpression : EqualityExpression `!=` RelationalExpression
+ // EqualityExpression : EqualityExpression `===` RelationalExpression
+ // EqualityExpression : EqualityExpression `!==` RelationalExpression
+ // BitwiseANDExpression : BitwiseANDExpression `&` EqualityExpression
+ // BitwiseXORExpression : BitwiseXORExpression `^` BitwiseANDExpression
+ // BitwiseORExpression : BitwiseORExpression `|` BitwiseXORExpression
+ // LogicalANDExpression : LogicalANDExpression `&&` BitwiseORExpression
+ // LogicalORExpression : LogicalORExpression `||` LogicalANDExpression
+ pub fn binary_expr(
+ &self,
+ operator: BinaryOperator,
+ left: arena::Box<'alloc, Expression<'alloc>>,
+ right: arena::Box<'alloc, Expression<'alloc>>,
+ ) -> arena::Box<'alloc, Expression<'alloc>> {
+ let left_loc = left.get_loc();
+ let right_loc = right.get_loc();
+ self.alloc_with(|| Expression::BinaryExpression {
+ operator,
+ left,
+ right,
+ loc: SourceLocation::from_parts(left_loc, right_loc),
+ })
+ }
+
+ // ConditionalExpression : LogicalORExpression `?` AssignmentExpression `:` AssignmentExpression
+ pub fn conditional_expr(
+ &self,
+ test: arena::Box<'alloc, Expression<'alloc>>,
+ consequent: arena::Box<'alloc, Expression<'alloc>>,
+ alternate: arena::Box<'alloc, Expression<'alloc>>,
+ ) -> arena::Box<'alloc, Expression<'alloc>> {
+ let test_loc = test.get_loc();
+ let alternate_loc = alternate.get_loc();
+ self.alloc_with(|| Expression::ConditionalExpression {
+ test,
+ consequent,
+ alternate,
+ loc: SourceLocation::from_parts(test_loc, alternate_loc),
+ })
+ }
+
+ /// Refine an *ArrayLiteral* into an *ArrayAssignmentPattern*.
+ fn array_expression_to_array_assignment_target(
+ &self,
+ mut elements: arena::Vec<'alloc, ArrayExpressionElement<'alloc>>,
+ loc: SourceLocation,
+ ) -> Result<'alloc, ArrayAssignmentTarget<'alloc>> {
+ let spread = self.pop_trailing_spread_element(&mut elements);
+ let elements =
+ self.collect_vec_from_results(elements.into_iter().map(|element| match element {
+ ArrayExpressionElement::SpreadElement(_) => {
+ Err(ParseError::NotImplemented("rest destructuring in array pattern").into())
+ }
+ ArrayExpressionElement::Expression(expression) => Ok(Some(
+ self.expression_to_assignment_target_maybe_default(expression)?,
+ )),
+ ArrayExpressionElement::Elision { .. } => Ok(None),
+ }))?;
+ let rest: Option<Result<'alloc, arena::Box<'alloc, AssignmentTarget<'alloc>>>> =
+ spread.map(|expr| Ok(self.alloc(self.expression_to_assignment_target(expr)?)));
+ let rest = rest.transpose()?;
+ Ok(ArrayAssignmentTarget {
+ elements,
+ rest,
+ loc,
+ })
+ }
+
+ fn object_property_to_assignment_target_property(
+ &self,
+ property: arena::Box<'alloc, ObjectProperty<'alloc>>,
+ ) -> Result<'alloc, AssignmentTargetProperty<'alloc>> {
+ Ok(match property.unbox() {
+ ObjectProperty::NamedObjectProperty(NamedObjectProperty::MethodDefinition(_)) => {
+ return Err(ParseError::ObjectPatternWithMethod.into())
+ }
+
+ ObjectProperty::NamedObjectProperty(NamedObjectProperty::DataProperty(
+ DataProperty {
+ property_name,
+ expression,
+ loc,
+ },
+ )) => AssignmentTargetProperty::AssignmentTargetPropertyProperty(
+ AssignmentTargetPropertyProperty {
+ name: property_name,
+ binding: self.expression_to_assignment_target_maybe_default(expression)?,
+ loc,
+ },
+ ),
+
+ ObjectProperty::ShorthandProperty(ShorthandProperty {
+ name: IdentifierExpression { name, loc },
+ ..
+ }) => {
+ // TODO - support CoverInitializedName
+ AssignmentTargetProperty::AssignmentTargetPropertyIdentifier(
+ AssignmentTargetPropertyIdentifier {
+ binding: AssignmentTargetIdentifier { name, loc },
+ init: None,
+ loc,
+ },
+ )
+ }
+
+ ObjectProperty::SpreadProperty(_expression) => {
+ return Err(ParseError::ObjectPatternWithNonFinalRest.into())
+ }
+ })
+ }
+
+ // Refine an *ObjectLiteral* into an *ObjectAssignmentPattern*.
+ fn object_expression_to_object_assignment_target(
+ &self,
+ mut properties: arena::Vec<'alloc, arena::Box<'alloc, ObjectProperty<'alloc>>>,
+ loc: SourceLocation,
+ ) -> Result<'alloc, ObjectAssignmentTarget<'alloc>> {
+ let spread = self.pop_trailing_spread_property(&mut properties);
+ let properties = self.collect_vec_from_results(
+ properties
+ .into_iter()
+ .map(|p| self.object_property_to_assignment_target_property(p)),
+ )?;
+ let rest: Option<Result<'alloc, arena::Box<'alloc, AssignmentTarget<'alloc>>>> =
+ spread.map(|expr| Ok(self.alloc(self.expression_to_assignment_target(expr)?)));
+ let rest = rest.transpose()?;
+ Ok(ObjectAssignmentTarget {
+ properties,
+ rest,
+ loc,
+ })
+ }
+
+ fn expression_to_assignment_target_maybe_default(
+ &self,
+ expression: arena::Box<'alloc, Expression<'alloc>>,
+ ) -> Result<'alloc, AssignmentTargetMaybeDefault<'alloc>> {
+ Ok(match expression.unbox() {
+ Expression::AssignmentExpression {
+ binding,
+ expression,
+ loc,
+ } => AssignmentTargetMaybeDefault::AssignmentTargetWithDefault(
+ AssignmentTargetWithDefault {
+ binding,
+ init: expression,
+ loc,
+ },
+ ),
+
+ other => AssignmentTargetMaybeDefault::AssignmentTarget(
+ self.expression_to_assignment_target(self.alloc_with(|| other))?,
+ ),
+ })
+ }
+
+ fn expression_to_assignment_target(
+ &self,
+ expression: arena::Box<'alloc, Expression<'alloc>>,
+ ) -> Result<'alloc, AssignmentTarget<'alloc>> {
+ Ok(match expression.unbox() {
+ Expression::ArrayExpression(ArrayExpression { elements, loc }) => {
+ AssignmentTarget::AssignmentTargetPattern(
+ AssignmentTargetPattern::ArrayAssignmentTarget(
+ self.array_expression_to_array_assignment_target(elements, loc)?,
+ ),
+ )
+ }
+
+ Expression::ObjectExpression(ObjectExpression { properties, loc }) => {
+ AssignmentTarget::AssignmentTargetPattern(
+ AssignmentTargetPattern::ObjectAssignmentTarget(
+ self.object_expression_to_object_assignment_target(properties, loc)?,
+ ),
+ )
+ }
+
+ other => AssignmentTarget::SimpleAssignmentTarget(
+ self.expression_to_simple_assignment_target(self.alloc_with(|| other))?,
+ ),
+ })
+ }
+
+ fn expression_to_simple_assignment_target(
+ &self,
+ expression: arena::Box<'alloc, Expression<'alloc>>,
+ ) -> Result<'alloc, SimpleAssignmentTarget<'alloc>> {
+ Ok(match expression.unbox() {
+ // Static Semantics: AssignmentTargetType
+ // https://tc39.es/ecma262/#sec-identifiers-static-semantics-assignmenttargettype
+ Expression::IdentifierExpression(IdentifierExpression { name, loc }) => {
+ // IdentifierReference : Identifier
+ //
+ // 1. If this IdentifierReference is contained in strict mode
+ // code and StringValue of Identifier is "eval" or
+ // "arguments", return invalid.
+ if name.value == CommonSourceAtomSetIndices::arguments()
+ || name.value == CommonSourceAtomSetIndices::eval()
+ {
+ if self.is_strict()? {
+ return Err(ParseError::InvalidAssignmentTarget.into());
+ }
+ }
+
+ // 2. Return simple.
+ //
+ // IdentifierReference : yield
+ //
+ // 1. Return simple.
+ //
+ // IdentifierReference : await
+ //
+ // 1. Return simple.
+ SimpleAssignmentTarget::AssignmentTargetIdentifier(AssignmentTargetIdentifier {
+ name,
+ loc,
+ })
+ }
+
+ // Static Semantics: AssignmentTargetType
+ // https://tc39.es/ecma262/#sec-static-semantics-static-semantics-assignmenttargettype
+ //
+ // MemberExpression :
+ // MemberExpression [ Expression ]
+ // MemberExpression . IdentifierName
+ // SuperProperty
+ //
+ // 1. Return simple.
+ Expression::MemberExpression(MemberExpression::StaticMemberExpression(
+ StaticMemberExpression {
+ object,
+ property,
+ loc,
+ },
+ )) => SimpleAssignmentTarget::MemberAssignmentTarget(
+ MemberAssignmentTarget::StaticMemberAssignmentTarget(
+ StaticMemberAssignmentTarget {
+ object,
+ property,
+ loc,
+ },
+ ),
+ ),
+ Expression::MemberExpression(MemberExpression::ComputedMemberExpression(
+ ComputedMemberExpression {
+ object,
+ expression,
+ loc,
+ },
+ )) => SimpleAssignmentTarget::MemberAssignmentTarget(
+ MemberAssignmentTarget::ComputedMemberAssignmentTarget(
+ ComputedMemberAssignmentTarget {
+ object,
+ expression,
+ loc,
+ },
+ ),
+ ),
+ Expression::MemberExpression(MemberExpression::PrivateFieldExpression(
+ PrivateFieldExpression { object, field, loc },
+ )) => SimpleAssignmentTarget::MemberAssignmentTarget(
+ MemberAssignmentTarget::PrivateFieldAssignmentTarget(
+ PrivateFieldAssignmentTarget { object, field, loc },
+ ),
+ ),
+
+ // Static Semantics: AssignmentTargetType
+ // https://tc39.es/ecma262/#sec-static-semantics-static-semantics-assignmenttargettype
+ //
+ // CallExpression :
+ // CallExpression [ Expression ]
+ // CallExpression . IdentifierName
+ //
+ // 1. Return simple.
+ Expression::CallExpression(CallExpression { .. }) => {
+ return Err(ParseError::NotImplemented(
+ "Assignment to CallExpression is allowed for non-strict mode.",
+ )
+ .into());
+ }
+
+ _ => {
+ return Err(ParseError::InvalidAssignmentTarget.into());
+ }
+ })
+ }
+
+ // AssignmentExpression : LeftHandSideExpression `=` AssignmentExpression
+ pub fn assignment_expr(
+ &self,
+ left_hand_side: arena::Box<'alloc, Expression<'alloc>>,
+ value: arena::Box<'alloc, Expression<'alloc>>,
+ ) -> Result<'alloc, arena::Box<'alloc, Expression<'alloc>>> {
+ let target = self.expression_to_assignment_target(left_hand_side)?;
+ let target_loc = target.get_loc();
+ let value_loc = value.get_loc();
+ Ok(self.alloc_with(|| Expression::AssignmentExpression {
+ binding: target,
+ expression: value,
+ loc: SourceLocation::from_parts(target_loc, value_loc),
+ }))
+ }
+
+ pub fn add_assign_op(&self, token: arena::Box<'alloc, Token>) -> CompoundAssignmentOperator {
+ CompoundAssignmentOperator::Add { loc: token.loc }
+ }
+ pub fn sub_assign_op(&self, token: arena::Box<'alloc, Token>) -> CompoundAssignmentOperator {
+ CompoundAssignmentOperator::Sub { loc: token.loc }
+ }
+ pub fn mul_assign_op(&self, token: arena::Box<'alloc, Token>) -> CompoundAssignmentOperator {
+ CompoundAssignmentOperator::Mul { loc: token.loc }
+ }
+ pub fn div_assign_op(&self, token: arena::Box<'alloc, Token>) -> CompoundAssignmentOperator {
+ CompoundAssignmentOperator::Div { loc: token.loc }
+ }
+ pub fn mod_assign_op(&self, token: arena::Box<'alloc, Token>) -> CompoundAssignmentOperator {
+ CompoundAssignmentOperator::Mod { loc: token.loc }
+ }
+ pub fn pow_assign_op(&self, token: arena::Box<'alloc, Token>) -> CompoundAssignmentOperator {
+ CompoundAssignmentOperator::Pow { loc: token.loc }
+ }
+ pub fn left_shift_assign_op(
+ &self,
+ token: arena::Box<'alloc, Token>,
+ ) -> CompoundAssignmentOperator {
+ CompoundAssignmentOperator::LeftShift { loc: token.loc }
+ }
+ pub fn right_shift_assign_op(
+ &self,
+ token: arena::Box<'alloc, Token>,
+ ) -> CompoundAssignmentOperator {
+ CompoundAssignmentOperator::RightShift { loc: token.loc }
+ }
+ pub fn right_shift_ext_assign_op(
+ &self,
+ token: arena::Box<'alloc, Token>,
+ ) -> CompoundAssignmentOperator {
+ CompoundAssignmentOperator::RightShiftExt { loc: token.loc }
+ }
+ pub fn bitwise_or_assign_op(
+ &self,
+ token: arena::Box<'alloc, Token>,
+ ) -> CompoundAssignmentOperator {
+ CompoundAssignmentOperator::Or { loc: token.loc }
+ }
+ pub fn bitwise_xor_assign_op(
+ &self,
+ token: arena::Box<'alloc, Token>,
+ ) -> CompoundAssignmentOperator {
+ CompoundAssignmentOperator::Xor { loc: token.loc }
+ }
+ pub fn bitwise_and_assign_op(
+ &self,
+ token: arena::Box<'alloc, Token>,
+ ) -> CompoundAssignmentOperator {
+ CompoundAssignmentOperator::And { loc: token.loc }
+ }
+
+ pub fn logical_or_assign_op(
+ &self,
+ token: arena::Box<'alloc, Token>,
+ ) -> CompoundAssignmentOperator {
+ CompoundAssignmentOperator::LogicalOr { loc: token.loc }
+ }
+ pub fn logical_and_assign_op(
+ &self,
+ token: arena::Box<'alloc, Token>,
+ ) -> CompoundAssignmentOperator {
+ CompoundAssignmentOperator::LogicalAnd { loc: token.loc }
+ }
+ pub fn coalesce_assign_op(
+ &self,
+ token: arena::Box<'alloc, Token>,
+ ) -> CompoundAssignmentOperator {
+ CompoundAssignmentOperator::Coalesce { loc: token.loc }
+ }
+
+ pub fn box_assign_op(
+ &self,
+ op: CompoundAssignmentOperator,
+ ) -> arena::Box<'alloc, CompoundAssignmentOperator> {
+ self.alloc_with(|| op)
+ }
+
+ // AssignmentExpression : LeftHandSideExpression AssignmentOperator AssignmentExpression
+ // AssignmentExpression : LeftHandSideExpression LogicalAssignmentOperator AssignmentExpression
+ pub fn compound_assignment_expr(
+ &self,
+ left_hand_side: arena::Box<'alloc, Expression<'alloc>>,
+ operator: arena::Box<'alloc, CompoundAssignmentOperator>,
+ value: arena::Box<'alloc, Expression<'alloc>>,
+ ) -> Result<'alloc, arena::Box<'alloc, Expression<'alloc>>> {
+ let target = self.expression_to_simple_assignment_target(left_hand_side)?;
+ let target_loc = target.get_loc();
+ let value_loc = value.get_loc();
+ Ok(
+ self.alloc_with(|| Expression::CompoundAssignmentExpression {
+ operator: operator.unbox(),
+ binding: target,
+ expression: value,
+ loc: SourceLocation::from_parts(target_loc, value_loc),
+ }),
+ )
+ }
+
+ // BlockStatement : Block
+ pub fn block_statement(
+ &self,
+ block: arena::Box<'alloc, Block<'alloc>>,
+ ) -> arena::Box<'alloc, Statement<'alloc>> {
+ let loc = block.loc;
+ self.alloc_with(|| Statement::BlockStatement {
+ block: block.unbox(),
+ loc,
+ })
+ }
+
+ // Block : `{` StatementList? `}`
+ pub fn block(
+ &mut self,
+ open_token: arena::Box<'alloc, Token>,
+ statements: Option<arena::Box<'alloc, arena::Vec<'alloc, Statement<'alloc>>>>,
+ close_token: arena::Box<'alloc, Token>,
+ ) -> Result<'alloc, arena::Box<'alloc, Block<'alloc>>> {
+ self.check_block_bindings(open_token.loc.start)?;
+
+ Ok(self.alloc_with(|| Block {
+ statements: match statements {
+ Some(statements) => statements.unbox(),
+ None => self.new_vec(),
+ },
+ declarations: None,
+ loc: SourceLocation::from_parts(open_token.loc, close_token.loc),
+ }))
+ }
+
+ // Block : `{` StatementList? `}`
+ // for Catch
+ pub fn catch_block(
+ &mut self,
+ open_token: arena::Box<'alloc, Token>,
+ statements: Option<arena::Box<'alloc, arena::Vec<'alloc, Statement<'alloc>>>>,
+ close_token: arena::Box<'alloc, Token>,
+ ) -> arena::Box<'alloc, Block<'alloc>> {
+ // Early Error handling is done in Catch.
+
+ self.alloc_with(|| Block {
+ statements: match statements {
+ Some(statements) => statements.unbox(),
+ None => self.new_vec(),
+ },
+ declarations: None,
+ loc: SourceLocation::from_parts(open_token.loc, close_token.loc),
+ })
+ }
+
+ // StatementList : StatementListItem
+ pub fn statement_list_single(
+ &self,
+ statement: arena::Box<'alloc, Statement<'alloc>>,
+ ) -> arena::Box<'alloc, arena::Vec<'alloc, Statement<'alloc>>> {
+ self.alloc_with(|| self.new_vec_single(statement.unbox()))
+ }
+
+ // StatementList : StatementList StatementListItem
+ pub fn statement_list_append(
+ &self,
+ mut list: arena::Box<'alloc, arena::Vec<'alloc, Statement<'alloc>>>,
+ statement: arena::Box<'alloc, Statement<'alloc>>,
+ ) -> arena::Box<'alloc, arena::Vec<'alloc, Statement<'alloc>>> {
+ self.push(&mut list, statement.unbox());
+ list
+ }
+
+ // LexicalDeclaration : LetOrConst BindingList `;`
+ pub fn lexical_declaration(
+ &mut self,
+ kind: arena::Box<'alloc, VariableDeclarationKind>,
+ declarators: arena::Box<'alloc, arena::Vec<'alloc, VariableDeclarator<'alloc>>>,
+ ) -> Result<'alloc, arena::Box<'alloc, Statement<'alloc>>> {
+ let binding_kind = match &*kind {
+ VariableDeclarationKind::Let { .. } => BindingKind::Let,
+ VariableDeclarationKind::Const { .. } => BindingKind::Const,
+ _ => panic!("unexpected VariableDeclarationKind"),
+ };
+
+ self.context_metadata
+ .mark_binding_kind(kind.get_loc().start, None, binding_kind);
+
+ // 13.3.1.1 Static Semantics: Early Errors
+ if let VariableDeclarationKind::Const { .. } = *kind {
+ for v in declarators.iter() {
+ if v.init == None {
+ return Err(ParseError::NotImplemented(
+ "Missing initializer in a lexical binding.",
+ )
+ .into());
+ }
+ }
+ }
+
+ let kind_loc = kind.get_loc();
+ let declarator_loc = declarators
+ .last()
+ .expect("There should be at least one declarator")
+ .get_loc();
+ Ok(self.alloc_with(|| {
+ Statement::VariableDeclarationStatement(VariableDeclaration {
+ kind: kind.unbox(),
+ declarators: declarators.unbox(),
+ loc: SourceLocation::from_parts(kind_loc, declarator_loc),
+ })
+ }))
+ }
+
+ // ForLexicalDeclaration : LetOrConst BindingList `;`
+ pub fn for_lexical_declaration(
+ &mut self,
+ kind: arena::Box<'alloc, VariableDeclarationKind>,
+ declarators: arena::Box<'alloc, arena::Vec<'alloc, VariableDeclarator<'alloc>>>,
+ ) -> Result<'alloc, arena::Box<'alloc, VariableDeclarationOrExpression<'alloc>>> {
+ let binding_kind = match &*kind {
+ VariableDeclarationKind::Let { .. } => BindingKind::Let,
+ VariableDeclarationKind::Const { .. } => BindingKind::Const,
+ _ => panic!("unexpected VariableDeclarationKind"),
+ };
+ self.context_metadata
+ .mark_binding_kind(kind.get_loc().start, None, binding_kind);
+
+ // 13.3.1.1 Static Semantics: Early Errors
+ if let VariableDeclarationKind::Const { .. } = *kind {
+ for v in declarators.iter() {
+ if v.init == None {
+ return Err(ParseError::NotImplemented(
+ "Missing initializer in a lexical binding.",
+ )
+ .into());
+ }
+ }
+ }
+
+ let kind_loc = kind.get_loc();
+ let declarator_loc = declarators
+ .last()
+ .expect("There should be at least one declarator")
+ .get_loc();
+ Ok(self.alloc_with(|| {
+ VariableDeclarationOrExpression::VariableDeclaration(VariableDeclaration {
+ kind: kind.unbox(),
+ declarators: declarators.unbox(),
+ loc: SourceLocation::from_parts(kind_loc, declarator_loc),
+ })
+ }))
+ }
+
+ // LetOrConst : `let`
+ pub fn let_kind(
+ &self,
+ token: arena::Box<'alloc, Token>,
+ ) -> arena::Box<'alloc, VariableDeclarationKind> {
+ self.alloc_with(|| VariableDeclarationKind::Let { loc: token.loc })
+ }
+
+ // LetOrConst : `const`
+ pub fn const_kind(
+ &self,
+ token: arena::Box<'alloc, Token>,
+ ) -> arena::Box<'alloc, VariableDeclarationKind> {
+ self.alloc_with(|| VariableDeclarationKind::Const { loc: token.loc })
+ }
+
+ // VariableStatement : `var` VariableDeclarationList `;`
+ pub fn variable_statement(
+ &mut self,
+ var_token: arena::Box<'alloc, Token>,
+ declarators: arena::Box<'alloc, arena::Vec<'alloc, VariableDeclarator<'alloc>>>,
+ ) -> arena::Box<'alloc, Statement<'alloc>> {
+ let var_loc = var_token.loc;
+ let declarator_loc = declarators
+ .last()
+ .expect("There should be at least one declarator")
+ .get_loc();
+
+ self.context_metadata
+ .mark_binding_kind(var_loc.start, None, BindingKind::Var);
+
+ self.alloc_with(|| {
+ Statement::VariableDeclarationStatement(VariableDeclaration {
+ kind: VariableDeclarationKind::Var { loc: var_loc },
+ declarators: declarators.unbox(),
+ loc: SourceLocation::from_parts(var_loc, declarator_loc),
+ })
+ })
+ }
+
+ // VariableDeclarationList : VariableDeclaration
+ // BindingList : LexicalBinding
+ pub fn variable_declaration_list_single(
+ &self,
+ decl: arena::Box<'alloc, VariableDeclarator<'alloc>>,
+ ) -> arena::Box<'alloc, arena::Vec<'alloc, VariableDeclarator<'alloc>>> {
+ self.alloc_with(|| self.new_vec_single(decl.unbox()))
+ }
+
+ // VariableDeclarationList : VariableDeclarationList `,` VariableDeclaration
+ // BindingList : BindingList `,` LexicalBinding
+ pub fn variable_declaration_list_append(
+ &self,
+ mut list: arena::Box<'alloc, arena::Vec<'alloc, VariableDeclarator<'alloc>>>,
+ decl: arena::Box<'alloc, VariableDeclarator<'alloc>>,
+ ) -> arena::Box<'alloc, arena::Vec<'alloc, VariableDeclarator<'alloc>>> {
+ self.push(&mut list, decl.unbox());
+ list
+ }
+
+ // VariableDeclaration : BindingIdentifier Initializer?
+ // VariableDeclaration : BindingPattern Initializer
+ pub fn variable_declaration(
+ &self,
+ binding: arena::Box<'alloc, Binding<'alloc>>,
+ init: Option<arena::Box<'alloc, Expression<'alloc>>>,
+ ) -> arena::Box<'alloc, VariableDeclarator<'alloc>> {
+ let binding_loc = binding.get_loc();
+ let loc = match init {
+ Some(ref init) => SourceLocation::from_parts(binding_loc, init.get_loc()),
+ None => binding_loc,
+ };
+ self.alloc_with(|| VariableDeclarator {
+ binding: binding.unbox(),
+ init,
+ loc,
+ })
+ }
+
+ // ObjectBindingPattern : `{` `}`
+ // ObjectBindingPattern : `{` BindingRestProperty `}`
+ // ObjectBindingPattern : `{` BindingPropertyList `}`
+ // ObjectBindingPattern : `{` BindingPropertyList `,` BindingRestProperty? `}`
+ pub fn object_binding_pattern(
+ &self,
+ open_token: arena::Box<'alloc, Token>,
+ properties: arena::Box<'alloc, arena::Vec<'alloc, BindingProperty<'alloc>>>,
+ rest: Option<arena::Box<'alloc, BindingIdentifier>>,
+ close_token: arena::Box<'alloc, Token>,
+ ) -> arena::Box<'alloc, Binding<'alloc>> {
+ self.alloc_with(|| {
+ Binding::BindingPattern(BindingPattern::ObjectBinding(ObjectBinding {
+ properties: properties.unbox(),
+ rest,
+ loc: SourceLocation::from_parts(open_token.loc, close_token.loc),
+ }))
+ })
+ }
+
+ pub fn binding_element_list_empty(
+ &self,
+ ) -> arena::Box<'alloc, arena::Vec<'alloc, Option<Parameter<'alloc>>>> {
+ self.alloc_with(|| self.new_vec())
+ }
+
+ // ArrayBindingPattern : `[` Elision? BindingRestElement? `]`
+ // ArrayBindingPattern : `[` BindingElementList `]`
+ // ArrayBindingPattern : `[` BindingElementList `,` Elision? BindingRestElement? `]`
+ pub fn array_binding_pattern(
+ &self,
+ open_token: arena::Box<'alloc, Token>,
+ mut elements: arena::Box<'alloc, arena::Vec<'alloc, Option<Parameter<'alloc>>>>,
+ elision: Option<arena::Box<'alloc, ArrayExpression<'alloc>>>,
+ rest: Option<arena::Box<'alloc, Binding<'alloc>>>,
+ close_token: arena::Box<'alloc, Token>,
+ ) -> arena::Box<'alloc, Binding<'alloc>> {
+ if let Some(elision) = elision {
+ for _ in 0..elision.elements.len() {
+ self.push(&mut elements, None);
+ }
+ }
+
+ self.alloc_with(|| {
+ Binding::BindingPattern(BindingPattern::ArrayBinding(ArrayBinding {
+ elements: elements.unbox(),
+ rest,
+ loc: SourceLocation::from_parts(open_token.loc, close_token.loc),
+ }))
+ })
+ }
+
+ pub fn binding_property_list_empty(
+ &self,
+ ) -> arena::Box<'alloc, arena::Vec<'alloc, BindingProperty<'alloc>>> {
+ self.alloc_with(|| self.new_vec())
+ }
+
+ // BindingPropertyList : BindingProperty
+ pub fn binding_property_list_single(
+ &self,
+ property: arena::Box<'alloc, BindingProperty<'alloc>>,
+ ) -> arena::Box<'alloc, arena::Vec<'alloc, BindingProperty<'alloc>>> {
+ self.alloc_with(|| self.new_vec_single(property.unbox()))
+ }
+
+ // BindingPropertyList : BindingPropertyList `,` BindingProperty
+ pub fn binding_property_list_append(
+ &self,
+ mut list: arena::Box<'alloc, arena::Vec<'alloc, BindingProperty<'alloc>>>,
+ property: arena::Box<'alloc, BindingProperty<'alloc>>,
+ ) -> arena::Box<'alloc, arena::Vec<'alloc, BindingProperty<'alloc>>> {
+ self.push(&mut list, property.unbox());
+ list
+ }
+
+ // BindingElementList : BindingElementList `,` BindingElisionElement
+ pub fn binding_element_list_append(
+ &self,
+ mut list: arena::Box<'alloc, arena::Vec<'alloc, Option<Parameter<'alloc>>>>,
+ mut element: arena::Box<'alloc, arena::Vec<'alloc, Option<Parameter<'alloc>>>>,
+ ) -> arena::Box<'alloc, arena::Vec<'alloc, Option<Parameter<'alloc>>>> {
+ self.append(&mut list, &mut element);
+ list
+ }
+
+ // BindingElisionElement : Elision? BindingElement
+ pub fn binding_elision_element(
+ &self,
+ elision: Option<arena::Box<'alloc, ArrayExpression<'alloc>>>,
+ element: arena::Box<'alloc, Parameter<'alloc>>,
+ ) -> arena::Box<'alloc, arena::Vec<'alloc, Option<Parameter<'alloc>>>> {
+ let elision_count = elision.map(|v| v.elements.len()).unwrap_or(0);
+ let mut result = self.alloc_with(|| self.new_vec());
+ for _ in 0..elision_count {
+ self.push(&mut result, None);
+ }
+ self.push(&mut result, Some(element.unbox()));
+ result
+ }
+
+ // BindingProperty : SingleNameBinding
+ pub fn binding_property_shorthand(
+ &self,
+ binding: arena::Box<'alloc, Parameter<'alloc>>,
+ ) -> arena::Box<'alloc, BindingProperty<'alloc>> {
+ // Previous parsing interpreted this as a Parameter. We need to take
+ // all the pieces out of that box and put them in a new box.
+ let (binding, init) = match binding.unbox() {
+ Parameter::Binding(binding) => (binding, None),
+ Parameter::BindingWithDefault(BindingWithDefault { binding, init, .. }) => {
+ (binding, Some(init.unbox()))
+ }
+ };
+
+ let binding = match binding {
+ Binding::BindingIdentifier(bi) => bi,
+ _ => {
+ // The grammar ensures that the parser always passes a valid
+ // argument to this method.
+ panic!("invalid argument: binding_property_shorthand requires a Binding::BindingIdentifier");
+ }
+ };
+
+ let loc = binding.loc;
+
+ self.alloc_with(|| {
+ BindingProperty::BindingPropertyIdentifier(BindingPropertyIdentifier {
+ binding,
+ init: init.map(|x| self.alloc_with(|| x)),
+ loc,
+ })
+ })
+ }
+
+ // BindingProperty : PropertyName `:` BindingElement
+ pub fn binding_property(
+ &self,
+ name: arena::Box<'alloc, PropertyName<'alloc>>,
+ binding: arena::Box<'alloc, Parameter<'alloc>>,
+ ) -> arena::Box<'alloc, BindingProperty<'alloc>> {
+ let name_loc = name.get_loc();
+ let binding_loc = binding.get_loc();
+ self.alloc_with(|| {
+ BindingProperty::BindingPropertyProperty(BindingPropertyProperty {
+ name: name.unbox(),
+ binding: binding.unbox(),
+ loc: SourceLocation::from_parts(name_loc, binding_loc),
+ })
+ })
+ }
+
+ // BindingElement : BindingPattern Initializer?
+ pub fn binding_element_pattern(
+ &self,
+ binding: arena::Box<'alloc, Binding<'alloc>>,
+ init: Option<arena::Box<'alloc, Expression<'alloc>>>,
+ ) -> arena::Box<'alloc, Parameter<'alloc>> {
+ self.alloc_with(|| match init {
+ None => Parameter::Binding(binding.unbox()),
+ Some(init) => {
+ let binding_loc = binding.get_loc();
+ let init_loc = init.get_loc();
+ Parameter::BindingWithDefault(BindingWithDefault {
+ binding: binding.unbox(),
+ init,
+ loc: SourceLocation::from_parts(binding_loc, init_loc),
+ })
+ }
+ })
+ }
+
+ // SingleNameBinding : BindingIdentifier Initializer?
+ pub fn single_name_binding(
+ &self,
+ name: arena::Box<'alloc, BindingIdentifier>,
+ init: Option<arena::Box<'alloc, Expression<'alloc>>>,
+ ) -> arena::Box<'alloc, Parameter<'alloc>> {
+ let binding = Binding::BindingIdentifier(name.unbox());
+ self.alloc_with(|| match init {
+ None => Parameter::Binding(binding),
+ Some(init) => {
+ let binding_loc = binding.get_loc();
+ let init_loc = init.get_loc();
+ Parameter::BindingWithDefault(BindingWithDefault {
+ binding,
+ init,
+ loc: SourceLocation::from_parts(binding_loc, init_loc),
+ })
+ }
+ })
+ }
+
+ // BindingRestElement : `...` BindingIdentifier
+ pub fn binding_rest_element(
+ &self,
+ name: arena::Box<'alloc, BindingIdentifier>,
+ ) -> arena::Box<'alloc, Binding<'alloc>> {
+ self.alloc_with(|| Binding::BindingIdentifier(name.unbox()))
+ }
+
+ // EmptyStatement : `;`
+ pub fn empty_statement(
+ &self,
+ token: arena::Box<'alloc, Token>,
+ ) -> arena::Box<'alloc, Statement<'alloc>> {
+ self.alloc_with(|| Statement::EmptyStatement { loc: token.loc })
+ }
+
+ // ExpressionStatement : [lookahead not in {'{', 'function', 'async', 'class', 'let'}] Expression `;`
+ pub fn expression_statement(
+ &self,
+ expression: arena::Box<'alloc, Expression<'alloc>>,
+ ) -> arena::Box<'alloc, Statement<'alloc>> {
+ self.alloc_with(|| Statement::ExpressionStatement(expression))
+ }
+
+ // IfStatement : `if` `(` Expression `)` Statement `else` Statement
+ // IfStatement : `if` `(` Expression `)` Statement
+ pub fn if_statement(
+ &self,
+ if_token: arena::Box<'alloc, Token>,
+ test: arena::Box<'alloc, Expression<'alloc>>,
+ consequent: arena::Box<'alloc, Statement<'alloc>>,
+ alternate: Option<arena::Box<'alloc, Statement<'alloc>>>,
+ ) -> Result<'alloc, arena::Box<'alloc, Statement<'alloc>>> {
+ self.check_single_statement(consequent.get_loc().start)?;
+ if let Some(ref stmt) = alternate {
+ self.check_single_statement(stmt.get_loc().start)?;
+ }
+
+ let if_loc = if_token.loc;
+ let loc = match alternate {
+ Some(ref alternate) => SourceLocation::from_parts(if_loc, alternate.get_loc()),
+ None => SourceLocation::from_parts(if_loc, consequent.get_loc()),
+ };
+ Ok(self.alloc_with(|| {
+ Statement::IfStatement(IfStatement {
+ test,
+ consequent,
+ alternate,
+ loc,
+ })
+ }))
+ }
+
+ // Create BlockStatement from FunctionDeclaration, for the following:
+ //
+ // IfStatement : `if` `(` Expression `)` FunctionDeclaration `else` Statement
+ // IfStatement : `if` `(` Expression `)` Statement `else` FunctionDeclaration
+ // IfStatement : `if` `(` Expression `)` FunctionDeclaration `else` FunctionDeclaration
+ // IfStatement : `if` `(` Expression `)` FunctionDeclaration
+ pub fn make_block_stmt_from_function_decl(
+ &mut self,
+ fun: arena::Box<'alloc, Statement<'alloc>>,
+ ) -> Result<'alloc, arena::Box<'alloc, Statement<'alloc>>> {
+ let fun_loc = fun.get_loc();
+
+ // Annex B. FunctionDeclarations in IfStatement Statement Clauses
+ // https://tc39.es/ecma262/#sec-functiondeclarations-in-ifstatement-statement-clauses
+ //
+ // This production only applies when parsing non-strict code.
+ if self.is_strict()? {
+ return Err(ParseError::FunctionDeclInSingleStatement.into());
+ }
+
+ // Code matching this production is processed as if each matching
+ // occurrence of FunctionDeclaration[?Yield, ?Await, ~Default] was the
+ // sole StatementListItem of a BlockStatement occupying that position
+ // in the source code. The semantics of such a synthetic BlockStatement
+ // includes the web legacy compatibility semantics specified in B.3.3.
+ self.check_block_bindings(fun_loc.start)?;
+
+ Ok(self.alloc_with(|| Statement::BlockStatement {
+ block: Block {
+ statements: self.new_vec_single(fun.unbox()),
+ declarations: None,
+ loc: fun_loc,
+ },
+ loc: fun_loc,
+ }))
+ }
+
+ fn is_strict(&self) -> Result<'alloc, bool> {
+ Err(ParseError::NotImplemented("strict-mode-only early error is not yet supported").into())
+ }
+
+ // IterationStatement : `do` Statement `while` `(` Expression `)` `;`
+ pub fn do_while_statement(
+ &mut self,
+ do_token: arena::Box<'alloc, Token>,
+ stmt: arena::Box<'alloc, Statement<'alloc>>,
+ test: arena::Box<'alloc, Expression<'alloc>>,
+ close_token: arena::Box<'alloc, Token>,
+ ) -> Result<'alloc, arena::Box<'alloc, Statement<'alloc>>> {
+ self.check_single_statement(stmt.get_loc().start)?;
+
+ self.context_metadata
+ .pop_unlabelled_breaks_and_continues_from(do_token.loc.start);
+ Ok(self.alloc_with(|| Statement::DoWhileStatement {
+ block: stmt,
+ test,
+ loc: SourceLocation::from_parts(do_token.loc, close_token.loc),
+ }))
+ }
+
+ // IterationStatement : `while` `(` Expression `)` Statement
+ pub fn while_statement(
+ &mut self,
+ while_token: arena::Box<'alloc, Token>,
+ test: arena::Box<'alloc, Expression<'alloc>>,
+ stmt: arena::Box<'alloc, Statement<'alloc>>,
+ ) -> Result<'alloc, arena::Box<'alloc, Statement<'alloc>>> {
+ self.check_single_statement(stmt.get_loc().start)?;
+
+ let stmt_loc = stmt.get_loc();
+ self.context_metadata
+ .pop_unlabelled_breaks_and_continues_from(stmt_loc.start);
+ Ok(self.alloc_with(|| Statement::WhileStatement {
+ test,
+ block: stmt,
+ loc: SourceLocation::from_parts(while_token.loc, stmt_loc),
+ }))
+ }
+
+ // IterationStatement : `for` `(` [lookahead != 'let'] Expression? `;` Expression? `;` Expression? `)` Statement
+ // IterationStatement : `for` `(` `var` VariableDeclarationList `;` Expression? `;` Expression? `)` Statement
+ pub fn for_statement(
+ &mut self,
+ for_token: arena::Box<'alloc, Token>,
+ init: Option<VariableDeclarationOrExpression<'alloc>>,
+ test: Option<arena::Box<'alloc, Expression<'alloc>>>,
+ update: Option<arena::Box<'alloc, Expression<'alloc>>>,
+ stmt: arena::Box<'alloc, Statement<'alloc>>,
+ ) -> Result<'alloc, arena::Box<'alloc, Statement<'alloc>>> {
+ self.check_single_statement(stmt.get_loc().start)?;
+ self.for_statement_common(for_token, init, test, update, stmt)
+ }
+
+ // IterationStatement : `for` `(` ForLexicalDeclaration Expression? `;` Expression? `)` Statement
+ pub fn for_statement_lexical(
+ &mut self,
+ for_token: arena::Box<'alloc, Token>,
+ init: VariableDeclarationOrExpression<'alloc>,
+ test: Option<arena::Box<'alloc, Expression<'alloc>>>,
+ update: Option<arena::Box<'alloc, Expression<'alloc>>>,
+ stmt: arena::Box<'alloc, Statement<'alloc>>,
+ ) -> Result<'alloc, arena::Box<'alloc, Statement<'alloc>>> {
+ self.check_single_statement(stmt.get_loc().start)?;
+ let init_loc = &init.get_loc();
+ self.check_lexical_for_bindings(init_loc.start, init_loc.end)?;
+ self.for_statement_common(for_token, Some(init), test, update, stmt)
+ }
+
+ pub fn for_statement_common(
+ &mut self,
+ for_token: arena::Box<'alloc, Token>,
+ init: Option<VariableDeclarationOrExpression<'alloc>>,
+ test: Option<arena::Box<'alloc, Expression<'alloc>>>,
+ update: Option<arena::Box<'alloc, Expression<'alloc>>>,
+ stmt: arena::Box<'alloc, Statement<'alloc>>,
+ ) -> Result<'alloc, arena::Box<'alloc, Statement<'alloc>>> {
+ let stmt_loc = stmt.get_loc();
+ self.context_metadata
+ .pop_unlabelled_breaks_and_continues_from(stmt_loc.start);
+ Ok(self.alloc_with(|| Statement::ForStatement {
+ init,
+ test,
+ update,
+ block: stmt,
+ loc: SourceLocation::from_parts(for_token.loc, stmt_loc),
+ }))
+ }
+
+ pub fn for_expression(
+ &self,
+ expr: Option<arena::Box<'alloc, Expression<'alloc>>>,
+ ) -> Option<VariableDeclarationOrExpression<'alloc>> {
+ expr.map(|expr| VariableDeclarationOrExpression::Expression(expr))
+ }
+
+ pub fn for_var_declaration(
+ &mut self,
+ var_token: arena::Box<'alloc, Token>,
+ declarators: arena::Box<'alloc, arena::Vec<'alloc, VariableDeclarator<'alloc>>>,
+ ) -> VariableDeclarationOrExpression<'alloc> {
+ let var_loc = var_token.loc;
+ let declarator_loc = declarators
+ .last()
+ .expect("There should be at least one declarator")
+ .get_loc();
+
+ self.context_metadata.mark_binding_kind(
+ var_loc.start,
+ Some(declarator_loc.end),
+ BindingKind::Var,
+ );
+
+ VariableDeclarationOrExpression::VariableDeclaration(VariableDeclaration {
+ kind: VariableDeclarationKind::Var { loc: var_loc },
+ declarators: declarators.unbox(),
+ loc: SourceLocation::from_parts(var_loc, declarator_loc),
+ })
+ }
+
+ pub fn unbox_for_lexical_declaration(
+ &self,
+ declaration: arena::Box<'alloc, VariableDeclarationOrExpression<'alloc>>,
+ ) -> VariableDeclarationOrExpression<'alloc> {
+ declaration.unbox()
+ }
+
+ // IterationStatement : `for` `(` [lookahead != 'let'] LeftHandSideExpression `in` Expression `)` Statement
+ // IterationStatement : `for` `(` `var` ForBinding `in` Expression `)` Statement
+ //
+ // Annex B: Initializers in ForIn Statement Heads
+ // https://tc39.es/ecma262/#sec-initializers-in-forin-statement-heads
+ //
+ // IterationStatement : `for` `(` `var` BindingIdentifier Initializer `in` Expression `)` Statement
+ pub fn for_in_statement(
+ &mut self,
+ for_token: arena::Box<'alloc, Token>,
+ left: VariableDeclarationOrAssignmentTarget<'alloc>,
+ right: arena::Box<'alloc, Expression<'alloc>>,
+ stmt: arena::Box<'alloc, Statement<'alloc>>,
+ ) -> Result<'alloc, arena::Box<'alloc, Statement<'alloc>>> {
+ self.check_single_statement(stmt.get_loc().start)?;
+ self.for_in_statement_common(for_token, left, right, stmt)
+ }
+
+ // IterationStatement : `for` `(` ForDeclaration `in` Expression `)` Statement
+ pub fn for_in_statement_lexical(
+ &mut self,
+ for_token: arena::Box<'alloc, Token>,
+ left: VariableDeclarationOrAssignmentTarget<'alloc>,
+ right: arena::Box<'alloc, Expression<'alloc>>,
+ stmt: arena::Box<'alloc, Statement<'alloc>>,
+ ) -> Result<'alloc, arena::Box<'alloc, Statement<'alloc>>> {
+ self.check_single_statement(stmt.get_loc().start)?;
+ let left_loc = &left.get_loc();
+ self.check_lexical_for_bindings(left_loc.start, left_loc.end)?;
+ self.for_in_statement_common(for_token, left, right, stmt)
+ }
+
+ pub fn for_in_statement_common(
+ &mut self,
+ for_token: arena::Box<'alloc, Token>,
+ left: VariableDeclarationOrAssignmentTarget<'alloc>,
+ right: arena::Box<'alloc, Expression<'alloc>>,
+ stmt: arena::Box<'alloc, Statement<'alloc>>,
+ ) -> Result<'alloc, arena::Box<'alloc, Statement<'alloc>>> {
+ let stmt_loc = stmt.get_loc();
+ self.context_metadata
+ .pop_unlabelled_breaks_and_continues_from(stmt_loc.start);
+ Ok(self.alloc_with(|| Statement::ForInStatement {
+ left,
+ right,
+ block: stmt,
+ loc: SourceLocation::from_parts(for_token.loc, stmt_loc),
+ }))
+ }
+
+ pub fn for_in_or_of_var_declaration(
+ &mut self,
+ var_token: arena::Box<'alloc, Token>,
+ binding: arena::Box<'alloc, Binding<'alloc>>,
+ init: Option<arena::Box<'alloc, Expression<'alloc>>>,
+ ) -> VariableDeclarationOrAssignmentTarget<'alloc> {
+ let var_loc = var_token.loc;
+ let binding_loc = binding.get_loc();
+ let decl_loc = match init {
+ Some(ref init) => SourceLocation::from_parts(binding_loc, init.get_loc()),
+ None => binding_loc,
+ };
+
+ self.context_metadata.mark_binding_kind(
+ binding_loc.start,
+ Some(binding_loc.end),
+ BindingKind::Var,
+ );
+
+ VariableDeclarationOrAssignmentTarget::VariableDeclaration(VariableDeclaration {
+ kind: VariableDeclarationKind::Var { loc: var_loc },
+ declarators: self.new_vec_single(VariableDeclarator {
+ binding: binding.unbox(),
+ init,
+ loc: decl_loc,
+ }),
+ loc: SourceLocation::from_parts(var_loc, decl_loc),
+ })
+ }
+
+ pub fn for_assignment_target(
+ &self,
+ expression: arena::Box<'alloc, Expression<'alloc>>,
+ ) -> Result<'alloc, VariableDeclarationOrAssignmentTarget<'alloc>> {
+ Ok(VariableDeclarationOrAssignmentTarget::AssignmentTarget(
+ self.expression_to_assignment_target(expression)?,
+ ))
+ }
+
+ pub fn unbox_for_declaration(
+ &self,
+ declaration: arena::Box<'alloc, VariableDeclarationOrAssignmentTarget<'alloc>>,
+ ) -> VariableDeclarationOrAssignmentTarget<'alloc> {
+ declaration.unbox()
+ }
+
+ // IterationStatement : `for` `(` [lookahead != 'let'] LeftHandSideExpression `of` AssignmentExpression `)` Statement
+ // IterationStatement : `for` `(` `var` ForBinding `of` AssignmentExpression `)` Statement
+ pub fn for_of_statement(
+ &mut self,
+ for_token: arena::Box<'alloc, Token>,
+ left: VariableDeclarationOrAssignmentTarget<'alloc>,
+ right: arena::Box<'alloc, Expression<'alloc>>,
+ stmt: arena::Box<'alloc, Statement<'alloc>>,
+ ) -> Result<'alloc, arena::Box<'alloc, Statement<'alloc>>> {
+ self.check_single_statement(stmt.get_loc().start)?;
+ self.for_of_statement_common(for_token, left, right, stmt)
+ }
+
+ // IterationStatement : `for` `(` ForDeclaration `of` AssignmentExpression `)` Statement
+ pub fn for_of_statement_lexical(
+ &mut self,
+ for_token: arena::Box<'alloc, Token>,
+ left: VariableDeclarationOrAssignmentTarget<'alloc>,
+ right: arena::Box<'alloc, Expression<'alloc>>,
+ stmt: arena::Box<'alloc, Statement<'alloc>>,
+ ) -> Result<'alloc, arena::Box<'alloc, Statement<'alloc>>> {
+ self.check_single_statement(stmt.get_loc().start)?;
+ let left_loc = &left.get_loc();
+ self.check_lexical_for_bindings(left_loc.start, left_loc.end)?;
+ self.for_of_statement_common(for_token, left, right, stmt)
+ }
+
+ pub fn for_of_statement_common(
+ &mut self,
+ for_token: arena::Box<'alloc, Token>,
+ left: VariableDeclarationOrAssignmentTarget<'alloc>,
+ right: arena::Box<'alloc, Expression<'alloc>>,
+ stmt: arena::Box<'alloc, Statement<'alloc>>,
+ ) -> Result<'alloc, arena::Box<'alloc, Statement<'alloc>>> {
+ let stmt_loc = stmt.get_loc();
+ self.context_metadata
+ .pop_unlabelled_breaks_and_continues_from(stmt_loc.start);
+ Ok(self.alloc_with(|| Statement::ForOfStatement {
+ left,
+ right,
+ block: stmt,
+ loc: SourceLocation::from_parts(for_token.loc, stmt_loc),
+ }))
+ }
+
+ // IterationStatement : `for` `await` `(` [lookahead != 'let'] LeftHandSideExpression `of` AssignmentExpression `)` Statement
+ // IterationStatement : `for` `await` `(` `var` ForBinding `of` AssignmentExpression `)` Statement
+ pub fn for_await_of_statement(
+ &self,
+ for_token: arena::Box<'alloc, Token>,
+ left: VariableDeclarationOrAssignmentTarget,
+ right: arena::Box<'alloc, Expression<'alloc>>,
+ stmt: arena::Box<'alloc, Statement<'alloc>>,
+ ) -> Result<'alloc, arena::Box<'alloc, Statement<'alloc>>> {
+ self.check_single_statement(stmt.get_loc().start)?;
+ self.for_await_of_statement_common(for_token, left, right, stmt)
+ }
+
+ // IterationStatement : `for` `await` `(` ForDeclaration `of` AssignmentExpression `)` Statement
+ pub fn for_await_of_statement_lexical(
+ &mut self,
+ for_token: arena::Box<'alloc, Token>,
+ left: VariableDeclarationOrAssignmentTarget,
+ right: arena::Box<'alloc, Expression<'alloc>>,
+ stmt: arena::Box<'alloc, Statement<'alloc>>,
+ ) -> Result<'alloc, arena::Box<'alloc, Statement<'alloc>>> {
+ self.check_single_statement(stmt.get_loc().start)?;
+ let left_loc = &left.get_loc();
+ self.check_lexical_for_bindings(left_loc.start, left_loc.end)?;
+ self.for_await_of_statement_common(for_token, left, right, stmt)
+ }
+
+ pub fn for_await_of_statement_common(
+ &self,
+ _for_token: arena::Box<'alloc, Token>,
+ _left: VariableDeclarationOrAssignmentTarget,
+ _right: arena::Box<'alloc, Expression<'alloc>>,
+ _stmt: arena::Box<'alloc, Statement<'alloc>>,
+ ) -> Result<'alloc, arena::Box<'alloc, Statement<'alloc>>> {
+ Err(ParseError::NotImplemented("for await statement (missing from AST)").into())
+ }
+
+ // ForDeclaration : LetOrConst ForBinding => ForDeclaration($0, $1)
+ pub fn for_declaration(
+ &mut self,
+ kind: arena::Box<'alloc, VariableDeclarationKind>,
+ binding: arena::Box<'alloc, Binding<'alloc>>,
+ ) -> arena::Box<'alloc, VariableDeclarationOrAssignmentTarget<'alloc>> {
+ let binding_kind = match &*kind {
+ VariableDeclarationKind::Let { .. } => BindingKind::Let,
+ VariableDeclarationKind::Const { .. } => BindingKind::Const,
+ _ => panic!("unexpected VariableDeclarationKind"),
+ };
+
+ self.context_metadata
+ .mark_binding_kind(kind.get_loc().start, None, binding_kind);
+
+ let kind_loc = kind.get_loc();
+ let binding_loc = binding.get_loc();
+ self.alloc_with(|| {
+ VariableDeclarationOrAssignmentTarget::VariableDeclaration(VariableDeclaration {
+ kind: kind.unbox(),
+ declarators: self.new_vec_single(VariableDeclarator {
+ binding: binding.unbox(),
+ init: None,
+ loc: binding_loc,
+ }),
+ loc: SourceLocation::from_parts(kind_loc, binding_loc),
+ })
+ })
+ }
+
+ // CatchParameter : BindingIdentifier
+ // ForBinding : BindingIdentifier
+ // LexicalBinding : BindingIdentifier Initializer?
+ // VariableDeclaration : BindingIdentifier Initializer?
+ pub fn binding_identifier_to_binding(
+ &self,
+ identifier: arena::Box<'alloc, BindingIdentifier>,
+ ) -> arena::Box<'alloc, Binding<'alloc>> {
+ self.alloc_with(|| Binding::BindingIdentifier(identifier.unbox()))
+ }
+
+ // ContinueStatement : `continue` `;`
+ // ContinueStatement : `continue` LabelIdentifier `;`
+ pub fn continue_statement(
+ &mut self,
+ continue_token: arena::Box<'alloc, Token>,
+ label: Option<arena::Box<'alloc, Label>>,
+ ) -> Result<'alloc, arena::Box<'alloc, Statement<'alloc>>> {
+ let info = match label {
+ Some(ref label) => {
+ // Label is used both for LabelledStatement and for labelled
+ // ContinueStatements. A label will be noted in the context metadata
+ // whenever we hit a label, as is the case for BreakStatements. These
+ // bindings are not necessary, and are at the end of the bindings stack.
+ // To keep things clean, we will pop the last element (the label we just
+ // added) off the stack.
+ let index = self
+ .context_metadata
+ .find_first_label(continue_token.loc.start);
+ self.context_metadata.pop_labels_from(index);
+
+ ControlInfo::new_continue(continue_token.loc.start, Some(label.value))
+ }
+ None => ControlInfo::new_continue(continue_token.loc.start, None),
+ };
+
+ self.context_metadata.push_break_or_continue(info);
+
+ let continue_loc = continue_token.loc;
+ let loc = match label {
+ Some(ref label) => SourceLocation::from_parts(continue_loc, label.loc),
+ None => continue_loc,
+ };
+ Ok(self.alloc_with(|| Statement::ContinueStatement {
+ label: label.map(|boxed| boxed.unbox()),
+ loc,
+ }))
+ }
+
+ // BreakStatement : `break` `;`
+ // BreakStatement : `break` LabelIdentifier `;`
+ pub fn break_statement(
+ &mut self,
+ break_token: arena::Box<'alloc, Token>,
+ label: Option<arena::Box<'alloc, Label>>,
+ ) -> Result<'alloc, arena::Box<'alloc, Statement<'alloc>>> {
+ let info = match label {
+ Some(ref label) => {
+ // Label is used both for LabelledStatement and for labelled
+ // BreakStatements. A label will be noted in the context metadata
+ // whenever we hit a label, as is the case for BreakStatements. These
+ // bindings are not necessary, and are at the end of the bindings stack.
+ // To keep things clean, we will pop the last element (the label we just
+ // added) off the stack.
+ let index = self.context_metadata.find_first_label(label.loc.start);
+ self.context_metadata.pop_labels_from(index);
+
+ ControlInfo::new_break(break_token.loc.start, Some(label.value))
+ }
+ None => ControlInfo::new_break(break_token.loc.start, None),
+ };
+
+ self.context_metadata.push_break_or_continue(info);
+ let break_loc = break_token.loc;
+ let loc = match label {
+ Some(ref label) => SourceLocation::from_parts(break_loc, label.loc),
+ None => break_loc,
+ };
+ Ok(self.alloc_with(|| Statement::BreakStatement {
+ label: label.map(|boxed| boxed.unbox()),
+ loc,
+ }))
+ }
+
+ // ReturnStatement : `return` `;`
+ // ReturnStatement : `return` Expression `;`
+ pub fn return_statement(
+ &self,
+ return_token: arena::Box<'alloc, Token>,
+ expression: Option<arena::Box<'alloc, Expression<'alloc>>>,
+ ) -> arena::Box<'alloc, Statement<'alloc>> {
+ let return_loc = return_token.loc;
+ let loc = match expression {
+ Some(ref expression) => SourceLocation::from_parts(return_loc, expression.get_loc()),
+ None => return_loc,
+ };
+ self.alloc_with(|| Statement::ReturnStatement { expression, loc })
+ }
+
+ // WithStatement : `with` `(` Expression `)` Statement
+ pub fn with_statement(
+ &self,
+ with_token: arena::Box<'alloc, Token>,
+ object: arena::Box<'alloc, Expression<'alloc>>,
+ body: arena::Box<'alloc, Statement<'alloc>>,
+ ) -> arena::Box<'alloc, Statement<'alloc>> {
+ let body_loc = body.get_loc();
+ self.alloc_with(|| Statement::WithStatement {
+ object,
+ body,
+ loc: SourceLocation::from_parts(with_token.loc, body_loc),
+ })
+ }
+
+ // SwitchStatement : `switch` `(` Expression `)` CaseBlock
+ pub fn switch_statement(
+ &self,
+ switch_token: arena::Box<'alloc, Token>,
+ discriminant_expr: arena::Box<'alloc, Expression<'alloc>>,
+ mut cases: arena::Box<'alloc, Statement<'alloc>>,
+ ) -> arena::Box<'alloc, Statement<'alloc>> {
+ match &mut *cases {
+ Statement::SwitchStatement {
+ discriminant, loc, ..
+ } => {
+ *discriminant = discriminant_expr;
+ (*loc).start = switch_token.loc.start;
+ }
+ Statement::SwitchStatementWithDefault {
+ discriminant, loc, ..
+ } => {
+ *discriminant = discriminant_expr;
+ (*loc).start = switch_token.loc.start;
+ }
+ _ => {
+ // The grammar ensures that the parser always passes a valid
+ // argument to this method.
+ panic!("invalid argument: argument 2 must be a SwitchStatement");
+ }
+ }
+ cases
+ }
+
+ // CaseBlock : `{` CaseClauses? `}`
+ pub fn case_block(
+ &mut self,
+ open_token: arena::Box<'alloc, Token>,
+ cases: Option<arena::Box<'alloc, arena::Vec<'alloc, SwitchCase<'alloc>>>>,
+ close_token: arena::Box<'alloc, Token>,
+ ) -> Result<'alloc, arena::Box<'alloc, Statement<'alloc>>> {
+ self.check_case_block_binding(open_token.loc.start)?;
+
+ Ok(self.alloc_with(|| Statement::SwitchStatement {
+ // This will be overwritten once the enclosing switch statement
+ // gets parsed.
+ discriminant: self.alloc_with(|| Expression::LiteralNullExpression {
+ loc: SourceLocation::default(),
+ }),
+ cases: match cases {
+ None => self.new_vec(),
+ Some(boxed) => boxed.unbox(),
+ },
+ // `start` of this will be overwritten once the enclosing switch
+ // statement gets parsed.
+ loc: close_token.loc,
+ }))
+ }
+
+ // CaseBlock : `{` CaseClauses DefaultClause CaseClauses `}`
+ pub fn case_block_with_default(
+ &mut self,
+ open_token: arena::Box<'alloc, Token>,
+ pre_default_cases: Option<arena::Box<'alloc, arena::Vec<'alloc, SwitchCase<'alloc>>>>,
+ default_case: arena::Box<'alloc, SwitchDefault<'alloc>>,
+ post_default_cases: Option<arena::Box<'alloc, arena::Vec<'alloc, SwitchCase<'alloc>>>>,
+ close_token: arena::Box<'alloc, Token>,
+ ) -> Result<'alloc, arena::Box<'alloc, Statement<'alloc>>> {
+ self.check_case_block_binding(open_token.loc.start)?;
+
+ Ok(self.alloc_with(|| Statement::SwitchStatementWithDefault {
+ // This will be overwritten once the enclosing switch statement
+ // gets parsed.
+ discriminant: self.alloc_with(|| Expression::LiteralNullExpression {
+ loc: SourceLocation::default(),
+ }),
+ pre_default_cases: match pre_default_cases {
+ None => self.new_vec(),
+ Some(boxed) => boxed.unbox(),
+ },
+ default_case: default_case.unbox(),
+ post_default_cases: match post_default_cases {
+ None => self.new_vec(),
+ Some(boxed) => boxed.unbox(),
+ },
+ // `start` of this will be overwritten once the enclosing switch
+ // statement gets parsed.
+ loc: close_token.loc,
+ }))
+ }
+
+ // CaseClauses : CaseClause
+ pub fn case_clauses_single(
+ &self,
+ case: arena::Box<'alloc, SwitchCase<'alloc>>,
+ ) -> arena::Box<'alloc, arena::Vec<'alloc, SwitchCase<'alloc>>> {
+ self.alloc_with(|| self.new_vec_single(case.unbox()))
+ }
+
+ // CaseClauses : CaseClauses CaseClause
+ pub fn case_clauses_append(
+ &self,
+ mut cases: arena::Box<'alloc, arena::Vec<'alloc, SwitchCase<'alloc>>>,
+ case: arena::Box<'alloc, SwitchCase<'alloc>>,
+ ) -> arena::Box<'alloc, arena::Vec<'alloc, SwitchCase<'alloc>>> {
+ self.push(&mut cases, case.unbox());
+ cases
+ }
+
+ // CaseClause : `case` Expression `:` StatementList
+ pub fn case_clause(
+ &self,
+ case_token: arena::Box<'alloc, Token>,
+ expression: arena::Box<'alloc, Expression<'alloc>>,
+ colon_token: arena::Box<'alloc, Token>,
+ statements: Option<arena::Box<'alloc, arena::Vec<'alloc, Statement<'alloc>>>>,
+ ) -> arena::Box<'alloc, SwitchCase<'alloc>> {
+ let case_loc = case_token.loc;
+ if let Some(statements) = statements {
+ let statement_loc = statements
+ .last()
+ .expect("There should be at least one statement")
+ .get_loc();
+
+ self.alloc_with(|| SwitchCase {
+ test: expression,
+ consequent: statements.unbox(),
+ loc: SourceLocation::from_parts(case_loc, statement_loc),
+ })
+ } else {
+ self.alloc_with(|| SwitchCase {
+ test: expression,
+ consequent: self.new_vec(),
+ loc: SourceLocation::from_parts(case_loc, colon_token.loc),
+ })
+ }
+ }
+
+ // DefaultClause : `default` `:` StatementList
+ pub fn default_clause(
+ &self,
+ default_token: arena::Box<'alloc, Token>,
+ colon_token: arena::Box<'alloc, Token>,
+ statements: Option<arena::Box<'alloc, arena::Vec<'alloc, Statement<'alloc>>>>,
+ ) -> arena::Box<'alloc, SwitchDefault<'alloc>> {
+ let default_loc = default_token.loc;
+ if let Some(statements) = statements {
+ let statement_loc = statements
+ .last()
+ .expect("There should be at least one statement")
+ .get_loc();
+
+ self.alloc_with(|| SwitchDefault {
+ consequent: statements.unbox(),
+ loc: SourceLocation::from_parts(default_loc, statement_loc),
+ })
+ } else {
+ self.alloc_with(|| SwitchDefault {
+ consequent: self.new_vec(),
+ loc: SourceLocation::from_parts(default_loc, colon_token.loc),
+ })
+ }
+ }
+
+ // LabelledStatement : LabelIdentifier `:` LabelledItem
+ pub fn labelled_statement(
+ &mut self,
+ label: arena::Box<'alloc, Label>,
+ body: arena::Box<'alloc, Statement<'alloc>>,
+ ) -> Result<'alloc, arena::Box<'alloc, Statement<'alloc>>> {
+ let label_loc = label.loc;
+ let body_loc = body.get_loc();
+ self.mark_labelled_statement(&label, &body);
+ self.check_labelled_statement(label.value, label_loc.start, body_loc.start)?;
+ Ok(self.alloc_with(|| Statement::LabelledStatement {
+ label: label.unbox(),
+ body,
+ loc: SourceLocation::from_parts(label_loc, body_loc),
+ }))
+ }
+
+ // ThrowStatement : `throw` Expression `;`
+ pub fn throw_statement(
+ &self,
+ throw_token: arena::Box<'alloc, Token>,
+ expression: arena::Box<'alloc, Expression<'alloc>>,
+ ) -> arena::Box<'alloc, Statement<'alloc>> {
+ let expression_loc = expression.get_loc();
+ self.alloc_with(|| Statement::ThrowStatement {
+ expression,
+ loc: SourceLocation::from_parts(throw_token.loc, expression_loc),
+ })
+ }
+
+ // TryStatement : `try` Block Catch
+ // TryStatement : `try` Block Finally
+ // TryStatement : `try` Block Catch Finally
+ pub fn try_statement(
+ &self,
+ try_token: arena::Box<'alloc, Token>,
+ body: arena::Box<'alloc, Block<'alloc>>,
+ catch_clause: Option<arena::Box<'alloc, CatchClause<'alloc>>>,
+ finally_block: Option<arena::Box<'alloc, Block<'alloc>>>,
+ ) -> arena::Box<'alloc, Statement<'alloc>> {
+ let try_loc = try_token.loc;
+ match (catch_clause, finally_block) {
+ (Some(catch_clause), None) => {
+ let catch_clause_loc = catch_clause.loc;
+ self.alloc_with(|| Statement::TryCatchStatement {
+ body: body.unbox(),
+ catch_clause: catch_clause.unbox(),
+ loc: SourceLocation::from_parts(try_loc, catch_clause_loc),
+ })
+ }
+ (catch_clause, Some(finally_block)) => {
+ let finally_block_loc = finally_block.loc;
+ self.alloc_with(|| Statement::TryFinallyStatement {
+ body: body.unbox(),
+ catch_clause: catch_clause.map(|boxed| boxed.unbox()),
+ finalizer: finally_block.unbox(),
+ loc: SourceLocation::from_parts(try_loc, finally_block_loc),
+ })
+ }
+ _ => {
+ // The grammar won't accept a bare try-block, so the parser always
+ // a catch clause, a finally block, or both.
+ panic!("invalid argument: try_statement requires a catch or finally block");
+ }
+ }
+ }
+
+ // Catch : `catch` `(` CatchParameter `)` Block
+ pub fn catch(
+ &mut self,
+ catch_token: arena::Box<'alloc, Token>,
+ binding: arena::Box<'alloc, Binding<'alloc>>,
+ body: arena::Box<'alloc, Block<'alloc>>,
+ ) -> Result<'alloc, arena::Box<'alloc, CatchClause<'alloc>>> {
+ let catch_loc = catch_token.loc;
+ let body_loc = body.loc;
+
+ let is_simple = match &*binding {
+ Binding::BindingIdentifier(_) => true,
+ _ => false,
+ };
+
+ let bindings_loc = &binding.get_loc();
+ self.check_catch_bindings(is_simple, bindings_loc.start, bindings_loc.end)?;
+
+ Ok(self.alloc_with(|| CatchClause {
+ binding: Some(binding),
+ body: body.unbox(),
+ loc: SourceLocation::from_parts(catch_loc, body_loc),
+ }))
+ }
+
+ // Catch : `catch` `(` CatchParameter `)` Block
+ pub fn catch_no_param(
+ &mut self,
+ catch_token: arena::Box<'alloc, Token>,
+ body: arena::Box<'alloc, Block<'alloc>>,
+ ) -> Result<'alloc, arena::Box<'alloc, CatchClause<'alloc>>> {
+ let catch_loc = catch_token.loc;
+ let body_loc = body.loc;
+
+ self.check_catch_no_param_bindings(catch_loc.start)?;
+
+ Ok(self.alloc_with(|| CatchClause {
+ binding: None,
+ body: body.unbox(),
+ loc: SourceLocation::from_parts(catch_loc, body_loc),
+ }))
+ }
+
+ // DebuggerStatement : `debugger` `;`
+ pub fn debugger_statement(
+ &self,
+ token: arena::Box<'alloc, Token>,
+ ) -> arena::Box<'alloc, Statement<'alloc>> {
+ self.alloc_with(|| Statement::DebuggerStatement { loc: token.loc })
+ }
+
+ pub fn function_decl(&mut self, f: Function<'alloc>) -> arena::Box<'alloc, Statement<'alloc>> {
+ self.context_metadata
+ .mark_binding_kind(f.loc.start, None, BindingKind::Function);
+
+ self.alloc_with(|| Statement::FunctionDeclaration(f))
+ }
+
+ pub fn async_or_generator_decl(
+ &mut self,
+ f: Function<'alloc>,
+ ) -> arena::Box<'alloc, Statement<'alloc>> {
+ self.context_metadata
+ .mark_binding_kind(f.loc.start, None, BindingKind::AsyncOrGenerator);
+
+ self.alloc_with(|| Statement::FunctionDeclaration(f))
+ }
+
+ pub fn function_expr(&mut self, f: Function<'alloc>) -> arena::Box<'alloc, Expression<'alloc>> {
+ let index = self.context_metadata.find_first_binding(f.loc.start);
+ self.context_metadata.pop_bindings_from(index);
+
+ let label_index = self.context_metadata.find_first_label(f.loc.start);
+ self.context_metadata.pop_labels_from(label_index);
+
+ self.alloc_with(|| Expression::FunctionExpression(f))
+ }
+
+ // FunctionDeclaration : `function` BindingIdentifier `(` FormalParameters `)` `{` FunctionBody `}`
+ // FunctionDeclaration : [+Default] `function` `(` FormalParameters `)` `{` FunctionBody `}`
+ // FunctionExpression : `function` BindingIdentifier? `(` FormalParameters `)` `{` FunctionBody `}`
+ pub fn function(
+ &mut self,
+ function_token: arena::Box<'alloc, Token>,
+ name: Option<arena::Box<'alloc, BindingIdentifier>>,
+ param_open_token: arena::Box<'alloc, Token>,
+ mut params: arena::Box<'alloc, FormalParameters<'alloc>>,
+ param_close_token: arena::Box<'alloc, Token>,
+ body_open_token: arena::Box<'alloc, Token>,
+ mut body: arena::Box<'alloc, FunctionBody<'alloc>>,
+ body_close_token: arena::Box<'alloc, Token>,
+ ) -> Result<'alloc, Function<'alloc>> {
+ let param_open_loc = param_open_token.loc;
+ let param_close_loc = param_close_token.loc;
+ let body_close_loc = body_close_token.loc;
+
+ let is_simple = Self::is_params_simple(&params);
+ self.check_function_bindings(is_simple, param_open_loc.start, param_close_loc.end)?;
+
+ params.loc.set_range(param_open_loc, param_close_loc);
+ body.loc.set_range(body_open_token.loc, body_close_loc);
+
+ Ok(Function {
+ name: name.map(|b| b.unbox()),
+ is_async: false,
+ is_generator: false,
+ params: params.unbox(),
+ body: body.unbox(),
+ loc: SourceLocation::from_parts(function_token.loc, body_close_loc),
+ })
+ }
+
+ // AsyncFunctionDeclaration : `async` `function` BindingIdentifier `(` FormalParameters `)` `{` AsyncFunctionBody `}`
+ // AsyncFunctionDeclaration : [+Default] `async` `function` `(` FormalParameters `)` `{` AsyncFunctionBody `}`
+ // AsyncFunctionExpression : `async` `function` `(` FormalParameters `)` `{` AsyncFunctionBody `}`
+ pub fn async_function(
+ &mut self,
+ async_token: arena::Box<'alloc, Token>,
+ name: Option<arena::Box<'alloc, BindingIdentifier>>,
+ param_open_token: arena::Box<'alloc, Token>,
+ mut params: arena::Box<'alloc, FormalParameters<'alloc>>,
+ param_close_token: arena::Box<'alloc, Token>,
+ body_open_token: arena::Box<'alloc, Token>,
+ mut body: arena::Box<'alloc, FunctionBody<'alloc>>,
+ body_close_token: arena::Box<'alloc, Token>,
+ ) -> Result<'alloc, Function<'alloc>> {
+ let param_open_loc = param_open_token.loc;
+ let param_close_loc = param_close_token.loc;
+ let body_close_loc = body_close_token.loc;
+
+ let is_simple = Self::is_params_simple(&params);
+ self.check_function_bindings(is_simple, param_open_loc.start, param_close_loc.end)?;
+
+ params.loc.set_range(param_open_loc, param_close_loc);
+ body.loc.set_range(body_open_token.loc, body_close_loc);
+
+ Ok(Function {
+ name: name.map(|b| b.unbox()),
+ is_async: true,
+ is_generator: false,
+ params: params.unbox(),
+ body: body.unbox(),
+ loc: SourceLocation::from_parts(async_token.loc, body_close_loc),
+ })
+ }
+
+ // GeneratorDeclaration : `function` `*` BindingIdentifier `(` FormalParameters `)` `{` GeneratorBody `}`
+ // GeneratorDeclaration : [+Default] `function` `*` `(` FormalParameters `)` `{` GeneratorBody `}`
+ // GeneratorExpression : `function` `*` BindingIdentifier? `(` FormalParameters `)` `{` GeneratorBody `}`
+ pub fn generator(
+ &mut self,
+ function_token: arena::Box<'alloc, Token>,
+ name: Option<arena::Box<'alloc, BindingIdentifier>>,
+ param_open_token: arena::Box<'alloc, Token>,
+ mut params: arena::Box<'alloc, FormalParameters<'alloc>>,
+ param_close_token: arena::Box<'alloc, Token>,
+ body_open_token: arena::Box<'alloc, Token>,
+ mut body: arena::Box<'alloc, FunctionBody<'alloc>>,
+ body_close_token: arena::Box<'alloc, Token>,
+ ) -> Result<'alloc, Function<'alloc>> {
+ let param_open_loc = param_open_token.loc;
+ let param_close_loc = param_close_token.loc;
+ let body_close_loc = body_close_token.loc;
+
+ let is_simple = Self::is_params_simple(&params);
+ self.check_function_bindings(is_simple, param_open_loc.start, param_close_loc.end)?;
+
+ params.loc.set_range(param_open_loc, param_close_loc);
+ body.loc.set_range(body_open_token.loc, body_close_loc);
+
+ Ok(Function {
+ name: name.map(|b| b.unbox()),
+ is_async: false,
+ is_generator: true,
+ params: params.unbox(),
+ body: body.unbox(),
+ loc: SourceLocation::from_parts(function_token.loc, body_close_loc),
+ })
+ }
+
+ // AsyncGeneratorDeclaration : `async` `function` `*` BindingIdentifier `(` FormalParameters `)` `{` AsyncGeneratorBody `}`
+ // AsyncGeneratorDeclaration : [+Default] `async` `function` `*` `(` FormalParameters `)` `{` AsyncGeneratorBody `}`
+ // AsyncGeneratorExpression : `async` `function` `*` BindingIdentifier? `(` FormalParameters `)` `{` AsyncGeneratorBody `}`
+ pub fn async_generator(
+ &mut self,
+ async_token: arena::Box<'alloc, Token>,
+ name: Option<arena::Box<'alloc, BindingIdentifier>>,
+ param_open_token: arena::Box<'alloc, Token>,
+ mut params: arena::Box<'alloc, FormalParameters<'alloc>>,
+ param_close_token: arena::Box<'alloc, Token>,
+ body_open_token: arena::Box<'alloc, Token>,
+ mut body: arena::Box<'alloc, FunctionBody<'alloc>>,
+ body_close_token: arena::Box<'alloc, Token>,
+ ) -> Result<'alloc, Function<'alloc>> {
+ let param_open_loc = param_open_token.loc;
+ let param_close_loc = param_close_token.loc;
+ let body_close_loc = body_close_token.loc;
+
+ let is_simple = Self::is_params_simple(&params);
+ self.check_function_bindings(is_simple, param_open_loc.start, param_close_loc.end)?;
+
+ params.loc.set_range(param_open_loc, param_close_loc);
+ body.loc.set_range(body_open_token.loc, body_close_loc);
+
+ Ok(Function {
+ name: name.map(|b| b.unbox()),
+ is_async: true,
+ is_generator: true,
+ params: params.unbox(),
+ body: body.unbox(),
+ loc: SourceLocation::from_parts(async_token.loc, body_close_loc),
+ })
+ }
+
+ // UniqueFormalParameters : FormalParameters
+ pub fn unique_formal_parameters(
+ &self,
+ parameters: arena::Box<'alloc, FormalParameters<'alloc>>,
+ ) -> arena::Box<'alloc, FormalParameters<'alloc>> {
+ parameters
+ }
+
+ // FormalParameters : [empty]
+ pub fn empty_formal_parameters(&self) -> arena::Box<'alloc, FormalParameters<'alloc>> {
+ self.alloc_with(|| FormalParameters {
+ items: self.new_vec(),
+ rest: None,
+ // This will be overwritten once the enclosing function gets parsed.
+ loc: SourceLocation::default(),
+ })
+ }
+
+ // FormalParameters : FunctionRestParameter
+ // FormalParameters : FormalParameterList `,` FunctionRestParameter
+ pub fn with_rest_parameter(
+ &self,
+ mut params: arena::Box<'alloc, FormalParameters<'alloc>>,
+ rest: arena::Box<'alloc, Binding<'alloc>>,
+ ) -> arena::Box<'alloc, FormalParameters<'alloc>> {
+ params.rest = Some(rest.unbox());
+ params
+ }
+
+ // FormalParameterList : FormalParameter
+ pub fn formal_parameter_list_single(
+ &self,
+ parameter: arena::Box<'alloc, Parameter<'alloc>>,
+ ) -> arena::Box<'alloc, FormalParameters<'alloc>> {
+ self.alloc_with(|| FormalParameters {
+ items: self.new_vec_single(parameter.unbox()),
+ rest: None,
+ // This will be overwritten once the enclosing function gets parsed.
+ loc: SourceLocation::default(),
+ })
+ }
+
+ // FormalParameterList : FormalParameterList "," FormalParameter
+ pub fn formal_parameter_list_append(
+ &self,
+ mut params: arena::Box<'alloc, FormalParameters<'alloc>>,
+ next_param: arena::Box<'alloc, Parameter<'alloc>>,
+ ) -> arena::Box<'alloc, FormalParameters<'alloc>> {
+ self.push(&mut params.items, next_param.unbox());
+ params
+ }
+
+ // FunctionBody : FunctionStatementList
+ pub fn function_body(
+ &self,
+ statements: arena::Box<'alloc, arena::Vec<'alloc, Statement<'alloc>>>,
+ ) -> arena::Box<'alloc, FunctionBody<'alloc>> {
+ // TODO: Directives
+ self.alloc_with(|| FunctionBody {
+ directives: self.new_vec(),
+ statements: statements.unbox(),
+ // This will be overwritten once the enclosing function gets parsed.
+ loc: SourceLocation::default(),
+ })
+ }
+
+ // FunctionStatementList : StatementList?
+ pub fn function_statement_list(
+ &self,
+ statements: Option<arena::Box<'alloc, arena::Vec<'alloc, Statement<'alloc>>>>,
+ ) -> arena::Box<'alloc, arena::Vec<'alloc, Statement<'alloc>>> {
+ match statements {
+ Some(statements) => statements,
+ None => self.alloc_with(|| self.new_vec()),
+ }
+ }
+
+ // ArrowFunction : ArrowParameters `=>` ConciseBody
+ pub fn arrow_function(
+ &mut self,
+ params: arena::Box<'alloc, FormalParameters<'alloc>>,
+ body: arena::Box<'alloc, ArrowExpressionBody<'alloc>>,
+ ) -> Result<'alloc, arena::Box<'alloc, Expression<'alloc>>> {
+ self.check_unique_function_bindings(params.loc.start, params.loc.end)?;
+
+ let params_loc = params.loc;
+ let body_loc = body.get_loc();
+
+ Ok(self.alloc_with(|| Expression::ArrowExpression {
+ is_async: false,
+ params: params.unbox(),
+ body: body.unbox(),
+ loc: SourceLocation::from_parts(params_loc, body_loc),
+ }))
+ }
+
+ // ArrowParameters : BindingIdentifier
+ pub fn arrow_parameters_bare(
+ &mut self,
+ identifier: arena::Box<'alloc, BindingIdentifier>,
+ ) -> arena::Box<'alloc, FormalParameters<'alloc>> {
+ let loc = identifier.loc;
+ self.alloc_with(|| FormalParameters {
+ items: self.new_vec_single(Parameter::Binding(Binding::BindingIdentifier(
+ identifier.unbox(),
+ ))),
+ rest: None,
+ loc,
+ })
+ }
+
+ // ArrowParameters : CoverParenthesizedExpressionAndArrowParameterList
+ pub fn uncover_arrow_parameters(
+ &self,
+ covered: arena::Box<'alloc, CoverParenthesized<'alloc>>,
+ ) -> Result<'alloc, arena::Box<'alloc, FormalParameters<'alloc>>> {
+ Ok(match covered.unbox() {
+ CoverParenthesized::Expression { expression, loc } => self.alloc(FormalParameters {
+ items: self.expression_to_parameter_list(expression)?,
+ rest: None,
+ loc,
+ }),
+ CoverParenthesized::Parameters(parameters) => parameters,
+ })
+ }
+
+ // ConciseBody : [lookahead != `{`] AssignmentExpression
+ pub fn concise_body_expression(
+ &self,
+ expression: arena::Box<'alloc, Expression<'alloc>>,
+ ) -> arena::Box<'alloc, ArrowExpressionBody<'alloc>> {
+ self.alloc_with(|| ArrowExpressionBody::Expression(expression))
+ }
+
+ // ConciseBody : `{` FunctionBody `}`
+ pub fn concise_body_block(
+ &self,
+ body_open_token: arena::Box<'alloc, Token>,
+ mut body: arena::Box<'alloc, FunctionBody<'alloc>>,
+ body_close_token: arena::Box<'alloc, Token>,
+ ) -> arena::Box<'alloc, ArrowExpressionBody<'alloc>> {
+ body.loc
+ .set_range(body_open_token.loc, body_close_token.loc);
+ self.alloc_with(|| ArrowExpressionBody::FunctionBody(body.unbox()))
+ }
+
+ // MethodDefinition : ClassElementName `(` UniqueFormalParameters `)` `{` FunctionBody `}`
+ pub fn method_definition(
+ &mut self,
+ name: arena::Box<'alloc, ClassElementName<'alloc>>,
+ param_open_token: arena::Box<'alloc, Token>,
+ mut params: arena::Box<'alloc, FormalParameters<'alloc>>,
+ param_close_token: arena::Box<'alloc, Token>,
+ body_open_token: arena::Box<'alloc, Token>,
+ mut body: arena::Box<'alloc, FunctionBody<'alloc>>,
+ body_close_token: arena::Box<'alloc, Token>,
+ ) -> Result<'alloc, arena::Box<'alloc, MethodDefinition<'alloc>>> {
+ let name_loc = name.get_loc();
+ let param_open_loc = param_open_token.loc;
+ let param_close_loc = param_close_token.loc;
+ let body_close_loc = body_close_token.loc;
+
+ self.check_unique_function_bindings(param_open_loc.start, param_close_loc.end)?;
+
+ params.loc.set_range(param_open_loc, param_close_loc);
+ body.loc.set_range(body_open_token.loc, body_close_loc);
+
+ Ok(self.alloc_with(|| {
+ MethodDefinition::Method(Method {
+ name: name.unbox(),
+ is_async: false,
+ is_generator: false,
+ params: params.unbox(),
+ body: body.unbox(),
+ loc: SourceLocation::from_parts(name_loc, body_close_loc),
+ })
+ }))
+ }
+
+ // MethodDefinition : `get` ClassElementName `(` `)` `{` FunctionBody `}`
+ pub fn getter(
+ &self,
+ get_token: arena::Box<'alloc, Token>,
+ name: arena::Box<'alloc, ClassElementName<'alloc>>,
+ body_open_token: arena::Box<'alloc, Token>,
+ mut body: arena::Box<'alloc, FunctionBody<'alloc>>,
+ body_close_token: arena::Box<'alloc, Token>,
+ ) -> arena::Box<'alloc, MethodDefinition<'alloc>> {
+ let body_close_loc = body_close_token.loc;
+ body.loc.set_range(body_open_token.loc, body_close_loc);
+ self.alloc_with(|| {
+ MethodDefinition::Getter(Getter {
+ property_name: name.unbox(),
+ body: body.unbox(),
+ loc: SourceLocation::from_parts(get_token.loc, body_close_loc),
+ })
+ })
+ }
+
+ // MethodDefinition : `set` ClassElementName `(` PropertySetParameterList `)` `{` FunctionBody `}`
+ pub fn setter(
+ &mut self,
+ set_token: arena::Box<'alloc, Token>,
+ name: arena::Box<'alloc, ClassElementName<'alloc>>,
+ param_open_token: arena::Box<'alloc, Token>,
+ mut parameter: arena::Box<'alloc, Parameter<'alloc>>,
+ param_close_token: arena::Box<'alloc, Token>,
+ body_open_token: arena::Box<'alloc, Token>,
+ mut body: arena::Box<'alloc, FunctionBody<'alloc>>,
+ body_close_token: arena::Box<'alloc, Token>,
+ ) -> Result<'alloc, arena::Box<'alloc, MethodDefinition<'alloc>>> {
+ let param_open_loc = param_open_token.loc;
+ let param_close_loc = param_close_token.loc;
+ let body_close_loc = body_close_token.loc;
+
+ // A setter only has one parameter, but it can be a destructuring
+ // pattern, so it is still possible to flunk this check.
+ self.check_unique_function_bindings(param_open_loc.start, param_close_loc.end)?;
+
+ parameter.set_loc(param_open_loc, param_close_loc);
+ body.loc.set_range(body_open_token.loc, body_close_loc);
+ Ok(self.alloc_with(|| {
+ MethodDefinition::Setter(Setter {
+ property_name: name.unbox(),
+ param: parameter.unbox(),
+ body: body.unbox(),
+ loc: SourceLocation::from_parts(set_token.loc, body_close_loc),
+ })
+ }))
+ }
+
+ // GeneratorMethod : `*` ClassElementName `(` UniqueFormalParameters `)` `{` GeneratorBody `}`
+ pub fn generator_method(
+ &mut self,
+ generator_token: arena::Box<'alloc, Token>,
+ name: arena::Box<'alloc, ClassElementName<'alloc>>,
+ param_open_token: arena::Box<'alloc, Token>,
+ mut params: arena::Box<'alloc, FormalParameters<'alloc>>,
+ param_close_token: arena::Box<'alloc, Token>,
+ body_open_token: arena::Box<'alloc, Token>,
+ mut body: arena::Box<'alloc, FunctionBody<'alloc>>,
+ body_close_token: arena::Box<'alloc, Token>,
+ ) -> Result<'alloc, arena::Box<'alloc, MethodDefinition<'alloc>>> {
+ let param_open_loc = param_open_token.loc;
+ let param_close_loc = param_close_token.loc;
+ let body_close_loc = body_close_token.loc;
+
+ self.check_unique_function_bindings(param_open_loc.start, param_close_loc.end)?;
+
+ params.loc.set_range(param_open_loc, param_close_loc);
+ body.loc.set_range(body_open_token.loc, body_close_loc);
+
+ Ok(self.alloc_with(|| {
+ MethodDefinition::Method(Method {
+ name: name.unbox(),
+ is_async: false,
+ is_generator: true,
+ params: params.unbox(),
+ body: body.unbox(),
+ loc: SourceLocation::from_parts(generator_token.loc, body_close_loc),
+ })
+ }))
+ }
+
+ // YieldExpression : `yield`
+ // YieldExpression : `yield` AssignmentExpression
+ pub fn yield_expr(
+ &self,
+ yield_token: arena::Box<'alloc, Token>,
+ operand: Option<arena::Box<'alloc, Expression<'alloc>>>,
+ ) -> arena::Box<'alloc, Expression<'alloc>> {
+ let yield_loc = yield_token.loc;
+ let loc = match operand {
+ Some(ref operand) => SourceLocation::from_parts(yield_loc, operand.get_loc()),
+ None => yield_loc,
+ };
+
+ self.alloc_with(|| Expression::YieldExpression {
+ expression: operand,
+ loc,
+ })
+ }
+
+ // YieldExpression : `yield` `*` AssignmentExpression
+ pub fn yield_star_expr(
+ &self,
+ yield_token: arena::Box<'alloc, Token>,
+ operand: arena::Box<'alloc, Expression<'alloc>>,
+ ) -> arena::Box<'alloc, Expression<'alloc>> {
+ let yield_loc = yield_token.loc;
+ let operand_loc = operand.get_loc();
+ self.alloc_with(|| Expression::YieldGeneratorExpression {
+ expression: operand,
+ loc: SourceLocation::from_parts(yield_loc, operand_loc),
+ })
+ }
+
+ // AsyncGeneratorMethod ::= "async" "*" ClassElementName "(" UniqueFormalParameters ")" "{" AsyncGeneratorBody "}"
+ pub fn async_generator_method(
+ &mut self,
+ async_token: arena::Box<'alloc, Token>,
+ name: arena::Box<'alloc, ClassElementName<'alloc>>,
+ param_open_token: arena::Box<'alloc, Token>,
+ mut params: arena::Box<'alloc, FormalParameters<'alloc>>,
+ param_close_token: arena::Box<'alloc, Token>,
+ body_open_token: arena::Box<'alloc, Token>,
+ mut body: arena::Box<'alloc, FunctionBody<'alloc>>,
+ body_close_token: arena::Box<'alloc, Token>,
+ ) -> Result<'alloc, arena::Box<'alloc, MethodDefinition<'alloc>>> {
+ let param_open_loc = param_open_token.loc;
+ let param_close_loc = param_close_token.loc;
+ let body_close_loc = body_close_token.loc;
+
+ self.check_unique_function_bindings(param_open_loc.start, param_close_loc.end)?;
+
+ params.loc.set_range(param_open_loc, param_close_loc);
+ body.loc.set_range(body_open_token.loc, body_close_loc);
+
+ Ok(self.alloc_with(|| {
+ MethodDefinition::Method(Method {
+ name: name.unbox(),
+ is_async: true,
+ is_generator: true,
+ params: params.unbox(),
+ body: body.unbox(),
+ loc: SourceLocation::from_parts(async_token.loc, body_close_loc),
+ })
+ }))
+ }
+
+ // ClassDeclaration : `class` BindingIdentifier ClassTail
+ // ClassDeclaration : `class` ClassTail
+ pub fn class_declaration(
+ &mut self,
+ class_token: arena::Box<'alloc, Token>,
+ name: Option<arena::Box<'alloc, BindingIdentifier>>,
+ tail: arena::Box<'alloc, ClassExpression<'alloc>>,
+ ) -> arena::Box<'alloc, Statement<'alloc>> {
+ let class_loc = class_token.loc;
+
+ self.context_metadata
+ .mark_binding_kind(class_loc.start, None, BindingKind::Class);
+
+ let tail = tail.unbox();
+ let tail_loc = tail.loc;
+ self.alloc_with(|| {
+ Statement::ClassDeclaration(ClassDeclaration {
+ name: match name {
+ None => {
+ let loc = SourceLocation::new(class_loc.end, class_loc.end);
+ BindingIdentifier {
+ name: Identifier {
+ value: CommonSourceAtomSetIndices::default(),
+ loc,
+ },
+ loc,
+ }
+ }
+ Some(bi) => bi.unbox(),
+ },
+ super_: tail.super_,
+ elements: tail.elements,
+ loc: SourceLocation::from_parts(class_loc, tail_loc),
+ })
+ })
+ }
+
+ // ClassExpression : `class` BindingIdentifier? ClassTail
+ pub fn class_expression(
+ &mut self,
+ class_token: arena::Box<'alloc, Token>,
+ name: Option<arena::Box<'alloc, BindingIdentifier>>,
+ mut tail: arena::Box<'alloc, ClassExpression<'alloc>>,
+ ) -> arena::Box<'alloc, Expression<'alloc>> {
+ let offset = class_token.loc.start;
+ let index = self.context_metadata.find_first_binding(offset);
+ self.context_metadata.pop_bindings_from(index);
+
+ tail.name = name.map(|boxed| boxed.unbox());
+ tail.loc.start = class_token.loc.start;
+ self.alloc_with(|| Expression::ClassExpression(tail.unbox()))
+ }
+
+ // ClassTail : ClassHeritage? `{` ClassBody? `}`
+ pub fn class_tail(
+ &self,
+ heritage: Option<arena::Box<'alloc, Expression<'alloc>>>,
+ body: Option<
+ arena::Box<'alloc, arena::Vec<'alloc, arena::Box<'alloc, ClassElement<'alloc>>>>,
+ >,
+ body_close_token: arena::Box<'alloc, Token>,
+ ) -> arena::Box<'alloc, ClassExpression<'alloc>> {
+ self.alloc_with(|| ClassExpression {
+ name: None,
+ super_: heritage,
+ elements: match body {
+ None => self.new_vec(),
+ Some(boxed) => boxed.unbox(),
+ },
+ // `start` of this will be overwritten once the enclosing class
+ // gets parsed.
+ loc: body_close_token.loc,
+ })
+ }
+
+ // ClassElementList : ClassElementList ClassElement
+ pub fn class_element_list_append(
+ &self,
+ mut list: arena::Box<'alloc, arena::Vec<'alloc, arena::Box<'alloc, ClassElement<'alloc>>>>,
+ mut element: arena::Box<
+ 'alloc,
+ arena::Vec<'alloc, arena::Box<'alloc, ClassElement<'alloc>>>,
+ >,
+ ) -> arena::Box<'alloc, arena::Vec<'alloc, arena::Box<'alloc, ClassElement<'alloc>>>> {
+ self.append(&mut list, &mut element);
+ list
+ }
+
+ // FieldDefinition : ClassElementName Initializer?
+ pub fn class_field_definition(
+ &self,
+ name: arena::Box<'alloc, ClassElementName<'alloc>>,
+ init: Option<arena::Box<'alloc, Expression<'alloc>>>,
+ ) -> arena::Box<'alloc, ClassElement<'alloc>> {
+ let name_loc = name.get_loc();
+ let loc = match &init {
+ None => name_loc,
+ Some(expr) => SourceLocation::from_parts(name_loc, expr.get_loc()),
+ };
+ self.alloc_with(|| ClassElement::FieldDefinition {
+ name: name.unbox(),
+ init,
+ loc,
+ })
+ }
+
+ // ClassElementName : PropertyName
+ pub fn property_name_to_class_element_name(
+ &self,
+ name: arena::Box<'alloc, PropertyName<'alloc>>,
+ ) -> arena::Box<'alloc, ClassElementName<'alloc>> {
+ self.alloc_with(|| match name.unbox() {
+ PropertyName::ComputedPropertyName(cpn) => ClassElementName::ComputedPropertyName(cpn),
+ PropertyName::StaticPropertyName(spn) => ClassElementName::StaticPropertyName(spn),
+ PropertyName::StaticNumericPropertyName(snpn) => {
+ ClassElementName::StaticNumericPropertyName(snpn)
+ }
+ })
+ }
+
+ // ClassElementName : PrivateIdentifier
+ pub fn class_element_name_private(
+ &self,
+ private_identifier: arena::Box<'alloc, Token>,
+ ) -> Result<'alloc, arena::Box<'alloc, ClassElementName<'alloc>>> {
+ let name = self.private_identifier(private_identifier)?;
+ Ok(self.alloc_with(|| ClassElementName::PrivateFieldName(name)))
+ }
+
+ // ClassElement : MethodDefinition
+ pub fn class_element(
+ &self,
+ method: arena::Box<'alloc, MethodDefinition<'alloc>>,
+ ) -> arena::Box<'alloc, arena::Vec<'alloc, arena::Box<'alloc, ClassElement<'alloc>>>> {
+ let loc = method.get_loc();
+ self.class_element_to_vec(self.alloc_with(|| ClassElement::MethodDefinition {
+ is_static: false,
+ method: method.unbox(),
+ loc,
+ }))
+ }
+
+ // ClassElement : FieldDefinition `;`
+ pub fn class_element_to_vec(
+ &self,
+ element: arena::Box<'alloc, ClassElement<'alloc>>,
+ ) -> arena::Box<'alloc, arena::Vec<'alloc, arena::Box<'alloc, ClassElement<'alloc>>>> {
+ self.alloc_with(|| self.new_vec_single(element))
+ }
+
+ // ClassElement : `static` MethodDefinition
+ pub fn class_element_static(
+ &self,
+ static_token: arena::Box<'alloc, Token>,
+ method: arena::Box<'alloc, MethodDefinition<'alloc>>,
+ ) -> arena::Box<'alloc, arena::Vec<'alloc, arena::Box<'alloc, ClassElement<'alloc>>>> {
+ let method_loc = method.get_loc();
+ self.alloc_with(|| {
+ self.new_vec_single(self.alloc_with(|| ClassElement::MethodDefinition {
+ is_static: true,
+ method: method.unbox(),
+ loc: SourceLocation::from_parts(static_token.loc, method_loc),
+ }))
+ })
+ }
+
+ // ClassElement : `static` MethodDefinition
+ pub fn class_element_static_field(
+ &self,
+ _static_token: arena::Box<'alloc, Token>,
+ _field: arena::Box<'alloc, ClassElement<'alloc>>,
+ ) -> Result<'alloc, arena::Box<'alloc, Void>> {
+ Err(ParseError::NotImplemented("class static field").into())
+ }
+
+ // ClassElement : `;`
+ pub fn class_element_empty(
+ &self,
+ ) -> arena::Box<'alloc, arena::Vec<'alloc, arena::Box<'alloc, ClassElement<'alloc>>>> {
+ self.alloc_with(|| self.new_vec())
+ }
+
+ // AsyncMethod : `async` ClassElementName `(` UniqueFormalParameters `)` `{` AsyncFunctionBody `}`
+ pub fn async_method(
+ &mut self,
+ async_token: arena::Box<'alloc, Token>,
+ name: arena::Box<'alloc, ClassElementName<'alloc>>,
+ param_open_token: arena::Box<'alloc, Token>,
+ mut params: arena::Box<'alloc, FormalParameters<'alloc>>,
+ param_close_token: arena::Box<'alloc, Token>,
+ body_open_token: arena::Box<'alloc, Token>,
+ mut body: arena::Box<'alloc, FunctionBody<'alloc>>,
+ body_close_token: arena::Box<'alloc, Token>,
+ ) -> Result<'alloc, arena::Box<'alloc, MethodDefinition<'alloc>>> {
+ let param_open_loc = param_open_token.loc;
+ let param_close_loc = param_close_token.loc;
+ let body_close_loc = body_close_token.loc;
+
+ self.check_unique_function_bindings(param_open_loc.start, param_close_loc.end)?;
+
+ params.loc.set_range(param_open_loc, param_close_loc);
+ body.loc.set_range(body_open_token.loc, body_close_loc);
+
+ Ok(self.alloc_with(|| {
+ MethodDefinition::Method(Method {
+ name: name.unbox(),
+ is_async: true,
+ is_generator: false,
+ params: params.unbox(),
+ body: body.unbox(),
+ loc: SourceLocation::from_parts(async_token.loc, body_close_loc),
+ })
+ }))
+ }
+
+ // AwaitExpression : `await` UnaryExpression
+ pub fn await_expr(
+ &self,
+ await_token: arena::Box<'alloc, Token>,
+ operand: arena::Box<'alloc, Expression<'alloc>>,
+ ) -> arena::Box<'alloc, Expression<'alloc>> {
+ let operand_loc = operand.get_loc();
+ self.alloc_with(|| Expression::AwaitExpression {
+ expression: operand,
+ loc: SourceLocation::from_parts(await_token.loc, operand_loc),
+ })
+ }
+
+ // AsyncArrowFunction : `async` AsyncArrowBindingIdentifier `=>` AsyncConciseBody
+ // AsyncArrowFunction : CoverCallExpressionAndAsyncArrowHead `=>` AsyncConciseBody
+ pub fn async_arrow_function_bare(
+ &mut self,
+ async_token: arena::Box<'alloc, Token>,
+ identifier: arena::Box<'alloc, BindingIdentifier>,
+ body: arena::Box<'alloc, ArrowExpressionBody<'alloc>>,
+ ) -> Result<'alloc, arena::Box<'alloc, Expression<'alloc>>> {
+ let params = self.arrow_parameters_bare(identifier);
+
+ self.check_unique_function_bindings(params.loc.start, params.loc.end)?;
+
+ let body_loc = body.get_loc();
+ Ok(self.alloc_with(|| Expression::ArrowExpression {
+ is_async: true,
+ params: params.unbox(),
+ body: body.unbox(),
+ loc: SourceLocation::from_parts(async_token.loc, body_loc),
+ }))
+ }
+
+ pub fn async_arrow_function(
+ &mut self,
+ params: arena::Box<'alloc, Expression<'alloc>>,
+ body: arena::Box<'alloc, ArrowExpressionBody<'alloc>>,
+ ) -> Result<'alloc, arena::Box<'alloc, Expression<'alloc>>> {
+ let (params, call_loc) = self.async_arrow_parameters(params)?;
+
+ self.check_unique_function_bindings(params.loc.start, params.loc.end)?;
+
+ let body_loc = body.get_loc();
+ Ok(self.alloc_with(|| Expression::ArrowExpression {
+ is_async: true,
+ params: params.unbox(),
+ body: body.unbox(),
+ loc: SourceLocation::from_parts(call_loc, body_loc),
+ }))
+ }
+
+ // AsyncArrowFunction : CoverCallExpressionAndAsyncArrowHead `=>` AsyncConciseBody
+ //
+ // This is used to convert the Expression that is produced by parsing a CoverCallExpressionAndAsyncArrowHead
+ fn async_arrow_parameters(
+ &self,
+ call_expression: arena::Box<'alloc, Expression<'alloc>>,
+ ) -> Result<'alloc, (arena::Box<'alloc, FormalParameters<'alloc>>, SourceLocation)> {
+ match call_expression.unbox() {
+ Expression::CallExpression(CallExpression {
+ callee: ce,
+ arguments,
+ loc,
+ }) => {
+ // Check that `callee` is `async`.
+ match ce {
+ ExpressionOrSuper::Expression(callee) => match callee.unbox() {
+ Expression::IdentifierExpression(IdentifierExpression { name, .. }) => {
+ if name.value != CommonSourceAtomSetIndices::async_() {
+ // `foo(a, b) => {}`
+ return Err(ParseError::ArrowHeadInvalid.into());
+ }
+ }
+ _ => {
+ // `obj.async() => {}`
+ return Err(ParseError::ArrowHeadInvalid.into());
+ }
+ },
+
+ ExpressionOrSuper::Super { .. } => {
+ // Can't happen: `super()` doesn't match
+ // CoverCallExpressionAndAsyncArrowHead.
+ return Err(ParseError::ArrowHeadInvalid.into());
+ }
+ }
+
+ Ok((self.arguments_to_parameter_list(arguments)?, loc))
+ }
+ _ => {
+ // The grammar ensures that the parser always passes
+ // a valid CallExpression to this function.
+ panic!("invalid argument");
+ }
+ }
+ }
+
+ // Script : ScriptBody?
+ pub fn script(
+ &mut self,
+ script: Option<arena::Box<'alloc, Script<'alloc>>>,
+ ) -> Result<'alloc, arena::Box<'alloc, Script<'alloc>>> {
+ self.check_script_bindings()?;
+
+ Ok(match script {
+ Some(script) => script,
+ None => self.alloc_with(|| Script {
+ directives: self.new_vec(),
+ statements: self.new_vec(),
+ loc: SourceLocation::default(),
+ }),
+ })
+ }
+
+ // ScriptBody : StatementList
+ pub fn script_body(
+ &self,
+ statements: arena::Box<'alloc, arena::Vec<'alloc, Statement<'alloc>>>,
+ ) -> arena::Box<'alloc, Script<'alloc>> {
+ let loc = if statements.is_empty() {
+ SourceLocation::default()
+ } else {
+ SourceLocation::from_parts(
+ statements.first().unwrap().get_loc(),
+ statements.last().unwrap().get_loc(),
+ )
+ };
+
+ // TODO: directives
+ self.alloc_with(|| Script {
+ directives: self.new_vec(),
+ statements: statements.unbox(),
+ loc,
+ })
+ }
+
+ // Module : ModuleBody?
+ pub fn module(
+ &mut self,
+ body: Option<arena::Box<'alloc, arena::Vec<'alloc, Statement<'alloc>>>>,
+ ) -> Result<'alloc, arena::Box<'alloc, arena::Vec<'alloc, Statement<'alloc>>>> {
+ self.check_module_bindings()?;
+
+ Ok(body.unwrap_or_else(|| self.alloc_with(|| self.new_vec())))
+ }
+
+ // ModuleItemList : ModuleItem
+ pub fn module_item_list_single(
+ &self,
+ item: arena::Box<'alloc, Statement<'alloc>>,
+ ) -> arena::Box<'alloc, arena::Vec<'alloc, Statement<'alloc>>> {
+ self.alloc_with(|| self.new_vec_single(item.unbox()))
+ }
+
+ // ModuleItemList : ModuleItemList ModuleItem
+ pub fn module_item_list_append(
+ &self,
+ mut list: arena::Box<'alloc, arena::Vec<'alloc, Statement<'alloc>>>,
+ item: arena::Box<'alloc, Statement<'alloc>>,
+ ) -> arena::Box<'alloc, arena::Vec<'alloc, Statement<'alloc>>> {
+ self.push(&mut list, item.unbox());
+ list
+ }
+
+ // ImportDeclaration : `import` ImportClause FromClause `;`
+ // ImportDeclaration : `import` ModuleSpecifier `;`
+ pub fn import_declaration(
+ &self,
+ _import_clause: Option<arena::Box<'alloc, Void>>,
+ _module_specifier: arena::Box<'alloc, Token>,
+ ) -> Result<'alloc, arena::Box<'alloc, Void>> {
+ Err(ParseError::NotImplemented("import").into())
+ }
+
+ // ImportClause : ImportedDefaultBinding
+ // ImportClause : NameSpaceImport
+ // ImportClause : NamedImports
+ // ImportClause : ImportedDefaultBinding `,` NameSpaceImport
+ // ImportClause : ImportedDefaultBinding `,` NamedImports
+ pub fn import_clause(
+ &self,
+ _default_binding: Option<arena::Box<'alloc, BindingIdentifier>>,
+ _name_space_import: Option<arena::Box<'alloc, Void>>,
+ _named_imports: Option<arena::Box<'alloc, Void>>,
+ ) -> Result<'alloc, arena::Box<'alloc, Void>> {
+ Err(ParseError::NotImplemented("import").into())
+ }
+
+ // NameSpaceImport : `*` `as` ImportedBinding
+ pub fn name_space_import(
+ &self,
+ _name: arena::Box<'alloc, BindingIdentifier>,
+ ) -> Result<'alloc, arena::Box<'alloc, Void>> {
+ Err(ParseError::NotImplemented("import").into())
+ }
+
+ // NamedImports : `{` `}`
+ pub fn imports_list_empty(&self) -> Result<'alloc, arena::Box<'alloc, Void>> {
+ Err(ParseError::NotImplemented("import").into())
+ }
+
+ // ImportsList : ImportSpecifier
+ // ImportsList : ImportsList `,` ImportSpecifier
+ pub fn imports_list_append(
+ &self,
+ _list: arena::Box<'alloc, Void>,
+ _item: arena::Box<'alloc, Void>,
+ ) -> Result<'alloc, arena::Box<'alloc, Void>> {
+ Err(ParseError::NotImplemented("import").into())
+ }
+
+ // ImportSpecifier : ImportedBinding
+ pub fn import_specifier(
+ &self,
+ _name: arena::Box<'alloc, BindingIdentifier>,
+ ) -> Result<'alloc, arena::Box<'alloc, Void>> {
+ Err(ParseError::NotImplemented("import").into())
+ }
+
+ // ImportSpecifier : IdentifierName `as` ImportedBinding
+ pub fn import_specifier_renaming(
+ &self,
+ _original_name: arena::Box<'alloc, Token>,
+ _local_name: arena::Box<'alloc, BindingIdentifier>,
+ ) -> Result<'alloc, arena::Box<'alloc, Void>> {
+ Err(ParseError::NotImplemented("import").into())
+ }
+
+ // ModuleSpecifier : StringLiteral
+ pub fn module_specifier(
+ &self,
+ _token: arena::Box<'alloc, Token>,
+ ) -> Result<'alloc, arena::Box<'alloc, Token>> {
+ Err(ParseError::NotImplemented("import").into())
+ }
+
+ // ExportDeclaration : `export` `*` FromClause `;`
+ pub fn export_all_from(
+ &self,
+ _module_specifier: arena::Box<'alloc, Token>,
+ ) -> Result<'alloc, arena::Box<'alloc, Void>> {
+ Err(ParseError::NotImplemented("export").into())
+ }
+
+ // ExportDeclaration : `export` ExportClause FromClause `;`
+ pub fn export_set_from(
+ &self,
+ _export_clause: arena::Box<'alloc, Void>,
+ _module_specifier: arena::Box<'alloc, Token>,
+ ) -> Result<'alloc, arena::Box<'alloc, Void>> {
+ Err(ParseError::NotImplemented("export").into())
+ }
+
+ // ExportDeclaration : `export` ExportClause `;`
+ pub fn export_set(
+ &self,
+ _export_clause: arena::Box<'alloc, Void>,
+ ) -> Result<'alloc, arena::Box<'alloc, Void>> {
+ Err(ParseError::NotImplemented("export").into())
+ }
+
+ // ExportDeclaration : `export` VariableStatement
+ pub fn export_vars(
+ &self,
+ _statement: arena::Box<'alloc, Statement<'alloc>>,
+ ) -> Result<'alloc, arena::Box<'alloc, Void>> {
+ Err(ParseError::NotImplemented("export").into())
+ }
+
+ // ExportDeclaration : `export` Declaration
+ pub fn export_declaration(
+ &self,
+ _declaration: arena::Box<'alloc, Statement<'alloc>>,
+ ) -> Result<'alloc, arena::Box<'alloc, Void>> {
+ Err(ParseError::NotImplemented("export").into())
+ }
+
+ // ExportDeclaration : `export` `default` HoistableDeclaration
+ pub fn export_default_hoistable(
+ &self,
+ _declaration: arena::Box<'alloc, Statement<'alloc>>,
+ ) -> Result<'alloc, arena::Box<'alloc, Void>> {
+ Err(ParseError::NotImplemented("export").into())
+ }
+
+ // ExportDeclaration : `export` `default` ClassDeclaration
+ pub fn export_default_class(
+ &self,
+ _class_declaration: arena::Box<'alloc, Statement<'alloc>>,
+ ) -> Result<'alloc, arena::Box<'alloc, Void>> {
+ Err(ParseError::NotImplemented("export").into())
+ }
+
+ // ExportDeclaration : `export` `default` [lookahead <! {`function`, `async`, `class`}] AssignmentExpression `;`
+ pub fn export_default_value(
+ &self,
+ _expression: arena::Box<'alloc, Expression<'alloc>>,
+ ) -> Result<'alloc, arena::Box<'alloc, Void>> {
+ Err(ParseError::NotImplemented("export").into())
+ }
+
+ // ExportClause : `{` `}`
+ pub fn exports_list_empty(&self) -> Result<'alloc, arena::Box<'alloc, Void>> {
+ Err(ParseError::NotImplemented("export").into())
+ }
+
+ // ExportsList : ExportSpecifier
+ // ExportsList : ExportsList `,` ExportSpecifier
+ pub fn exports_list_append(
+ &self,
+ _list: arena::Box<'alloc, Void>,
+ _export_specifier: arena::Box<'alloc, Void>,
+ ) -> Result<'alloc, arena::Box<'alloc, Void>> {
+ Err(ParseError::NotImplemented("export").into())
+ }
+
+ // ExportSpecifier : IdentifierName
+ pub fn export_specifier(
+ &self,
+ _identifier: arena::Box<'alloc, Token>,
+ ) -> Result<'alloc, arena::Box<'alloc, Void>> {
+ Err(ParseError::NotImplemented("export").into())
+ }
+
+ // ExportSpecifier : IdentifierName `as` IdentifierName
+ pub fn export_specifier_renaming(
+ &self,
+ _local_name: arena::Box<'alloc, Token>,
+ _exported_name: arena::Box<'alloc, Token>,
+ ) -> Result<'alloc, arena::Box<'alloc, Void>> {
+ Err(ParseError::NotImplemented("export").into())
+ }
+
+ // Returns IsSimpleParameterList of `params`.
+ //
+ // NOTE: For Syntax-only parsing (NYI), the stack value for FormalParameters
+ // should contain this information.
+ fn is_params_simple(params: &FormalParameters<'alloc>) -> bool {
+ for param in params.items.iter() {
+ match param {
+ Parameter::Binding(Binding::BindingIdentifier(_)) => {}
+ _ => {
+ return false;
+ }
+ }
+ }
+
+ if params.rest.is_some() {
+ return false;
+ }
+
+ true
+ }
+
+ fn mark_labelled_statement(
+ &mut self,
+ label: &arena::Box<'alloc, Label>,
+ body: &Statement<'alloc>,
+ ) {
+ let start_label_offset = label.loc.start;
+ let kind = match body {
+ Statement::ForStatement { .. }
+ | Statement::ForOfStatement { .. }
+ | Statement::ForInStatement { .. }
+ | Statement::WhileStatement { .. }
+ | Statement::DoWhileStatement { .. } => LabelKind::Loop,
+ Statement::LabelledStatement { .. } => LabelKind::LabelledLabel,
+ Statement::FunctionDeclaration { .. } => LabelKind::Function,
+ _ => LabelKind::Other,
+ };
+
+ self.context_metadata
+ .mark_label_kind_at_offset(start_label_offset, kind);
+ }
+}
+
+impl<'alloc> EarlyErrorChecker<'alloc> for AstBuilder<'alloc> {
+ fn context_metadata_mut(&mut self) -> &mut ContextMetadata {
+ &mut self.context_metadata
+ }
+ fn context_metadata(&self) -> &ContextMetadata {
+ &self.context_metadata
+ }
+ fn atoms(&self) -> &Rc<RefCell<SourceAtomSet<'alloc>>> {
+ &self.atoms
+ }
+}