diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /third_party/rust/jsparagus-generated-parser/src/ast_builder.rs | |
parent | Initial commit. (diff) | |
download | firefox-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.rs | 4666 |
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(¶ms); + 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(¶ms); + 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(¶ms); + 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(¶ms); + 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 + } +} |