diff --git a/core/ast/src/declaration/export.rs b/core/ast/src/declaration/export.rs index 675c41e2e4..dc05f9ff77 100644 --- a/core/ast/src/declaration/export.rs +++ b/core/ast/src/declaration/export.rs @@ -9,17 +9,19 @@ //! [spec]: https://tc39.es/ecma262/#sec-exports //! [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export -use std::ops::ControlFlow; - use super::{ModuleSpecifier, VarDeclaration}; use crate::{ expression::Identifier, - function::{AsyncFunction, AsyncGenerator, Class, Function, Generator}, + function::{ + AsyncFunctionDeclaration, AsyncGeneratorDeclaration, ClassDeclaration, FunctionDeclaration, + GeneratorDeclaration, + }, try_break, visitor::{VisitWith, Visitor, VisitorMut}, Declaration, Expression, }; use boa_interner::Sym; +use std::ops::ControlFlow; /// The kind of re-export in an [`ExportDeclaration`]. #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] @@ -95,15 +97,15 @@ pub enum ExportDeclaration { /// Declaration export. Declaration(Declaration), /// Default function export. - DefaultFunction(Function), + DefaultFunctionDeclaration(FunctionDeclaration), /// Default generator export. - DefaultGenerator(Generator), + DefaultGeneratorDeclaration(GeneratorDeclaration), /// Default async function export. - DefaultAsyncFunction(AsyncFunction), + DefaultAsyncFunctionDeclaration(AsyncFunctionDeclaration), /// Default async generator export. - DefaultAsyncGenerator(AsyncGenerator), + DefaultAsyncGeneratorDeclaration(AsyncGeneratorDeclaration), /// Default class declaration export. - DefaultClassDeclaration(Class), + DefaultClassDeclaration(ClassDeclaration), /// Default assignment expression export. DefaultAssignmentExpression(Expression), } @@ -126,11 +128,15 @@ impl VisitWith for ExportDeclaration { } Self::VarStatement(var) => visitor.visit_var_declaration(var), Self::Declaration(decl) => visitor.visit_declaration(decl), - Self::DefaultFunction(f) => visitor.visit_function(f), - Self::DefaultGenerator(g) => visitor.visit_generator(g), - Self::DefaultAsyncFunction(af) => visitor.visit_async_function(af), - Self::DefaultAsyncGenerator(ag) => visitor.visit_async_generator(ag), - Self::DefaultClassDeclaration(c) => visitor.visit_class(c), + Self::DefaultFunctionDeclaration(f) => visitor.visit_function_declaration(f), + Self::DefaultGeneratorDeclaration(g) => visitor.visit_generator_declaration(g), + Self::DefaultAsyncFunctionDeclaration(af) => { + visitor.visit_async_function_declaration(af) + } + Self::DefaultAsyncGeneratorDeclaration(ag) => { + visitor.visit_async_generator_declaration(ag) + } + Self::DefaultClassDeclaration(c) => visitor.visit_class_declaration(c), Self::DefaultAssignmentExpression(expr) => visitor.visit_expression(expr), } } @@ -152,11 +158,15 @@ impl VisitWith for ExportDeclaration { } Self::VarStatement(var) => visitor.visit_var_declaration_mut(var), Self::Declaration(decl) => visitor.visit_declaration_mut(decl), - Self::DefaultFunction(f) => visitor.visit_function_mut(f), - Self::DefaultGenerator(g) => visitor.visit_generator_mut(g), - Self::DefaultAsyncFunction(af) => visitor.visit_async_function_mut(af), - Self::DefaultAsyncGenerator(ag) => visitor.visit_async_generator_mut(ag), - Self::DefaultClassDeclaration(c) => visitor.visit_class_mut(c), + Self::DefaultFunctionDeclaration(f) => visitor.visit_function_declaration_mut(f), + Self::DefaultGeneratorDeclaration(g) => visitor.visit_generator_declaration_mut(g), + Self::DefaultAsyncFunctionDeclaration(af) => { + visitor.visit_async_function_declaration_mut(af) + } + Self::DefaultAsyncGeneratorDeclaration(ag) => { + visitor.visit_async_generator_declaration_mut(ag) + } + Self::DefaultClassDeclaration(c) => visitor.visit_class_declaration_mut(c), Self::DefaultAssignmentExpression(expr) => visitor.visit_expression_mut(expr), } } diff --git a/core/ast/src/declaration/mod.rs b/core/ast/src/declaration/mod.rs index 4f15e95856..f57b551a81 100644 --- a/core/ast/src/declaration/mod.rs +++ b/core/ast/src/declaration/mod.rs @@ -14,7 +14,13 @@ //! [class]: https://tc39.es/ecma262/#prod-ClassDeclaration //! [diff]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements#difference_between_statements_and_declarations -use super::function::{AsyncFunction, AsyncGenerator, Class, Function, Generator}; +use super::function::{ + AsyncFunctionDeclaration, AsyncGeneratorDeclaration, FunctionDeclaration, GeneratorDeclaration, +}; +use crate::{ + function::ClassDeclaration, + visitor::{VisitWith, Visitor, VisitorMut}, +}; use boa_interner::{Interner, Sym, ToIndentedString, ToInternedString}; use core::ops::ControlFlow; @@ -22,7 +28,6 @@ mod export; mod import; mod variable; -use crate::visitor::{VisitWith, Visitor, VisitorMut}; pub use export::*; pub use import::*; pub use variable::*; @@ -34,20 +39,20 @@ pub use variable::*; #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive(Clone, Debug, PartialEq)] pub enum Declaration { - /// See [`Function`] - Function(Function), + /// See [`FunctionDeclaration`] + FunctionDeclaration(FunctionDeclaration), - /// See [`Generator`] - Generator(Generator), + /// See [`GeneratorDeclaration`] + GeneratorDeclaration(GeneratorDeclaration), - /// See [`AsyncFunction`] - AsyncFunction(AsyncFunction), + /// See [`AsyncFunctionDeclaration`] + AsyncFunctionDeclaration(AsyncFunctionDeclaration), - /// See [`AsyncGenerator`] - AsyncGenerator(AsyncGenerator), + /// See [`AsyncGeneratorDeclaration`] + AsyncGeneratorDeclaration(AsyncGeneratorDeclaration), - /// See [`Class`] - Class(Class), + /// See [`ClassDeclaration`] + ClassDeclaration(ClassDeclaration), /// See [`LexicalDeclaration`] Lexical(LexicalDeclaration), @@ -56,11 +61,11 @@ pub enum Declaration { impl ToIndentedString for Declaration { fn to_indented_string(&self, interner: &Interner, indentation: usize) -> String { match self { - Self::Function(f) => f.to_indented_string(interner, indentation), - Self::Generator(g) => g.to_indented_string(interner, indentation), - Self::AsyncFunction(af) => af.to_indented_string(interner, indentation), - Self::AsyncGenerator(ag) => ag.to_indented_string(interner, indentation), - Self::Class(c) => c.to_indented_string(interner, indentation), + Self::FunctionDeclaration(f) => f.to_indented_string(interner, indentation), + Self::GeneratorDeclaration(g) => g.to_indented_string(interner, indentation), + Self::AsyncFunctionDeclaration(af) => af.to_indented_string(interner, indentation), + Self::AsyncGeneratorDeclaration(ag) => ag.to_indented_string(interner, indentation), + Self::ClassDeclaration(c) => c.to_indented_string(interner, indentation), Self::Lexical(l) => { let mut s = l.to_interned_string(interner); s.push(';'); @@ -76,11 +81,11 @@ impl VisitWith for Declaration { V: Visitor<'a>, { match self { - Self::Function(f) => visitor.visit_function(f), - Self::Generator(g) => visitor.visit_generator(g), - Self::AsyncFunction(af) => visitor.visit_async_function(af), - Self::AsyncGenerator(ag) => visitor.visit_async_generator(ag), - Self::Class(c) => visitor.visit_class(c), + Self::FunctionDeclaration(f) => visitor.visit_function_declaration(f), + Self::GeneratorDeclaration(g) => visitor.visit_generator_declaration(g), + Self::AsyncFunctionDeclaration(af) => visitor.visit_async_function_declaration(af), + Self::AsyncGeneratorDeclaration(ag) => visitor.visit_async_generator_declaration(ag), + Self::ClassDeclaration(c) => visitor.visit_class_declaration(c), Self::Lexical(ld) => visitor.visit_lexical_declaration(ld), } } @@ -90,11 +95,13 @@ impl VisitWith for Declaration { V: VisitorMut<'a>, { match self { - Self::Function(f) => visitor.visit_function_mut(f), - Self::Generator(g) => visitor.visit_generator_mut(g), - Self::AsyncFunction(af) => visitor.visit_async_function_mut(af), - Self::AsyncGenerator(ag) => visitor.visit_async_generator_mut(ag), - Self::Class(c) => visitor.visit_class_mut(c), + Self::FunctionDeclaration(f) => visitor.visit_function_declaration_mut(f), + Self::GeneratorDeclaration(g) => visitor.visit_generator_declaration_mut(g), + Self::AsyncFunctionDeclaration(af) => visitor.visit_async_function_declaration_mut(af), + Self::AsyncGeneratorDeclaration(ag) => { + visitor.visit_async_generator_declaration_mut(ag) + } + Self::ClassDeclaration(c) => visitor.visit_class_declaration_mut(c), Self::Lexical(ld) => visitor.visit_lexical_declaration_mut(ld), } } diff --git a/core/ast/src/declaration/variable.rs b/core/ast/src/declaration/variable.rs index d010c8eb73..b142c0ad34 100644 --- a/core/ast/src/declaration/variable.rs +++ b/core/ast/src/declaration/variable.rs @@ -1,19 +1,16 @@ //! Variable related declarations. -use core::ops::ControlFlow; -use std::convert::TryFrom; - -use crate::try_break; -use crate::visitor::{VisitWith, Visitor, VisitorMut}; +use super::Declaration; use crate::{ expression::{Expression, Identifier}, join_nodes, pattern::Pattern, + try_break, + visitor::{VisitWith, Visitor, VisitorMut}, Statement, }; use boa_interner::{Interner, ToInternedString}; - -use super::Declaration; +use core::{convert::TryFrom, ops::ControlFlow}; /// A [`var`][var] statement, also called [`VariableStatement`][varstmt] in the spec. /// diff --git a/core/ast/src/expression/literal/array.rs b/core/ast/src/expression/literal/array.rs index 3ddaec8077..3ec3c28650 100644 --- a/core/ast/src/expression/literal/array.rs +++ b/core/ast/src/expression/literal/array.rs @@ -105,9 +105,11 @@ impl ArrayLiteral { } match assign.lhs() { AssignTarget::Identifier(ident) => { + let mut init = assign.rhs().clone(); + init.set_anonymous_function_definition_name(ident); bindings.push(ArrayPatternElement::SingleName { ident: *ident, - default_init: Some(assign.rhs().clone()), + default_init: Some(init), }); } AssignTarget::Access(access) => { diff --git a/core/ast/src/expression/literal/mod.rs b/core/ast/src/expression/literal/mod.rs index b93995c558..4bbb369d1c 100644 --- a/core/ast/src/expression/literal/mod.rs +++ b/core/ast/src/expression/literal/mod.rs @@ -13,7 +13,7 @@ mod template; pub use array::ArrayLiteral; use core::ops::ControlFlow; -pub use object::ObjectLiteral; +pub use object::{ObjectLiteral, ObjectMethodDefinition, PropertyDefinition}; pub use template::{TemplateElement, TemplateLiteral}; use crate::visitor::{VisitWith, Visitor, VisitorMut}; diff --git a/core/ast/src/expression/literal/object.rs b/core/ast/src/expression/literal/object.rs index bad63edff1..86be5f4d3e 100644 --- a/core/ast/src/expression/literal/object.rs +++ b/core/ast/src/expression/literal/object.rs @@ -4,11 +4,12 @@ use crate::{ block_to_string, expression::{ operator::assign::{AssignOp, AssignTarget}, - Expression, RESERVED_IDENTIFIERS_STRICT, + Expression, Identifier, RESERVED_IDENTIFIERS_STRICT, }, + function::{FormalParameterList, FunctionBody}, join_nodes, pattern::{ObjectPattern, ObjectPatternElement}, - property::{MethodDefinition, PropertyDefinition, PropertyName}, + property::{MethodDefinitionKind, PropertyName}, try_break, visitor::{VisitWith, Visitor, VisitorMut}, }; @@ -125,10 +126,12 @@ impl ObjectLiteral { return None; } } + let mut init = assign.rhs().clone(); + init.set_anonymous_function_definition_name(ident); bindings.push(ObjectPatternElement::SingleName { ident: *ident, name: PropertyName::Literal(name), - default_init: Some(assign.rhs().clone()), + default_init: Some(init), }); } else { return None; @@ -182,16 +185,17 @@ impl ObjectLiteral { return None; } } - PropertyDefinition::MethodDefinition(_, _) => return None, + PropertyDefinition::MethodDefinition(_) => return None, PropertyDefinition::CoverInitializedName(ident, expr) => { if strict && [Sym::EVAL, Sym::ARGUMENTS].contains(&ident.sym()) { return None; } - + let mut expr = expr.clone(); + expr.set_anonymous_function_definition_name(ident); bindings.push(ObjectPatternElement::SingleName { ident: *ident, name: PropertyName::Literal(ident.sym()), - default_init: Some(expr.clone()), + default_init: Some(expr), }); } } @@ -220,73 +224,7 @@ impl ToIndentedString for ObjectLiteral { PropertyDefinition::SpreadObject(key) => { format!("{indentation}...{},\n", key.to_interned_string(interner)) } - PropertyDefinition::MethodDefinition(key, method) => { - format!( - "{indentation}{}({}) {},\n", - match &method { - MethodDefinition::Get(_) => - format!("get {}", key.to_interned_string(interner)), - MethodDefinition::Set(_) => - format!("set {}", key.to_interned_string(interner)), - MethodDefinition::Ordinary(_) => - key.to_interned_string(interner).to_string(), - MethodDefinition::Generator(_) => - format!("*{}", key.to_interned_string(interner)), - MethodDefinition::AsyncGenerator(_) => - format!("async *{}", key.to_interned_string(interner)), - MethodDefinition::Async(_) => - format!("async {}", key.to_interned_string(interner)), - }, - match &method { - MethodDefinition::Get(expression) - | MethodDefinition::Set(expression) - | MethodDefinition::Ordinary(expression) => { - join_nodes(interner, expression.parameters().as_ref()) - } - MethodDefinition::Generator(expression) => { - join_nodes(interner, expression.parameters().as_ref()) - } - MethodDefinition::AsyncGenerator(expression) => { - join_nodes(interner, expression.parameters().as_ref()) - } - MethodDefinition::Async(expression) => { - join_nodes(interner, expression.parameters().as_ref()) - } - }, - match &method { - MethodDefinition::Get(expression) - | MethodDefinition::Set(expression) - | MethodDefinition::Ordinary(expression) => { - block_to_string( - expression.body().statements(), - interner, - indent_n + 1, - ) - } - MethodDefinition::Generator(expression) => { - block_to_string( - expression.body().statements(), - interner, - indent_n + 1, - ) - } - MethodDefinition::AsyncGenerator(expression) => { - block_to_string( - expression.body().statements(), - interner, - indent_n + 1, - ) - } - MethodDefinition::Async(expression) => { - block_to_string( - expression.body().statements(), - interner, - indent_n + 1, - ) - } - }, - ) - } + PropertyDefinition::MethodDefinition(m) => m.to_indented_string(interner, indent_n), PropertyDefinition::CoverInitializedName(ident, expr) => { format!( "{indentation}{} = {},\n", @@ -341,3 +279,215 @@ impl VisitWith for ObjectLiteral { ControlFlow::Continue(()) } } + +/// Describes the definition of a property within an object literal. +/// +/// A property has a name (a string) and a value (primitive, method, or object reference). +/// Note that when we say that "a property holds an object", that is shorthand for "a property holds an object reference". +/// This distinction matters because the original referenced object remains unchanged when you change the property's value. +/// +/// More information: +/// - [ECMAScript reference][spec] +/// - [MDN documentation][mdn] +/// +/// [spec]: https://tc39.es/ecma262/#prod-PropertyDefinition +/// [mdn]: https://developer.mozilla.org/en-US/docs/Glossary/property/JavaScript +// TODO: Support all features: https://tc39.es/ecma262/#prod-PropertyDefinition +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +#[derive(Clone, Debug, PartialEq)] +pub enum PropertyDefinition { + /// Puts a variable into an object. + /// + /// More information: + /// - [ECMAScript reference][spec] + /// - [MDN documentation][mdn] + /// + /// [spec]: https://tc39.es/ecma262/#prod-IdentifierReference + /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#Property_definitions + IdentifierReference(Identifier), + + /// Binds a property name to a JavaScript value. + /// + /// More information: + /// - [ECMAScript reference][spec] + /// - [MDN documentation][mdn] + /// + /// [spec]: https://tc39.es/ecma262/#prod-PropertyDefinition + /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#Property_definitions + Property(PropertyName, Expression), + + /// A property of an object can also refer to a function or a getter or setter method. + /// + /// More information: + /// - [ECMAScript reference][spec] + /// - [MDN documentation][mdn] + /// + /// [spec]: https://tc39.es/ecma262/#prod-MethodDefinition + /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#Method_definitions + MethodDefinition(ObjectMethodDefinition), + + /// The Rest/Spread Properties for ECMAScript proposal (stage 4) adds spread properties to object literals. + /// It copies own enumerable properties from a provided object onto a new object. + /// + /// Shallow-cloning (excluding `prototype`) or merging objects is now possible using a shorter syntax than `Object.assign()`. + /// + /// More information: + /// - [ECMAScript reference][spec] + /// - [MDN documentation][mdn] + /// + /// [spec]: https://tc39.es/ecma262/#prod-PropertyDefinition + /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#Spread_properties + SpreadObject(Expression), + + /// Cover grammar for when an object literal is used as an object binding pattern. + /// + /// More information: + /// - [ECMAScript reference][spec] + /// + /// [spec]: https://tc39.es/ecma262/#prod-CoverInitializedName + CoverInitializedName(Identifier, Expression), +} + +impl VisitWith for PropertyDefinition { + fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow + where + V: Visitor<'a>, + { + match self { + Self::IdentifierReference(id) => visitor.visit_identifier(id), + Self::Property(pn, expr) => { + try_break!(visitor.visit_property_name(pn)); + visitor.visit_expression(expr) + } + Self::MethodDefinition(m) => visitor.visit_object_method_definition(m), + Self::SpreadObject(expr) => visitor.visit_expression(expr), + Self::CoverInitializedName(id, expr) => { + try_break!(visitor.visit_identifier(id)); + visitor.visit_expression(expr) + } + } + } + + fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow + where + V: VisitorMut<'a>, + { + match self { + Self::IdentifierReference(id) => visitor.visit_identifier_mut(id), + Self::Property(pn, expr) => { + try_break!(visitor.visit_property_name_mut(pn)); + visitor.visit_expression_mut(expr) + } + Self::MethodDefinition(m) => visitor.visit_object_method_definition_mut(m), + Self::SpreadObject(expr) => visitor.visit_expression_mut(expr), + Self::CoverInitializedName(id, expr) => { + try_break!(visitor.visit_identifier_mut(id)); + visitor.visit_expression_mut(expr) + } + } + } +} + +/// A method definition. +/// +/// This type is specific to object method definitions. +/// +/// More information: +/// - [ECMAScript reference][spec] +/// +/// [spec]: https://tc39.es/ecma262/#prod-MethodDefinition +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +#[derive(Clone, Debug, PartialEq)] +pub struct ObjectMethodDefinition { + name: PropertyName, + parameters: FormalParameterList, + body: FunctionBody, + kind: MethodDefinitionKind, +} + +impl ObjectMethodDefinition { + /// Creates a new object method definition. + #[inline] + #[must_use] + pub const fn new( + name: PropertyName, + parameters: FormalParameterList, + body: FunctionBody, + kind: MethodDefinitionKind, + ) -> Self { + Self { + name, + parameters, + body, + kind, + } + } + + /// Returns the name of the object method definition. + #[inline] + #[must_use] + pub const fn name(&self) -> &PropertyName { + &self.name + } + + /// Returns the parameters of the object method definition. + #[inline] + #[must_use] + pub const fn parameters(&self) -> &FormalParameterList { + &self.parameters + } + + /// Returns the body of the object method definition. + #[inline] + #[must_use] + pub const fn body(&self) -> &FunctionBody { + &self.body + } + + /// Returns the kind of the object method definition. + #[inline] + #[must_use] + pub const fn kind(&self) -> MethodDefinitionKind { + self.kind + } +} + +impl ToIndentedString for ObjectMethodDefinition { + fn to_indented_string(&self, interner: &Interner, indent_n: usize) -> String { + let indentation = " ".repeat(indent_n + 1); + let prefix = match &self.kind { + MethodDefinitionKind::Get => "get ", + MethodDefinitionKind::Set => "set ", + MethodDefinitionKind::Ordinary => "", + MethodDefinitionKind::Generator => "*", + MethodDefinitionKind::AsyncGenerator => "async *", + MethodDefinitionKind::Async => "async ", + }; + let name = self.name.to_interned_string(interner); + let parameters = join_nodes(interner, self.parameters.as_ref()); + let body = block_to_string(self.body.statements(), interner, indent_n + 1); + format!("{indentation}{prefix}{name}({parameters}) {body},\n") + } +} + +impl VisitWith for ObjectMethodDefinition { + fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow + where + V: Visitor<'a>, + { + try_break!(visitor.visit_property_name(&self.name)); + try_break!(visitor.visit_formal_parameter_list(&self.parameters)); + visitor.visit_script(&self.body) + } + + fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow + where + V: VisitorMut<'a>, + { + try_break!(visitor.visit_property_name_mut(&mut self.name)); + try_break!(visitor.visit_formal_parameter_list_mut(&mut self.parameters)); + visitor.visit_script_mut(&mut self.body) + } +} diff --git a/core/ast/src/expression/mod.rs b/core/ast/src/expression/mod.rs index 82bad5d09c..2bc1cce4ba 100644 --- a/core/ast/src/expression/mod.rs +++ b/core/ast/src/expression/mod.rs @@ -15,7 +15,10 @@ use self::{ operator::{Assign, Binary, BinaryInPrivate, Conditional, Unary, Update}, }; use super::{ - function::{ArrowFunction, AsyncFunction, AsyncGenerator, Class, Function, Generator}, + function::{ + ArrowFunction, AsyncFunctionExpression, AsyncGeneratorExpression, ClassExpression, + FunctionExpression, GeneratorExpression, + }, function::{AsyncArrowFunction, FormalParameterList}, Statement, }; @@ -88,8 +91,8 @@ pub enum Expression { /// See [`Spread`], Spread(Spread), - /// See [`Function`]. - Function(Function), + /// See [`FunctionExpression`]. + FunctionExpression(FunctionExpression), /// See [`ArrowFunction`]. ArrowFunction(ArrowFunction), @@ -97,20 +100,18 @@ pub enum Expression { /// See [`AsyncArrowFunction`]. AsyncArrowFunction(AsyncArrowFunction), - /// See [`Generator`]. - Generator(Generator), + /// See [`GeneratorExpression`]. + GeneratorExpression(GeneratorExpression), - /// See [`AsyncFunction`]. - AsyncFunction(AsyncFunction), + /// See [`AsyncFunctionExpression`]. + AsyncFunctionExpression(AsyncFunctionExpression), - /// See [`AsyncGenerator`]. - AsyncGenerator(AsyncGenerator), + /// See [`AsyncGeneratorExpression`]. + AsyncGeneratorExpression(AsyncGeneratorExpression), - /// See [`Class`]. - Class(Box), + /// See [`ClassExpression`]. + ClassExpression(Box), - // TODO: Extract regexp literal Expression - // RegExpLiteral, /// See [`TemplateLiteral`]. TemplateLiteral(TemplateLiteral), @@ -189,13 +190,15 @@ impl Expression { Self::ArrayLiteral(arr) => arr.to_interned_string(interner), Self::ObjectLiteral(o) => o.to_indented_string(interner, indentation), Self::Spread(sp) => sp.to_interned_string(interner), - Self::Function(f) => f.to_indented_string(interner, indentation), + Self::FunctionExpression(f) => f.to_indented_string(interner, indentation), Self::AsyncArrowFunction(f) => f.to_indented_string(interner, indentation), Self::ArrowFunction(arrf) => arrf.to_indented_string(interner, indentation), - Self::Class(cl) => cl.to_indented_string(interner, indentation), - Self::Generator(gen) => gen.to_indented_string(interner, indentation), - Self::AsyncFunction(asf) => asf.to_indented_string(interner, indentation), - Self::AsyncGenerator(asgen) => asgen.to_indented_string(interner, indentation), + Self::ClassExpression(cl) => cl.to_indented_string(interner, indentation), + Self::GeneratorExpression(gen) => gen.to_indented_string(interner, indentation), + Self::AsyncFunctionExpression(asf) => asf.to_indented_string(interner, indentation), + Self::AsyncGeneratorExpression(asgen) => { + asgen.to_indented_string(interner, indentation) + } Self::TemplateLiteral(tem) => tem.to_interned_string(interner), Self::PropertyAccess(prop) => prop.to_interned_string(interner), Self::New(new) => new.to_interned_string(interner), @@ -220,27 +223,6 @@ impl Expression { } } - /// Returns if the expression is a function definition according to the spec. - /// - /// More information: - /// - [ECMAScript reference][spec] - /// - /// [spec]: https://tc39.es/ecma262/#sec-static-semantics-isfunctiondefinition - #[must_use] - #[inline] - pub const fn is_function_definition(&self) -> bool { - matches!( - self, - Self::ArrowFunction(_) - | Self::AsyncArrowFunction(_) - | Self::Function(_) - | Self::Generator(_) - | Self::AsyncGenerator(_) - | Self::AsyncFunction(_) - | Self::Class(_) - ) - } - /// Returns if the expression is a function definition without a name. /// /// More information: @@ -253,16 +235,34 @@ impl Expression { match self { Self::ArrowFunction(f) => f.name().is_none(), Self::AsyncArrowFunction(f) => f.name().is_none(), - Self::Function(f) => f.name().is_none(), - Self::Generator(f) => f.name().is_none(), - Self::AsyncGenerator(f) => f.name().is_none(), - Self::AsyncFunction(f) => f.name().is_none(), - Self::Class(f) => f.name().is_none(), + Self::FunctionExpression(f) => f.name().is_none(), + Self::GeneratorExpression(f) => f.name().is_none(), + Self::AsyncGeneratorExpression(f) => f.name().is_none(), + Self::AsyncFunctionExpression(f) => f.name().is_none(), + Self::ClassExpression(f) => f.name().is_none(), Self::Parenthesized(p) => p.expression().is_anonymous_function_definition(), _ => false, } } + /// Sets the name of an anonymous function definition. + /// + /// This is used to set the name of a function expression when it is assigned to a variable. + /// If the function already has a name, this does nothing. + pub fn set_anonymous_function_definition_name(&mut self, name: &Identifier) { + match self { + Self::ArrowFunction(f) if f.name().is_none() => f.name = Some(*name), + Self::AsyncArrowFunction(f) if f.name().is_none() => f.name = Some(*name), + Self::FunctionExpression(f) if f.name().is_none() => f.name = Some(*name), + Self::GeneratorExpression(f) if f.name().is_none() => f.name = Some(*name), + Self::AsyncGeneratorExpression(f) if f.name().is_none() => f.name = Some(*name), + Self::AsyncFunctionExpression(f) if f.name().is_none() => f.name = Some(*name), + Self::ClassExpression(f) if f.name().is_none() => f.name = Some(*name), + Self::Parenthesized(p) => p.expression.set_anonymous_function_definition_name(name), + _ => {} + } + } + /// Returns the expression without any outer parenthesized expressions. #[must_use] #[inline] @@ -301,13 +301,13 @@ impl VisitWith for Expression { Self::ArrayLiteral(arlit) => visitor.visit_array_literal(arlit), Self::ObjectLiteral(olit) => visitor.visit_object_literal(olit), Self::Spread(sp) => visitor.visit_spread(sp), - Self::Function(f) => visitor.visit_function(f), + Self::FunctionExpression(f) => visitor.visit_function_expression(f), Self::ArrowFunction(af) => visitor.visit_arrow_function(af), Self::AsyncArrowFunction(af) => visitor.visit_async_arrow_function(af), - Self::Generator(g) => visitor.visit_generator(g), - Self::AsyncFunction(af) => visitor.visit_async_function(af), - Self::AsyncGenerator(ag) => visitor.visit_async_generator(ag), - Self::Class(c) => visitor.visit_class(c), + Self::GeneratorExpression(g) => visitor.visit_generator_expression(g), + Self::AsyncFunctionExpression(af) => visitor.visit_async_function_expression(af), + Self::AsyncGeneratorExpression(ag) => visitor.visit_async_generator_expression(ag), + Self::ClassExpression(c) => visitor.visit_class_expression(c), Self::TemplateLiteral(tlit) => visitor.visit_template_literal(tlit), Self::PropertyAccess(pa) => visitor.visit_property_access(pa), Self::New(n) => visitor.visit_new(n), @@ -344,13 +344,13 @@ impl VisitWith for Expression { Self::ArrayLiteral(arlit) => visitor.visit_array_literal_mut(arlit), Self::ObjectLiteral(olit) => visitor.visit_object_literal_mut(olit), Self::Spread(sp) => visitor.visit_spread_mut(sp), - Self::Function(f) => visitor.visit_function_mut(f), + Self::FunctionExpression(f) => visitor.visit_function_expression_mut(f), Self::ArrowFunction(af) => visitor.visit_arrow_function_mut(af), Self::AsyncArrowFunction(af) => visitor.visit_async_arrow_function_mut(af), - Self::Generator(g) => visitor.visit_generator_mut(g), - Self::AsyncFunction(af) => visitor.visit_async_function_mut(af), - Self::AsyncGenerator(ag) => visitor.visit_async_generator_mut(ag), - Self::Class(c) => visitor.visit_class_mut(c), + Self::GeneratorExpression(g) => visitor.visit_generator_expression_mut(g), + Self::AsyncFunctionExpression(af) => visitor.visit_async_function_expression_mut(af), + Self::AsyncGeneratorExpression(ag) => visitor.visit_async_generator_expression_mut(ag), + Self::ClassExpression(c) => visitor.visit_class_expression_mut(c), Self::TemplateLiteral(tlit) => visitor.visit_template_literal_mut(tlit), Self::PropertyAccess(pa) => visitor.visit_property_access_mut(pa), Self::New(n) => visitor.visit_new_mut(n), diff --git a/core/ast/src/expression/parenthesized.rs b/core/ast/src/expression/parenthesized.rs index 1b28abf81d..04d5b3554b 100644 --- a/core/ast/src/expression/parenthesized.rs +++ b/core/ast/src/expression/parenthesized.rs @@ -15,7 +15,7 @@ use core::ops::ControlFlow; #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive(Clone, Debug, PartialEq)] pub struct Parenthesized { - expression: Box, + pub(crate) expression: Box, } impl Parenthesized { diff --git a/core/ast/src/function/arrow_function.rs b/core/ast/src/function/arrow_function.rs index ca9af3b8c9..f11ffba5fa 100644 --- a/core/ast/src/function/arrow_function.rs +++ b/core/ast/src/function/arrow_function.rs @@ -22,7 +22,7 @@ use super::{FormalParameterList, FunctionBody}; #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive(Clone, Debug, PartialEq)] pub struct ArrowFunction { - name: Option, + pub(crate) name: Option, parameters: FormalParameterList, body: FunctionBody, } diff --git a/core/ast/src/function/async_arrow_function.rs b/core/ast/src/function/async_arrow_function.rs index b3a3278263..6e4d19ad98 100644 --- a/core/ast/src/function/async_arrow_function.rs +++ b/core/ast/src/function/async_arrow_function.rs @@ -22,7 +22,7 @@ use boa_interner::{Interner, ToIndentedString}; #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive(Clone, Debug, PartialEq)] pub struct AsyncArrowFunction { - name: Option, + pub(crate) name: Option, parameters: FormalParameterList, body: FunctionBody, } diff --git a/core/ast/src/function/async_function.rs b/core/ast/src/function/async_function.rs index 76789be407..a90711654b 100644 --- a/core/ast/src/function/async_function.rs +++ b/core/ast/src/function/async_function.rs @@ -1,36 +1,129 @@ //! Async Function Expression. -use crate::try_break; -use crate::visitor::{VisitWith, Visitor, VisitorMut}; +use super::{FormalParameterList, FunctionBody}; use crate::{ + block_to_string, expression::{Expression, Identifier}, - join_nodes, Declaration, + join_nodes, try_break, + visitor::{VisitWith, Visitor, VisitorMut}, + Declaration, }; use boa_interner::{Interner, ToIndentedString}; use core::ops::ControlFlow; -use super::{FormalParameterList, FunctionBody}; +/// An async function declaration. +/// +/// More information: +/// - [ECMAScript reference][spec] +/// - [MDN documentation][mdn] +/// +/// [spec]: https://tc39.es/ecma262/#prod-AsyncFunctionDeclaration +/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +#[derive(Clone, Debug, PartialEq)] +pub struct AsyncFunctionDeclaration { + name: Identifier, + parameters: FormalParameterList, + body: FunctionBody, +} + +impl AsyncFunctionDeclaration { + /// Creates a new async function declaration. + #[inline] + #[must_use] + pub const fn new( + name: Identifier, + parameters: FormalParameterList, + body: FunctionBody, + ) -> Self { + Self { + name, + parameters, + body, + } + } + + /// Gets the name of the async function declaration. + #[inline] + #[must_use] + pub const fn name(&self) -> Identifier { + self.name + } -/// An async function definition, as defined by the [spec]. + /// Gets the list of parameters of the async function declaration. + #[inline] + #[must_use] + pub const fn parameters(&self) -> &FormalParameterList { + &self.parameters + } + + /// Gets the body of the async function declaration. + #[inline] + #[must_use] + pub const fn body(&self) -> &FunctionBody { + &self.body + } +} + +impl ToIndentedString for AsyncFunctionDeclaration { + fn to_indented_string(&self, interner: &Interner, indentation: usize) -> String { + format!( + "async function {}({}) {}", + interner.resolve_expect(self.name.sym()), + join_nodes(interner, self.parameters.as_ref()), + block_to_string(self.body.statements(), interner, indentation) + ) + } +} + +impl VisitWith for AsyncFunctionDeclaration { + fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow + where + V: Visitor<'a>, + { + try_break!(visitor.visit_identifier(&self.name)); + try_break!(visitor.visit_formal_parameter_list(&self.parameters)); + visitor.visit_script(&self.body) + } + + fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow + where + V: VisitorMut<'a>, + { + try_break!(visitor.visit_identifier_mut(&mut self.name)); + try_break!(visitor.visit_formal_parameter_list_mut(&mut self.parameters)); + visitor.visit_script_mut(&mut self.body) + } +} + +impl From for Declaration { + #[inline] + fn from(f: AsyncFunctionDeclaration) -> Self { + Self::AsyncFunctionDeclaration(f) + } +} + +/// An async function expression. /// -/// An [async function][mdn] is a function where await expressions are allowed within it. -/// The async and await keywords enable asynchronous programming on Javascript without the use -/// of promise chains. +/// More information: +/// - [ECMAScript reference][spec] +/// - [MDN documentation][mdn] /// -/// [spec]: https://tc39.es/ecma262/#sec-async-function-definitions +/// [spec]: https://tc39.es/ecma262/#prod-AsyncFunctionExpression /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive(Clone, Debug, PartialEq)] -pub struct AsyncFunction { - name: Option, +pub struct AsyncFunctionExpression { + pub(crate) name: Option, parameters: FormalParameterList, body: FunctionBody, has_binding_identifier: bool, } -impl AsyncFunction { - /// Creates a new function expression +impl AsyncFunctionExpression { + /// Creates a new async function expression. #[inline] #[must_use] pub const fn new( @@ -47,28 +140,28 @@ impl AsyncFunction { } } - /// Gets the name of the function declaration. + /// Gets the name of the async function expression. #[inline] #[must_use] pub const fn name(&self) -> Option { self.name } - /// Gets the list of parameters of the function declaration. + /// Gets the list of parameters of the async function expression. #[inline] #[must_use] pub const fn parameters(&self) -> &FormalParameterList { &self.parameters } - /// Gets the body of the function declaration. + /// Gets the body of the async function expression. #[inline] #[must_use] pub const fn body(&self) -> &FunctionBody { &self.body } - /// Returns whether the function expression has a binding identifier. + /// Returns whether the async function expression has a binding identifier. #[inline] #[must_use] pub const fn has_binding_identifier(&self) -> bool { @@ -76,7 +169,7 @@ impl AsyncFunction { } } -impl ToIndentedString for AsyncFunction { +impl ToIndentedString for AsyncFunctionExpression { fn to_indented_string(&self, interner: &Interner, indentation: usize) -> String { let mut buf = "async function".to_owned(); if self.has_binding_identifier { @@ -101,21 +194,14 @@ impl ToIndentedString for AsyncFunction { } } -impl From for Expression { - #[inline] - fn from(expr: AsyncFunction) -> Self { - Self::AsyncFunction(expr) - } -} - -impl From for Declaration { +impl From for Expression { #[inline] - fn from(f: AsyncFunction) -> Self { - Self::AsyncFunction(f) + fn from(expr: AsyncFunctionExpression) -> Self { + Self::AsyncFunctionExpression(expr) } } -impl VisitWith for AsyncFunction { +impl VisitWith for AsyncFunctionExpression { fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow where V: Visitor<'a>, diff --git a/core/ast/src/function/async_generator.rs b/core/ast/src/function/async_generator.rs index 0ced6bbb9f..72614a0bef 100644 --- a/core/ast/src/function/async_generator.rs +++ b/core/ast/src/function/async_generator.rs @@ -11,25 +11,119 @@ use core::ops::ControlFlow; use super::{FormalParameterList, FunctionBody}; -/// An async generator definition, as defined by the [spec]. +/// An async generator declaration. /// -/// An [async generator][mdn] combines async functions with generators, making it possible to use -/// `await` and `yield` expressions within the definition of the function. +/// More information: +/// - [ECMAScript reference][spec] +/// - [MDN documentation][mdn] /// -/// [spec]: https://tc39.es/ecma262/#sec-async-generator-function-definitions +/// [spec]: https://tc39.es/ecma262/#prod-AsyncGeneratorDeclaration /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function* #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive(Clone, Debug, PartialEq)] -pub struct AsyncGenerator { - name: Option, +pub struct AsyncGeneratorDeclaration { + name: Identifier, + parameters: FormalParameterList, + body: FunctionBody, +} + +impl AsyncGeneratorDeclaration { + /// Creates a new async generator declaration. + #[inline] + #[must_use] + pub const fn new( + name: Identifier, + parameters: FormalParameterList, + body: FunctionBody, + ) -> Self { + Self { + name, + parameters, + body, + } + } + + /// Gets the name of the async generator declaration. + #[inline] + #[must_use] + pub const fn name(&self) -> Identifier { + self.name + } + + /// Gets the list of parameters of the async generator declaration. + #[inline] + #[must_use] + pub const fn parameters(&self) -> &FormalParameterList { + &self.parameters + } + + /// Gets the body of the async generator declaration. + #[inline] + #[must_use] + pub const fn body(&self) -> &FunctionBody { + &self.body + } +} + +impl ToIndentedString for AsyncGeneratorDeclaration { + fn to_indented_string(&self, interner: &Interner, indentation: usize) -> String { + format!( + "async function* {}({}) {}", + interner.resolve_expect(self.name.sym()), + join_nodes(interner, self.parameters.as_ref()), + block_to_string(self.body.statements(), interner, indentation) + ) + } +} + +impl VisitWith for AsyncGeneratorDeclaration { + fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow + where + V: Visitor<'a>, + { + try_break!(visitor.visit_identifier(&self.name)); + try_break!(visitor.visit_formal_parameter_list(&self.parameters)); + visitor.visit_script(&self.body) + } + + fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow + where + V: VisitorMut<'a>, + { + try_break!(visitor.visit_identifier_mut(&mut self.name)); + try_break!(visitor.visit_formal_parameter_list_mut(&mut self.parameters)); + visitor.visit_script_mut(&mut self.body) + } +} + +impl From for Declaration { + #[inline] + fn from(f: AsyncGeneratorDeclaration) -> Self { + Self::AsyncGeneratorDeclaration(f) + } +} + +/// An async generator expression. +/// +/// More information: +/// - [ECMAScript reference][spec] +/// - [MDN documentation][mdn] +/// +/// [spec]: https://tc39.es/ecma262/#prod-AsyncGeneratorExpression +/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function* +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +#[derive(Clone, Debug, PartialEq)] +pub struct AsyncGeneratorExpression { + pub(crate) name: Option, parameters: FormalParameterList, body: FunctionBody, has_binding_identifier: bool, } -impl AsyncGenerator { - /// Creates a new async generator expression +impl AsyncGeneratorExpression { + /// Creates a new async generator expression. #[inline] #[must_use] pub const fn new( @@ -46,28 +140,28 @@ impl AsyncGenerator { } } - /// Gets the name of the async generator expression + /// Gets the name of the async generator expression. #[inline] #[must_use] pub const fn name(&self) -> Option { self.name } - /// Gets the list of parameters of the async generator expression + /// Gets the list of parameters of the async generator expression. #[inline] #[must_use] pub const fn parameters(&self) -> &FormalParameterList { &self.parameters } - /// Gets the body of the async generator expression + /// Gets the body of the async generator expression. #[inline] #[must_use] pub const fn body(&self) -> &FunctionBody { &self.body } - /// Returns whether the function expression has a binding identifier. + /// Returns whether the async generator expression has a binding identifier. #[inline] #[must_use] pub const fn has_binding_identifier(&self) -> bool { @@ -75,7 +169,7 @@ impl AsyncGenerator { } } -impl ToIndentedString for AsyncGenerator { +impl ToIndentedString for AsyncGeneratorExpression { fn to_indented_string(&self, interner: &Interner, indentation: usize) -> String { let mut buf = "async function*".to_owned(); if self.has_binding_identifier { @@ -93,21 +187,14 @@ impl ToIndentedString for AsyncGenerator { } } -impl From for Expression { - #[inline] - fn from(expr: AsyncGenerator) -> Self { - Self::AsyncGenerator(expr) - } -} - -impl From for Declaration { +impl From for Expression { #[inline] - fn from(f: AsyncGenerator) -> Self { - Self::AsyncGenerator(f) + fn from(expr: AsyncGeneratorExpression) -> Self { + Self::AsyncGeneratorExpression(expr) } } -impl VisitWith for AsyncGenerator { +impl VisitWith for AsyncGeneratorExpression { fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow where V: Visitor<'a>, diff --git a/core/ast/src/function/class.rs b/core/ast/src/function/class.rs index 3806078e7f..677d8ac86b 100644 --- a/core/ast/src/function/class.rs +++ b/core/ast/src/function/class.rs @@ -1,9 +1,9 @@ -use super::Function; +use super::{FormalParameterList, FunctionBody, FunctionExpression}; use crate::{ block_to_string, expression::{Expression, Identifier}, join_nodes, - property::{MethodDefinition, PropertyName}, + property::{MethodDefinitionKind, PropertyName}, try_break, visitor::{VisitWith, Visitor, VisitorMut}, Declaration, @@ -12,81 +12,212 @@ use boa_interner::{Interner, Sym, ToIndentedString, ToInternedString}; use core::ops::ControlFlow; use std::hash::Hash; -/// A class declaration, as defined by the [spec]. +/// A class declaration. /// -/// A [class][mdn] declaration defines a class with the specified methods, fields, and optional constructor. -/// Classes can be used to create objects, which can also be created through literals (using `{}`). +/// More information: +/// - [ECMAScript reference][spec] +/// - [MDN documentation][mdn] /// -/// [spec]: https://tc39.es/ecma262/#sec-class-definitions -/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes +/// [spec]: https://tc39.es/ecma262/#prod-ClassDeclaration +/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/class #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive(Clone, Debug, PartialEq)] -pub struct Class { - name: Option, +pub struct ClassDeclaration { + name: Identifier, super_ref: Option, - pub(crate) constructor: Option, + pub(crate) constructor: Option, pub(crate) elements: Box<[ClassElement]>, - has_binding_identifier: bool, } -impl Class { +impl ClassDeclaration { /// Creates a new class declaration. #[inline] #[must_use] pub fn new( - name: Option, + name: Identifier, super_ref: Option, - constructor: Option, + constructor: Option, elements: Box<[ClassElement]>, - has_binding_identifier: bool, ) -> Self { Self { name, super_ref, constructor, elements, - has_binding_identifier, } } - /// Returns the name of the class. + /// Returns the name of the class declaration. #[inline] #[must_use] - pub const fn name(&self) -> Option { + pub const fn name(&self) -> Identifier { self.name } - /// Returns the super class ref of the class. + /// Returns the super class ref of the class declaration. #[inline] #[must_use] pub const fn super_ref(&self) -> Option<&Expression> { self.super_ref.as_ref() } - /// Returns the constructor of the class. + /// Returns the constructor of the class declaration. #[inline] #[must_use] - pub const fn constructor(&self) -> Option<&Function> { + pub const fn constructor(&self) -> Option<&FunctionExpression> { self.constructor.as_ref() } - /// Gets the list of all fields defined on the class. + /// Gets the list of all fields defined on the class declaration. #[inline] #[must_use] pub const fn elements(&self) -> &[ClassElement] { &self.elements } +} - /// Returns whether the class has a binding identifier. +impl ToIndentedString for ClassDeclaration { + fn to_indented_string(&self, interner: &Interner, indent_n: usize) -> String { + let mut buf = format!("class {}", interner.resolve_expect(self.name.sym())); + if let Some(super_ref) = self.super_ref.as_ref() { + buf.push_str(&format!( + " extends {}", + super_ref.to_interned_string(interner) + )); + } + if self.elements.is_empty() && self.constructor().is_none() { + buf.push_str(" {}"); + return buf; + } + let indentation = " ".repeat(indent_n + 1); + buf.push_str(" {\n"); + if let Some(expr) = &self.constructor { + buf.push_str(&format!( + "{indentation}constructor({}) {}\n", + join_nodes(interner, expr.parameters().as_ref()), + block_to_string(expr.body().statements(), interner, indent_n + 1) + )); + } + for element in &self.elements { + buf.push_str(&element.to_indented_string(interner, indent_n)); + } + buf.push('}'); + buf + } +} + +impl VisitWith for ClassDeclaration { + fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow + where + V: Visitor<'a>, + { + try_break!(visitor.visit_identifier(&self.name)); + if let Some(expr) = &self.super_ref { + try_break!(visitor.visit_expression(expr)); + } + if let Some(func) = &self.constructor { + try_break!(visitor.visit_function_expression(func)); + } + for elem in &*self.elements { + try_break!(visitor.visit_class_element(elem)); + } + ControlFlow::Continue(()) + } + + fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow + where + V: VisitorMut<'a>, + { + try_break!(visitor.visit_identifier_mut(&mut self.name)); + if let Some(expr) = &mut self.super_ref { + try_break!(visitor.visit_expression_mut(expr)); + } + if let Some(func) = &mut self.constructor { + try_break!(visitor.visit_function_expression_mut(func)); + } + for elem in &mut *self.elements { + try_break!(visitor.visit_class_element_mut(elem)); + } + ControlFlow::Continue(()) + } +} + +impl From for Declaration { + fn from(f: ClassDeclaration) -> Self { + Self::ClassDeclaration(f) + } +} + +/// A class expression. +/// +/// More information: +/// - [ECMAScript reference][spec] +/// - [MDN documentation][mdn] +/// +/// [spec]: https://tc39.es/ecma262/#prod-ClassExpression +/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/class +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +#[derive(Clone, Debug, PartialEq)] +pub struct ClassExpression { + pub(crate) name: Option, + super_ref: Option, + pub(crate) constructor: Option, + pub(crate) elements: Box<[ClassElement]>, + has_binding_identifier: bool, +} + +impl ClassExpression { + /// Creates a new class expression. + #[inline] + #[must_use] + pub fn new( + name: Option, + super_ref: Option, + constructor: Option, + elements: Box<[ClassElement]>, + has_binding_identifier: bool, + ) -> Self { + Self { + name, + super_ref, + constructor, + elements, + has_binding_identifier, + } + } + + /// Returns the name of the class expression. + #[inline] + #[must_use] + pub const fn name(&self) -> Option { + self.name + } + + /// Returns the super class ref of the class expression. + #[inline] + #[must_use] + pub const fn super_ref(&self) -> Option<&Expression> { + self.super_ref.as_ref() + } + + /// Returns the constructor of the class expression. #[inline] #[must_use] - pub const fn has_binding_identifier(&self) -> bool { - self.has_binding_identifier + pub const fn constructor(&self) -> Option<&FunctionExpression> { + self.constructor.as_ref() + } + + /// Gets the list of all fields defined on the class expression. + #[inline] + #[must_use] + pub const fn elements(&self) -> &[ClassElement] { + &self.elements } } -impl ToIndentedString for Class { +impl ToIndentedString for ClassExpression { fn to_indented_string(&self, interner: &Interner, indent_n: usize) -> String { let mut buf = "class".to_string(); if self.has_binding_identifier { @@ -113,263 +244,21 @@ impl ToIndentedString for Class { block_to_string(expr.body().statements(), interner, indent_n + 1) )); } - for element in &*self.elements { - buf.push_str(&match element { - ClassElement::MethodDefinition(name, method) => { - format!( - "{indentation}{}{}({}) {}\n", - match &method { - MethodDefinition::Get(_) => "get ", - MethodDefinition::Set(_) => "set ", - _ => "", - }, - name.to_interned_string(interner), - match &method { - MethodDefinition::Get(expr) - | MethodDefinition::Set(expr) - | MethodDefinition::Ordinary(expr) => { - join_nodes(interner, expr.parameters().as_ref()) - } - MethodDefinition::Generator(expr) => { - join_nodes(interner, expr.parameters().as_ref()) - } - MethodDefinition::AsyncGenerator(expr) => { - join_nodes(interner, expr.parameters().as_ref()) - } - MethodDefinition::Async(expr) => { - join_nodes(interner, expr.parameters().as_ref()) - } - }, - match &method { - MethodDefinition::Get(expr) - | MethodDefinition::Set(expr) - | MethodDefinition::Ordinary(expr) => { - block_to_string(expr.body().statements(), interner, indent_n + 1) - } - MethodDefinition::Generator(expr) => { - block_to_string(expr.body().statements(), interner, indent_n + 1) - } - MethodDefinition::AsyncGenerator(expr) => { - block_to_string(expr.body().statements(), interner, indent_n + 1) - } - MethodDefinition::Async(expr) => { - block_to_string(expr.body().statements(), interner, indent_n + 1) - } - }, - ) - } - ClassElement::StaticMethodDefinition(name, method) => { - format!( - "{indentation}static {}{}({}) {}\n", - match &method { - MethodDefinition::Get(_) => "get ", - MethodDefinition::Set(_) => "set ", - _ => "", - }, - name.to_interned_string(interner), - match &method { - MethodDefinition::Get(expr) - | MethodDefinition::Set(expr) - | MethodDefinition::Ordinary(expr) => { - join_nodes(interner, expr.parameters().as_ref()) - } - MethodDefinition::Generator(expr) => { - join_nodes(interner, expr.parameters().as_ref()) - } - MethodDefinition::AsyncGenerator(expr) => { - join_nodes(interner, expr.parameters().as_ref()) - } - MethodDefinition::Async(expr) => { - join_nodes(interner, expr.parameters().as_ref()) - } - }, - match &method { - MethodDefinition::Get(expr) - | MethodDefinition::Set(expr) - | MethodDefinition::Ordinary(expr) => { - block_to_string(expr.body().statements(), interner, indent_n + 1) - } - MethodDefinition::Generator(expr) => { - block_to_string(expr.body().statements(), interner, indent_n + 1) - } - MethodDefinition::AsyncGenerator(expr) => { - block_to_string(expr.body().statements(), interner, indent_n + 1) - } - MethodDefinition::Async(expr) => { - block_to_string(expr.body().statements(), interner, indent_n + 1) - } - }, - ) - } - ClassElement::FieldDefinition(name, field) => match field { - Some(expr) => { - format!( - "{indentation}{} = {};\n", - name.to_interned_string(interner), - expr.to_no_indent_string(interner, indent_n + 1) - ) - } - None => { - format!("{indentation}{};\n", name.to_interned_string(interner),) - } - }, - ClassElement::StaticFieldDefinition(name, field) => match field { - Some(expr) => { - format!( - "{indentation}static {} = {};\n", - name.to_interned_string(interner), - expr.to_no_indent_string(interner, indent_n + 1) - ) - } - None => { - format!( - "{indentation}static {};\n", - name.to_interned_string(interner), - ) - } - }, - ClassElement::PrivateMethodDefinition(name, method) => { - format!( - "{indentation}{}#{}({}) {}\n", - match &method { - MethodDefinition::Get(_) => "get ", - MethodDefinition::Set(_) => "set ", - _ => "", - }, - interner.resolve_expect(name.description()), - match &method { - MethodDefinition::Get(expr) - | MethodDefinition::Set(expr) - | MethodDefinition::Ordinary(expr) => { - join_nodes(interner, expr.parameters().as_ref()) - } - MethodDefinition::Generator(expr) => { - join_nodes(interner, expr.parameters().as_ref()) - } - MethodDefinition::AsyncGenerator(expr) => { - join_nodes(interner, expr.parameters().as_ref()) - } - MethodDefinition::Async(expr) => { - join_nodes(interner, expr.parameters().as_ref()) - } - }, - match &method { - MethodDefinition::Get(expr) - | MethodDefinition::Set(expr) - | MethodDefinition::Ordinary(expr) => { - block_to_string(expr.body().statements(), interner, indent_n + 1) - } - MethodDefinition::Generator(expr) => { - block_to_string(expr.body().statements(), interner, indent_n + 1) - } - MethodDefinition::AsyncGenerator(expr) => { - block_to_string(expr.body().statements(), interner, indent_n + 1) - } - MethodDefinition::Async(expr) => { - block_to_string(expr.body().statements(), interner, indent_n + 1) - } - }, - ) - } - ClassElement::PrivateStaticMethodDefinition(name, method) => { - format!( - "{indentation}static {}#{}({}) {}\n", - match &method { - MethodDefinition::Get(_) => "get ", - MethodDefinition::Set(_) => "set ", - _ => "", - }, - interner.resolve_expect(name.description()), - match &method { - MethodDefinition::Get(expr) - | MethodDefinition::Set(expr) - | MethodDefinition::Ordinary(expr) => { - join_nodes(interner, expr.parameters().as_ref()) - } - MethodDefinition::Generator(expr) => { - join_nodes(interner, expr.parameters().as_ref()) - } - MethodDefinition::AsyncGenerator(expr) => { - join_nodes(interner, expr.parameters().as_ref()) - } - MethodDefinition::Async(expr) => { - join_nodes(interner, expr.parameters().as_ref()) - } - }, - match &method { - MethodDefinition::Get(expr) - | MethodDefinition::Set(expr) - | MethodDefinition::Ordinary(expr) => { - block_to_string(expr.body().statements(), interner, indent_n + 1) - } - MethodDefinition::Generator(expr) => { - block_to_string(expr.body().statements(), interner, indent_n + 1) - } - MethodDefinition::AsyncGenerator(expr) => { - block_to_string(expr.body().statements(), interner, indent_n + 1) - } - MethodDefinition::Async(expr) => { - block_to_string(expr.body().statements(), interner, indent_n + 1) - } - }, - ) - } - ClassElement::PrivateFieldDefinition(name, field) => match field { - Some(expr) => { - format!( - "{indentation}#{} = {};\n", - interner.resolve_expect(name.description()), - expr.to_no_indent_string(interner, indent_n + 1) - ) - } - None => { - format!( - "{indentation}#{};\n", - interner.resolve_expect(name.description()), - ) - } - }, - ClassElement::PrivateStaticFieldDefinition(name, field) => match field { - Some(expr) => { - format!( - "{indentation}static #{} = {};\n", - interner.resolve_expect(name.description()), - expr.to_no_indent_string(interner, indent_n + 1) - ) - } - None => { - format!( - "{indentation}static #{};\n", - interner.resolve_expect(name.description()), - ) - } - }, - ClassElement::StaticBlock(body) => { - format!( - "{indentation}static {}\n", - block_to_string(body.statements(), interner, indent_n + 1) - ) - } - }); + for element in &self.elements { + buf.push_str(&element.to_indented_string(interner, indent_n)); } buf.push('}'); buf } } -impl From for Expression { - fn from(expr: Class) -> Self { - Self::Class(Box::new(expr)) - } -} - -impl From for Declaration { - fn from(f: Class) -> Self { - Self::Class(f) +impl From for Expression { + fn from(expr: ClassExpression) -> Self { + Self::ClassExpression(Box::new(expr)) } } -impl VisitWith for Class { +impl VisitWith for ClassExpression { fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow where V: Visitor<'a>, @@ -381,7 +270,7 @@ impl VisitWith for Class { try_break!(visitor.visit_expression(expr)); } if let Some(func) = &self.constructor { - try_break!(visitor.visit_function(func)); + try_break!(visitor.visit_function_expression(func)); } for elem in &*self.elements { try_break!(visitor.visit_class_element(elem)); @@ -400,7 +289,7 @@ impl VisitWith for Class { try_break!(visitor.visit_expression_mut(expr)); } if let Some(func) = &mut self.constructor { - try_break!(visitor.visit_function_mut(func)); + try_break!(visitor.visit_function_expression_mut(func)); } for elem in &mut *self.elements { try_break!(visitor.visit_class_element_mut(elem)); @@ -416,18 +305,18 @@ impl VisitWith for Class { /// [spec]: https://tc39.es/ecma262/#prod-ClassStaticBlockBody type StaticBlockBody = crate::Script; -/// An element that can be within a [`Class`], as defined by the [spec]. +/// An element that can be within a class. +/// +/// More information: +/// - [ECMAScript reference][spec] /// /// [spec]: https://tc39.es/ecma262/#prod-ClassElement #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive(Clone, Debug, PartialEq)] pub enum ClassElement { - /// A method definition, including `get` and `set` accessors. - MethodDefinition(PropertyName, MethodDefinition), - - /// A static method definition, accessible from the class constructor object. - StaticMethodDefinition(PropertyName, MethodDefinition), + /// A method definition. + MethodDefinition(ClassMethodDefinition), /// A field definition. FieldDefinition(PropertyName, Option), @@ -435,13 +324,6 @@ pub enum ClassElement { /// A static field definition, accessible from the class constructor object StaticFieldDefinition(PropertyName, Option), - /// A private method definition, only accessible inside the class declaration. - PrivateMethodDefinition(PrivateName, MethodDefinition), - - /// A private static method definition, only accessible from static methods and fields inside - /// the class declaration. - PrivateStaticMethodDefinition(PrivateName, MethodDefinition), - /// A private field definition, only accessible inside the class declaration. PrivateFieldDefinition(PrivateName, Option), @@ -453,15 +335,95 @@ pub enum ClassElement { StaticBlock(StaticBlockBody), } +impl ToIndentedString for ClassElement { + fn to_indented_string(&self, interner: &Interner, indent_n: usize) -> String { + let indentation = " ".repeat(indent_n + 1); + match self { + Self::MethodDefinition(m) => m.to_indented_string(interner, indent_n), + Self::FieldDefinition(name, field) => match field { + Some(expr) => { + format!( + "{indentation}{} = {};\n", + name.to_interned_string(interner), + expr.to_no_indent_string(interner, indent_n + 1) + ) + } + None => { + format!("{indentation}{};\n", name.to_interned_string(interner),) + } + }, + Self::StaticFieldDefinition(name, field) => match field { + Some(expr) => { + format!( + "{indentation}static {} = {};\n", + name.to_interned_string(interner), + expr.to_no_indent_string(interner, indent_n + 1) + ) + } + None => { + format!( + "{indentation}static {};\n", + name.to_interned_string(interner), + ) + } + }, + Self::PrivateFieldDefinition(name, field) => match field { + Some(expr) => { + format!( + "{indentation}#{} = {};\n", + interner.resolve_expect(name.description()), + expr.to_no_indent_string(interner, indent_n + 1) + ) + } + None => { + format!( + "{indentation}#{};\n", + interner.resolve_expect(name.description()), + ) + } + }, + Self::PrivateStaticFieldDefinition(name, field) => match field { + Some(expr) => { + format!( + "{indentation}static #{} = {};\n", + interner.resolve_expect(name.description()), + expr.to_no_indent_string(interner, indent_n + 1) + ) + } + None => { + format!( + "{indentation}static #{};\n", + interner.resolve_expect(name.description()), + ) + } + }, + Self::StaticBlock(body) => { + format!( + "{indentation}static {}\n", + block_to_string(body.statements(), interner, indent_n + 1) + ) + } + } + } +} + impl VisitWith for ClassElement { fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow where V: Visitor<'a>, { match self { - Self::MethodDefinition(pn, md) | Self::StaticMethodDefinition(pn, md) => { - try_break!(visitor.visit_property_name(pn)); - visitor.visit_method_definition(md) + Self::MethodDefinition(m) => { + match &m.name { + ClassElementName::PropertyName(pn) => { + try_break!(visitor.visit_property_name(pn)); + } + ClassElementName::PrivateName(pn) => { + try_break!(visitor.visit_private_name(pn)); + } + } + try_break!(visitor.visit_formal_parameter_list(&m.parameters)); + visitor.visit_script(&m.body) } Self::FieldDefinition(pn, maybe_expr) | Self::StaticFieldDefinition(pn, maybe_expr) => { try_break!(visitor.visit_property_name(pn)); @@ -471,11 +433,6 @@ impl VisitWith for ClassElement { ControlFlow::Continue(()) } } - Self::PrivateMethodDefinition(name, md) - | Self::PrivateStaticMethodDefinition(name, md) => { - try_break!(visitor.visit_private_name(name)); - visitor.visit_method_definition(md) - } Self::PrivateFieldDefinition(name, maybe_expr) | Self::PrivateStaticFieldDefinition(name, maybe_expr) => { try_break!(visitor.visit_private_name(name)); @@ -494,9 +451,17 @@ impl VisitWith for ClassElement { V: VisitorMut<'a>, { match self { - Self::MethodDefinition(pn, md) | Self::StaticMethodDefinition(pn, md) => { - try_break!(visitor.visit_property_name_mut(pn)); - visitor.visit_method_definition_mut(md) + Self::MethodDefinition(m) => { + match m.name { + ClassElementName::PropertyName(ref mut pn) => { + try_break!(visitor.visit_property_name_mut(pn)); + } + ClassElementName::PrivateName(ref mut pn) => { + try_break!(visitor.visit_private_name_mut(pn)); + } + } + try_break!(visitor.visit_formal_parameter_list_mut(&mut m.parameters)); + visitor.visit_script_mut(&mut m.body) } Self::FieldDefinition(pn, maybe_expr) | Self::StaticFieldDefinition(pn, maybe_expr) => { try_break!(visitor.visit_property_name_mut(pn)); @@ -506,11 +471,6 @@ impl VisitWith for ClassElement { ControlFlow::Continue(()) } } - Self::PrivateMethodDefinition(name, md) - | Self::PrivateStaticMethodDefinition(name, md) => { - try_break!(visitor.visit_private_name_mut(name)); - visitor.visit_method_definition_mut(md) - } Self::PrivateFieldDefinition(name, maybe_expr) | Self::PrivateStaticFieldDefinition(name, maybe_expr) => { try_break!(visitor.visit_private_name_mut(name)); @@ -525,6 +485,148 @@ impl VisitWith for ClassElement { } } +/// A method definition. +/// +/// This type is specific to class method definitions. +/// It includes private names and the information about whether the method is static or not. +/// +/// More information: +/// - [ECMAScript reference][spec] +/// +/// [spec]: https://tc39.es/ecma262/#prod-MethodDefinition +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +#[derive(Clone, Debug, PartialEq)] +pub struct ClassMethodDefinition { + name: ClassElementName, + parameters: FormalParameterList, + body: FunctionBody, + kind: MethodDefinitionKind, + is_static: bool, +} + +impl ClassMethodDefinition { + /// Creates a new class method definition. + #[inline] + #[must_use] + pub const fn new( + name: ClassElementName, + parameters: FormalParameterList, + body: FunctionBody, + kind: MethodDefinitionKind, + is_static: bool, + ) -> Self { + Self { + name, + parameters, + body, + kind, + is_static, + } + } + + /// Returns the name of the class method definition. + #[inline] + #[must_use] + pub const fn name(&self) -> &ClassElementName { + &self.name + } + + /// Returns the parameters of the class method definition. + #[inline] + #[must_use] + pub const fn parameters(&self) -> &FormalParameterList { + &self.parameters + } + + /// Returns the body of the class method definition. + #[inline] + #[must_use] + pub const fn body(&self) -> &FunctionBody { + &self.body + } + + /// Returns the kind of the class method definition. + #[inline] + #[must_use] + pub const fn kind(&self) -> MethodDefinitionKind { + self.kind + } + + /// Returns whether the class method definition is static. + #[inline] + #[must_use] + pub const fn is_static(&self) -> bool { + self.is_static + } + + /// Returns whether the class method definition is private. + #[inline] + #[must_use] + pub const fn is_private(&self) -> bool { + self.name.is_private() + } +} + +impl ToIndentedString for ClassMethodDefinition { + fn to_indented_string(&self, interner: &Interner, indent_n: usize) -> String { + let indentation = " ".repeat(indent_n + 1); + let prefix = match (self.is_static, &self.kind) { + (true, MethodDefinitionKind::Get) => "static get ", + (true, MethodDefinitionKind::Set) => "static set ", + (true, MethodDefinitionKind::Ordinary) => "static ", + (true, MethodDefinitionKind::Generator) => "static *", + (true, MethodDefinitionKind::AsyncGenerator) => "static async *", + (true, MethodDefinitionKind::Async) => "static async ", + (false, MethodDefinitionKind::Get) => "get ", + (false, MethodDefinitionKind::Set) => "set ", + (false, MethodDefinitionKind::Ordinary) => "", + (false, MethodDefinitionKind::Generator) => "*", + (false, MethodDefinitionKind::AsyncGenerator) => "async *", + (false, MethodDefinitionKind::Async) => "async ", + }; + let name = self.name.to_interned_string(interner); + let parameters = join_nodes(interner, self.parameters.as_ref()); + let body = block_to_string(self.body.statements(), interner, indent_n + 1); + format!("{indentation}{prefix}{name}({parameters}) {body}\n") + } +} + +/// A class element name. +/// +/// More information: +/// - [ECMAScript reference][spec] +/// +/// [spec]: https://tc39.es/ecma262/#prod-ClassElementName +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +#[derive(Clone, Debug, PartialEq)] +pub enum ClassElementName { + /// A property name. + PropertyName(PropertyName), + + /// A private name. + PrivateName(PrivateName), +} + +impl ClassElementName { + /// Returns whether the class element name is private. + #[inline] + #[must_use] + pub const fn is_private(&self) -> bool { + matches!(self, Self::PrivateName(_)) + } +} + +impl ToInternedString for ClassElementName { + fn to_interned_string(&self, interner: &Interner) -> String { + match &self { + Self::PropertyName(name) => name.to_interned_string(interner), + Self::PrivateName(name) => format!("#{}", interner.resolve_expect(name.description())), + } + } +} + /// A private name as defined by the [spec]. /// /// [spec]: https://tc39.es/ecma262/#sec-private-names diff --git a/core/ast/src/function/generator.rs b/core/ast/src/function/generator.rs index a36515072c..3c340b87a0 100644 --- a/core/ast/src/function/generator.rs +++ b/core/ast/src/function/generator.rs @@ -1,37 +1,127 @@ +use super::{FormalParameterList, FunctionBody}; use crate::{ block_to_string, expression::{Expression, Identifier}, - join_nodes, Declaration, + join_nodes, try_break, + visitor::{VisitWith, Visitor, VisitorMut}, + Declaration, }; +use boa_interner::{Interner, ToIndentedString}; use core::ops::ControlFlow; -use crate::try_break; -use crate::visitor::{VisitWith, Visitor, VisitorMut}; -use boa_interner::{Interner, ToIndentedString}; +/// A generator declaration. +/// +/// More information: +/// - [ECMAScript reference][spec] +/// - [MDN documentation][mdn] +/// +/// [spec]: https://tc39.es/ecma262/#prod-GeneratorDeclaration +/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function* +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +#[derive(Clone, Debug, PartialEq)] +pub struct GeneratorDeclaration { + name: Identifier, + parameters: FormalParameterList, + body: FunctionBody, +} -use super::{FormalParameterList, FunctionBody}; +impl GeneratorDeclaration { + /// Creates a new generator declaration. + #[inline] + #[must_use] + pub const fn new( + name: Identifier, + parameters: FormalParameterList, + body: FunctionBody, + ) -> Self { + Self { + name, + parameters, + body, + } + } + + /// Gets the name of the generator declaration. + #[inline] + #[must_use] + pub const fn name(&self) -> Identifier { + self.name + } + + /// Gets the list of parameters of the generator declaration. + #[inline] + #[must_use] + pub const fn parameters(&self) -> &FormalParameterList { + &self.parameters + } + + /// Gets the body of the generator declaration. + #[inline] + #[must_use] + pub const fn body(&self) -> &FunctionBody { + &self.body + } +} + +impl ToIndentedString for GeneratorDeclaration { + fn to_indented_string(&self, interner: &Interner, indentation: usize) -> String { + format!( + "function* {}({}) {}", + interner.resolve_expect(self.name.sym()), + join_nodes(interner, self.parameters.as_ref()), + block_to_string(self.body.statements(), interner, indentation) + ) + } +} + +impl VisitWith for GeneratorDeclaration { + fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow + where + V: Visitor<'a>, + { + try_break!(visitor.visit_identifier(&self.name)); + try_break!(visitor.visit_formal_parameter_list(&self.parameters)); + visitor.visit_script(&self.body) + } -/// A generator definition, as defined by the [spec]. + fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow + where + V: VisitorMut<'a>, + { + try_break!(visitor.visit_identifier_mut(&mut self.name)); + try_break!(visitor.visit_formal_parameter_list_mut(&mut self.parameters)); + visitor.visit_script_mut(&mut self.body) + } +} + +impl From for Declaration { + #[inline] + fn from(f: GeneratorDeclaration) -> Self { + Self::GeneratorDeclaration(f) + } +} + +/// A generator expression. /// -/// [Generators][mdn] are "resumable functions", which can be suspended during execution and -/// resumed at any later time. The main feature of a generator are `yield` expressions, which -/// specifies the value returned when a generator is suspended, and the point from which -/// the execution will resume. +/// More information: +/// - [ECMAScript reference][spec] +/// - [MDN documentation][mdn] /// -/// [spec]: https://tc39.es/ecma262/#sec-generator-function-definitions +/// [spec]: https://tc39.es/ecma262/#prod-GeneratorExpression /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function* #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive(Clone, Debug, PartialEq)] -pub struct Generator { - name: Option, +pub struct GeneratorExpression { + pub(crate) name: Option, parameters: FormalParameterList, body: FunctionBody, has_binding_identifier: bool, } -impl Generator { - /// Creates a new generator expression +impl GeneratorExpression { + /// Creates a new generator expression. #[inline] #[must_use] pub const fn new( @@ -48,28 +138,28 @@ impl Generator { } } - /// Gets the name of the generator declaration. + /// Gets the name of the generator expression. #[inline] #[must_use] pub const fn name(&self) -> Option { self.name } - /// Gets the list of parameters of the generator declaration. + /// Gets the list of parameters of the generator expression. #[inline] #[must_use] pub const fn parameters(&self) -> &FormalParameterList { &self.parameters } - /// Gets the body of the generator declaration. + /// Gets the body of the generator expression. #[inline] #[must_use] pub const fn body(&self) -> &FunctionBody { &self.body } - /// Returns whether the function expression has a binding identifier. + /// Returns whether the generator expression has a binding identifier. #[inline] #[must_use] pub const fn has_binding_identifier(&self) -> bool { @@ -77,7 +167,7 @@ impl Generator { } } -impl ToIndentedString for Generator { +impl ToIndentedString for GeneratorExpression { fn to_indented_string(&self, interner: &Interner, indentation: usize) -> String { let mut buf = "function*".to_owned(); if self.has_binding_identifier { @@ -95,21 +185,14 @@ impl ToIndentedString for Generator { } } -impl From for Expression { - #[inline] - fn from(expr: Generator) -> Self { - Self::Generator(expr) - } -} - -impl From for Declaration { +impl From for Expression { #[inline] - fn from(f: Generator) -> Self { - Self::Generator(f) + fn from(expr: GeneratorExpression) -> Self { + Self::GeneratorExpression(expr) } } -impl VisitWith for Generator { +impl VisitWith for GeneratorExpression { fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow where V: Visitor<'a>, diff --git a/core/ast/src/function/mod.rs b/core/ast/src/function/mod.rs index fc43553162..d245572f97 100644 --- a/core/ast/src/function/mod.rs +++ b/core/ast/src/function/mod.rs @@ -1,25 +1,27 @@ -//! Functions and classes nodes, as defined by the [spec]. +//! This module contains Function and Class AST nodes. //! -//! [Functions][func] are mainly subprograms that can be called by external code to execute a sequence of -//! statements (the *body* of the function). Javascript functions fall in several categories: +//! ECMAScript defines multiple types of functions and classes. +//! They are split into different AST nodes to reduce ambiguity and to make the AST more readable. //! -//! - [`Function`]s. -//! - [`ArrowFunction`]s. -//! - [`AsyncArrowFunction`]s. -//! - [`Generator`]s. -//! - [`AsyncFunction`]s. -//! - [`AsyncGenerator`]s. -//! -//! All of them can be declared in either [declaration][decl] form or [expression][expr] form, -//! except from `ArrowFunction`s and `AsyncArrowFunction`s, which can only be declared in expression form. -//! -//! This module also contains [`Class`]es, which are templates for creating objects. Classes -//! can also be declared in either declaration or expression form. -//! -//! [spec]: https://tc39.es/ecma262/#sec-ecmascript-language-functions-and-classes -//! [func]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions -//! [decl]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function -//! [expr]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/function +//! - Functions: +//! - [`FunctionDeclaration`] +//! - [`FunctionExpression`] +//! - Async functions: +//! - [`AsyncFunctionDeclaration`] +//! - [`AsyncFunctionExpression`] +//! - Generators +//! - [`GeneratorDeclaration`] +//! - [`GeneratorExpression`] +//! - Async Generators +//! - [`AsyncGeneratorDeclaration`] +//! - [`AsyncGeneratorExpression`] +//! - Arrow Functions +//! - [`ArrowFunction`] +//! - Async Arrow Functions +//! - [`AsyncArrowFunction`] +//! - Classes +//! - [`ClassDeclaration`] +//! - [`ClassExpression`] mod arrow_function; mod async_arrow_function; @@ -27,163 +29,22 @@ mod async_function; mod async_generator; mod class; mod generator; +mod ordinary_function; mod parameters; pub use arrow_function::ArrowFunction; pub use async_arrow_function::AsyncArrowFunction; -pub use async_function::AsyncFunction; -pub use async_generator::AsyncGenerator; -pub use class::{Class, ClassElement, PrivateName}; -use core::ops::ControlFlow; -pub use generator::Generator; +pub use async_function::{AsyncFunctionDeclaration, AsyncFunctionExpression}; +pub use async_generator::{AsyncGeneratorDeclaration, AsyncGeneratorExpression}; +pub use class::{ + ClassDeclaration, ClassElement, ClassElementName, ClassExpression, ClassMethodDefinition, + PrivateName, +}; +pub use generator::{GeneratorDeclaration, GeneratorExpression}; +pub use ordinary_function::{FunctionDeclaration, FunctionExpression}; pub use parameters::{FormalParameter, FormalParameterList, FormalParameterListFlags}; -use crate::visitor::{VisitWith, Visitor, VisitorMut}; -use crate::{block_to_string, join_nodes}; -use crate::{try_break, Script}; -use boa_interner::{Interner, ToIndentedString}; - -use super::expression::{Expression, Identifier}; -use super::Declaration; - -/// A function definition, as defined by the [spec]. -/// -/// By default, functions return `undefined`. To return any other value, the function must have -/// a return statement that specifies the value to return. -/// -/// More information: -/// - [MDN documentation][mdn] -/// -/// [spec]: https://tc39.es/ecma262/#sec-function-definitions -/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[derive(Clone, Debug, PartialEq)] -pub struct Function { - name: Option, - parameters: FormalParameterList, - body: FunctionBody, - has_binding_identifier: bool, -} - -impl Function { - /// Creates a new function expression. - #[inline] - #[must_use] - pub const fn new( - name: Option, - parameters: FormalParameterList, - body: FunctionBody, - ) -> Self { - Self { - name, - parameters, - body, - has_binding_identifier: false, - } - } - - /// Creates a new function expression with an expression binding identifier. - #[inline] - #[must_use] - pub const fn new_with_binding_identifier( - name: Option, - parameters: FormalParameterList, - body: FunctionBody, - has_binding_identifier: bool, - ) -> Self { - Self { - name, - parameters, - body, - has_binding_identifier, - } - } - - /// Gets the name of the function declaration. - #[inline] - #[must_use] - pub const fn name(&self) -> Option { - self.name - } - - /// Gets the list of parameters of the function declaration. - #[inline] - #[must_use] - pub const fn parameters(&self) -> &FormalParameterList { - &self.parameters - } - - /// Gets the body of the function declaration. - #[inline] - #[must_use] - pub const fn body(&self) -> &FunctionBody { - &self.body - } - - /// Returns whether the function expression has a binding identifier. - #[inline] - #[must_use] - pub const fn has_binding_identifier(&self) -> bool { - self.has_binding_identifier - } -} - -impl ToIndentedString for Function { - fn to_indented_string(&self, interner: &Interner, indentation: usize) -> String { - let mut buf = "function".to_owned(); - if self.has_binding_identifier { - if let Some(name) = self.name { - buf.push_str(&format!(" {}", interner.resolve_expect(name.sym()))); - } - } - buf.push_str(&format!( - "({}) {}", - join_nodes(interner, self.parameters.as_ref()), - block_to_string(self.body.statements(), interner, indentation) - )); - - buf - } -} - -impl From for Expression { - #[inline] - fn from(expr: Function) -> Self { - Self::Function(expr) - } -} - -impl From for Declaration { - #[inline] - fn from(f: Function) -> Self { - Self::Function(f) - } -} - -impl VisitWith for Function { - fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow - where - V: Visitor<'a>, - { - if let Some(ident) = &self.name { - try_break!(visitor.visit_identifier(ident)); - } - try_break!(visitor.visit_formal_parameter_list(&self.parameters)); - visitor.visit_script(&self.body) - } - - fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow - where - V: VisitorMut<'a>, - { - if let Some(ident) = &mut self.name { - try_break!(visitor.visit_identifier_mut(ident)); - } - try_break!(visitor.visit_formal_parameter_list_mut(&mut self.parameters)); - visitor.visit_script_mut(&mut self.body) - } -} +use crate::Script; /// A Function body. /// diff --git a/core/ast/src/function/ordinary_function.rs b/core/ast/src/function/ordinary_function.rs new file mode 100644 index 0000000000..9ecaa36f43 --- /dev/null +++ b/core/ast/src/function/ordinary_function.rs @@ -0,0 +1,217 @@ +use super::{FormalParameterList, FunctionBody}; +use crate::{ + block_to_string, + expression::{Expression, Identifier}, + join_nodes, try_break, + visitor::{VisitWith, Visitor, VisitorMut}, + Declaration, +}; +use boa_interner::{Interner, ToIndentedString}; +use core::ops::ControlFlow; + +/// A function declaration. +/// +/// More information: +/// - [ECMAScript reference][spec] +/// - [MDN documentation][mdn] +/// +/// [spec]: https://tc39.es/ecma262/#prod-FunctionDeclaration +/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +#[derive(Clone, Debug, PartialEq)] +pub struct FunctionDeclaration { + name: Identifier, + parameters: FormalParameterList, + body: FunctionBody, +} + +impl FunctionDeclaration { + /// Creates a new function declaration. + #[inline] + #[must_use] + pub const fn new( + name: Identifier, + parameters: FormalParameterList, + body: FunctionBody, + ) -> Self { + Self { + name, + parameters, + body, + } + } + + /// Gets the name of the function declaration. + #[inline] + #[must_use] + pub const fn name(&self) -> Identifier { + self.name + } + + /// Gets the list of parameters of the function declaration. + #[inline] + #[must_use] + pub const fn parameters(&self) -> &FormalParameterList { + &self.parameters + } + + /// Gets the body of the function declaration. + #[inline] + #[must_use] + pub const fn body(&self) -> &FunctionBody { + &self.body + } +} + +impl ToIndentedString for FunctionDeclaration { + fn to_indented_string(&self, interner: &Interner, indentation: usize) -> String { + format!( + "function {}({}) {}", + interner.resolve_expect(self.name.sym()), + join_nodes(interner, self.parameters.as_ref()), + block_to_string(self.body.statements(), interner, indentation) + ) + } +} + +impl VisitWith for FunctionDeclaration { + fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow + where + V: Visitor<'a>, + { + try_break!(visitor.visit_identifier(&self.name)); + try_break!(visitor.visit_formal_parameter_list(&self.parameters)); + visitor.visit_script(&self.body) + } + + fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow + where + V: VisitorMut<'a>, + { + try_break!(visitor.visit_identifier_mut(&mut self.name)); + try_break!(visitor.visit_formal_parameter_list_mut(&mut self.parameters)); + visitor.visit_script_mut(&mut self.body) + } +} + +impl From for Declaration { + #[inline] + fn from(f: FunctionDeclaration) -> Self { + Self::FunctionDeclaration(f) + } +} + +/// A function expression. +/// +/// More information: +/// - [ECMAScript reference][spec] +/// - [MDN documentation][mdn] +/// +/// [spec]: https://tc39.es/ecma262/#prod-FunctionExpression +/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +#[derive(Clone, Debug, PartialEq)] +pub struct FunctionExpression { + pub(crate) name: Option, + parameters: FormalParameterList, + body: FunctionBody, + has_binding_identifier: bool, +} + +impl FunctionExpression { + /// Creates a new function expression. + #[inline] + #[must_use] + pub const fn new( + name: Option, + parameters: FormalParameterList, + body: FunctionBody, + has_binding_identifier: bool, + ) -> Self { + Self { + name, + parameters, + body, + has_binding_identifier, + } + } + + /// Gets the name of the function expression. + #[inline] + #[must_use] + pub const fn name(&self) -> Option { + self.name + } + + /// Gets the list of parameters of the function expression. + #[inline] + #[must_use] + pub const fn parameters(&self) -> &FormalParameterList { + &self.parameters + } + + /// Gets the body of the function expression. + #[inline] + #[must_use] + pub const fn body(&self) -> &FunctionBody { + &self.body + } + + /// Returns whether the function expression has a binding identifier. + #[inline] + #[must_use] + pub const fn has_binding_identifier(&self) -> bool { + self.has_binding_identifier + } +} + +impl ToIndentedString for FunctionExpression { + fn to_indented_string(&self, interner: &Interner, indentation: usize) -> String { + let mut buf = "function".to_owned(); + if self.has_binding_identifier { + if let Some(name) = self.name { + buf.push_str(&format!(" {}", interner.resolve_expect(name.sym()))); + } + } + buf.push_str(&format!( + "({}) {}", + join_nodes(interner, self.parameters.as_ref()), + block_to_string(self.body.statements(), interner, indentation) + )); + + buf + } +} + +impl From for Expression { + #[inline] + fn from(expr: FunctionExpression) -> Self { + Self::FunctionExpression(expr) + } +} + +impl VisitWith for FunctionExpression { + fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow + where + V: Visitor<'a>, + { + if let Some(ident) = &self.name { + try_break!(visitor.visit_identifier(ident)); + } + try_break!(visitor.visit_formal_parameter_list(&self.parameters)); + visitor.visit_script(&self.body) + } + + fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow + where + V: VisitorMut<'a>, + { + if let Some(ident) = &mut self.name { + try_break!(visitor.visit_identifier_mut(ident)); + } + try_break!(visitor.visit_formal_parameter_list_mut(&mut self.parameters)); + visitor.visit_script_mut(&mut self.body) + } +} diff --git a/core/ast/src/module_item_list/mod.rs b/core/ast/src/module_item_list/mod.rs index 5c7001cef8..828789be0e 100644 --- a/core/ast/src/module_item_list/mod.rs +++ b/core/ast/src/module_item_list/mod.rs @@ -5,12 +5,6 @@ //! //! [spec]: https://tc39.es/ecma262/#sec-modules -use std::{convert::Infallible, hash::BuildHasherDefault, ops::ControlFlow}; - -use boa_interner::Sym; -use indexmap::IndexSet; -use rustc_hash::{FxHashSet, FxHasher}; - use crate::{ declaration::{ ExportDeclaration, ExportEntry, ExportSpecifier, ImportDeclaration, ImportEntry, @@ -23,6 +17,10 @@ use crate::{ visitor::{VisitWith, Visitor, VisitorMut}, StatementListItem, }; +use boa_interner::Sym; +use indexmap::IndexSet; +use rustc_hash::{FxHashSet, FxHasher}; +use std::{convert::Infallible, hash::BuildHasherDefault, ops::ControlFlow}; /// Module item list AST node. /// @@ -106,10 +104,10 @@ impl ModuleItemList { ExportDeclaration::Declaration(decl) => { BoundNamesVisitor(self.0).visit_declaration(decl) } - ExportDeclaration::DefaultFunction(_) - | ExportDeclaration::DefaultGenerator(_) - | ExportDeclaration::DefaultAsyncFunction(_) - | ExportDeclaration::DefaultAsyncGenerator(_) + ExportDeclaration::DefaultFunctionDeclaration(_) + | ExportDeclaration::DefaultGeneratorDeclaration(_) + | ExportDeclaration::DefaultAsyncFunctionDeclaration(_) + | ExportDeclaration::DefaultAsyncGeneratorDeclaration(_) | ExportDeclaration::DefaultClassDeclaration(_) | ExportDeclaration::DefaultAssignmentExpression(_) => { self.0.push(Sym::DEFAULT); @@ -178,15 +176,14 @@ impl ModuleItemList { ExportDeclaration::Declaration(decl) => { return BoundNamesVisitor(self.0).visit_declaration(decl); } - ExportDeclaration::DefaultFunction(f) => f.name(), - ExportDeclaration::DefaultGenerator(g) => g.name(), - ExportDeclaration::DefaultAsyncFunction(af) => af.name(), - ExportDeclaration::DefaultAsyncGenerator(ag) => ag.name(), + ExportDeclaration::DefaultFunctionDeclaration(f) => f.name(), + ExportDeclaration::DefaultGeneratorDeclaration(g) => g.name(), + ExportDeclaration::DefaultAsyncFunctionDeclaration(af) => af.name(), + ExportDeclaration::DefaultAsyncGeneratorDeclaration(ag) => ag.name(), ExportDeclaration::DefaultClassDeclaration(cl) => cl.name(), }; - self.0 - .insert(name.unwrap_or_else(|| Identifier::new(Sym::DEFAULT_EXPORT))); + self.0.insert(name); ControlFlow::Continue(()) } @@ -388,23 +385,18 @@ impl ModuleItemList { } return ControlFlow::Continue(()); } - ExportDeclaration::DefaultFunction(f) => f.name(), - ExportDeclaration::DefaultGenerator(g) => g.name(), - ExportDeclaration::DefaultAsyncFunction(af) => af.name(), - ExportDeclaration::DefaultAsyncGenerator(ag) => ag.name(), + ExportDeclaration::DefaultFunctionDeclaration(f) => f.name(), + ExportDeclaration::DefaultGeneratorDeclaration(g) => g.name(), + ExportDeclaration::DefaultAsyncFunctionDeclaration(af) => af.name(), + ExportDeclaration::DefaultAsyncGeneratorDeclaration(ag) => ag.name(), ExportDeclaration::DefaultClassDeclaration(c) => c.name(), ExportDeclaration::DefaultAssignmentExpression(_) => { - Some(Identifier::from(Sym::DEFAULT_EXPORT)) + Identifier::from(Sym::DEFAULT_EXPORT) } }; - self.0.push( - LocalExportEntry::new( - name.unwrap_or_else(|| Identifier::from(Sym::DEFAULT_EXPORT)), - Sym::DEFAULT, - ) - .into(), - ); + self.0 + .push(LocalExportEntry::new(name, Sym::DEFAULT).into()); ControlFlow::Continue(()) } diff --git a/core/ast/src/operations.rs b/core/ast/src/operations.rs index c9836ba1fa..f74c6ac8ba 100644 --- a/core/ast/src/operations.rs +++ b/core/ast/src/operations.rs @@ -14,14 +14,16 @@ use crate::{ }, expression::{ access::{PrivatePropertyAccess, SuperPropertyAccess}, + literal::PropertyDefinition, operator::BinaryInPrivate, Await, Identifier, OptionalOperationKind, SuperCall, Yield, }, function::{ - ArrowFunction, AsyncArrowFunction, AsyncFunction, AsyncGenerator, Class, ClassElement, - Function, Generator, + ArrowFunction, AsyncArrowFunction, AsyncFunctionDeclaration, AsyncFunctionExpression, + AsyncGeneratorDeclaration, AsyncGeneratorExpression, ClassDeclaration, ClassElement, + ClassElementName, ClassExpression, FormalParameterList, FunctionDeclaration, + FunctionExpression, GeneratorDeclaration, GeneratorExpression, }, - property::{MethodDefinition, PropertyDefinition}, statement::{ iteration::{ForLoopInitializer, IterableLoopInitializer}, LabelledItem, @@ -87,23 +89,81 @@ where ControlFlow::Continue(()) } - fn visit_function(&mut self, _: &'ast Function) -> ControlFlow { + fn visit_function_expression( + &mut self, + _: &'ast FunctionExpression, + ) -> ControlFlow { + ControlFlow::Continue(()) + } + + fn visit_function_declaration( + &mut self, + _: &'ast FunctionDeclaration, + ) -> ControlFlow { + ControlFlow::Continue(()) + } + + fn visit_async_function_expression( + &mut self, + _: &'ast AsyncFunctionExpression, + ) -> ControlFlow { + ControlFlow::Continue(()) + } + + fn visit_async_function_declaration( + &mut self, + _: &'ast AsyncFunctionDeclaration, + ) -> ControlFlow { ControlFlow::Continue(()) } - fn visit_async_function(&mut self, _: &'ast AsyncFunction) -> ControlFlow { + fn visit_generator_expression( + &mut self, + _: &'ast GeneratorExpression, + ) -> ControlFlow { ControlFlow::Continue(()) } - fn visit_generator(&mut self, _: &'ast Generator) -> ControlFlow { + fn visit_generator_declaration( + &mut self, + _: &'ast GeneratorDeclaration, + ) -> ControlFlow { ControlFlow::Continue(()) } - fn visit_async_generator(&mut self, _: &'ast AsyncGenerator) -> ControlFlow { + fn visit_async_generator_expression( + &mut self, + _: &'ast AsyncGeneratorExpression, + ) -> ControlFlow { ControlFlow::Continue(()) } - fn visit_class(&mut self, node: &'ast Class) -> ControlFlow { + fn visit_async_generator_declaration( + &mut self, + _: &'ast AsyncGeneratorDeclaration, + ) -> ControlFlow { + ControlFlow::Continue(()) + } + + fn visit_class_expression( + &mut self, + node: &'ast ClassExpression, + ) -> ControlFlow { + if !node.elements().is_empty() && self.0 == ContainsSymbol::ClassBody { + return ControlFlow::Break(()); + } + + if node.super_ref().is_some() && self.0 == ContainsSymbol::ClassHeritage { + return ControlFlow::Break(()); + } + + node.visit_with(self) + } + + fn visit_class_declaration( + &mut self, + node: &'ast ClassDeclaration, + ) -> ControlFlow { if !node.elements().is_empty() && self.0 == ContainsSymbol::ClassBody { return ControlFlow::Break(()); } @@ -118,9 +178,14 @@ where // `ComputedPropertyContains`: https://tc39.es/ecma262/#sec-static-semantics-computedpropertycontains fn visit_class_element(&mut self, node: &'ast ClassElement) -> ControlFlow { match node { - ClassElement::MethodDefinition(name, _) - | ClassElement::StaticMethodDefinition(name, _) - | ClassElement::FieldDefinition(name, _) + ClassElement::MethodDefinition(m) => { + if let ClassElementName::PropertyName(name) = m.name() { + name.visit_with(self) + } else { + ControlFlow::Continue(()) + } + } + ClassElement::FieldDefinition(name, _) | ClassElement::StaticFieldDefinition(name, _) => name.visit_with(self), _ => ControlFlow::Continue(()), } @@ -130,11 +195,11 @@ where &mut self, node: &'ast PropertyDefinition, ) -> ControlFlow { - if let PropertyDefinition::MethodDefinition(name, _) = node { + if let PropertyDefinition::MethodDefinition(m) = node { if self.0 == ContainsSymbol::MethodDefinition { return ControlFlow::Break(()); } - return name.visit_with(self); + return m.name().visit_with(self); } node.visit_with(self) @@ -250,27 +315,67 @@ where } } - fn visit_function(&mut self, _: &'ast Function) -> ControlFlow { + fn visit_function_expression( + &mut self, + _: &'ast FunctionExpression, + ) -> ControlFlow { + ControlFlow::Continue(()) + } + + fn visit_function_declaration( + &mut self, + _: &'ast FunctionDeclaration, + ) -> ControlFlow { ControlFlow::Continue(()) } - fn visit_async_function(&mut self, _: &'ast AsyncFunction) -> ControlFlow { + fn visit_async_function_expression( + &mut self, + _: &'ast AsyncFunctionExpression, + ) -> ControlFlow { ControlFlow::Continue(()) } - fn visit_generator(&mut self, _: &'ast Generator) -> ControlFlow { + fn visit_async_function_declaration( + &mut self, + _: &'ast AsyncFunctionDeclaration, + ) -> ControlFlow { ControlFlow::Continue(()) } - fn visit_async_generator(&mut self, _: &'ast AsyncGenerator) -> ControlFlow { + fn visit_generator_expression( + &mut self, + _: &'ast GeneratorExpression, + ) -> ControlFlow { + ControlFlow::Continue(()) + } + + fn visit_generator_declaration( + &mut self, + _: &'ast GeneratorDeclaration, + ) -> ControlFlow { + ControlFlow::Continue(()) + } + + fn visit_async_generator_expression( + &mut self, + _: &'ast AsyncGeneratorExpression, + ) -> ControlFlow { + ControlFlow::Continue(()) + } + + fn visit_async_generator_declaration( + &mut self, + _: &'ast AsyncGeneratorDeclaration, + ) -> ControlFlow { ControlFlow::Continue(()) } fn visit_class_element(&mut self, node: &'ast ClassElement) -> ControlFlow { - match node { - ClassElement::MethodDefinition(name, _) - | ClassElement::StaticMethodDefinition(name, _) => return name.visit_with(self), - _ => {} + if let ClassElement::MethodDefinition(m) = node { + if let ClassElementName::PropertyName(name) = m.name() { + return name.visit_with(self); + } } node.visit_with(self) } @@ -279,8 +384,8 @@ where &mut self, node: &'ast PropertyDefinition, ) -> ControlFlow { - if let PropertyDefinition::MethodDefinition(name, _) = node { - name.visit_with(self) + if let PropertyDefinition::MethodDefinition(m) = node { + m.name().visit_with(self) } else { node.visit_with(self) } @@ -296,15 +401,8 @@ where /// [spec]: https://tc39.es/ecma262/#sec-static-semantics-hasdirectsuper #[must_use] #[inline] -pub fn has_direct_super(method: &MethodDefinition) -> bool { - match method { - MethodDefinition::Get(f) | MethodDefinition::Set(f) | MethodDefinition::Ordinary(f) => { - contains(f, ContainsSymbol::SuperCall) - } - MethodDefinition::Generator(f) => contains(f, ContainsSymbol::SuperCall), - MethodDefinition::AsyncGenerator(f) => contains(f, ContainsSymbol::SuperCall), - MethodDefinition::Async(f) => contains(f, ContainsSymbol::SuperCall), - } +pub fn has_direct_super_new(params: &FormalParameterList, body: &Script) -> bool { + contains(params, ContainsSymbol::SuperCall) || contains(body, ContainsSymbol::SuperCall) } /// A container that [`BoundNamesVisitor`] can use to push the found identifiers. @@ -352,41 +450,96 @@ impl<'ast, T: IdentList> Visitor<'ast> for BoundNamesVisitor<'_, T> { ControlFlow::Continue(()) } - fn visit_function(&mut self, node: &'ast Function) -> ControlFlow { + fn visit_function_expression( + &mut self, + node: &'ast FunctionExpression, + ) -> ControlFlow { if let Some(ident) = node.name() { self.0.add(ident.sym(), true); } ControlFlow::Continue(()) } - fn visit_generator(&mut self, node: &'ast Generator) -> ControlFlow { + fn visit_function_declaration( + &mut self, + node: &'ast FunctionDeclaration, + ) -> ControlFlow { + self.0.add(node.name().sym(), true); + ControlFlow::Continue(()) + } + + fn visit_generator_expression( + &mut self, + node: &'ast GeneratorExpression, + ) -> ControlFlow { if let Some(ident) = node.name() { self.0.add(ident.sym(), false); } ControlFlow::Continue(()) } - fn visit_async_function(&mut self, node: &'ast AsyncFunction) -> ControlFlow { + fn visit_generator_declaration( + &mut self, + node: &'ast GeneratorDeclaration, + ) -> ControlFlow { + self.0.add(node.name().sym(), false); + ControlFlow::Continue(()) + } + + fn visit_async_function_expression( + &mut self, + node: &'ast AsyncFunctionExpression, + ) -> ControlFlow { if let Some(ident) = node.name() { self.0.add(ident.sym(), false); } ControlFlow::Continue(()) } - fn visit_async_generator(&mut self, node: &'ast AsyncGenerator) -> ControlFlow { + fn visit_async_function_declaration( + &mut self, + node: &'ast AsyncFunctionDeclaration, + ) -> ControlFlow { + self.0.add(node.name().sym(), false); + ControlFlow::Continue(()) + } + + fn visit_async_generator_expression( + &mut self, + node: &'ast AsyncGeneratorExpression, + ) -> ControlFlow { if let Some(ident) = node.name() { self.0.add(ident.sym(), false); } ControlFlow::Continue(()) } - fn visit_class(&mut self, node: &'ast Class) -> ControlFlow { + fn visit_async_generator_declaration( + &mut self, + node: &'ast AsyncGeneratorDeclaration, + ) -> ControlFlow { + self.0.add(node.name().sym(), false); + ControlFlow::Continue(()) + } + + fn visit_class_expression( + &mut self, + node: &'ast ClassExpression, + ) -> ControlFlow { if let Some(ident) = node.name() { self.0.add(ident.sym(), false); } ControlFlow::Continue(()) } + fn visit_class_declaration( + &mut self, + node: &'ast ClassDeclaration, + ) -> ControlFlow { + self.0.add(node.name().sym(), false); + ControlFlow::Continue(()) + } + fn visit_export_declaration( &mut self, node: &'ast ExportDeclaration, @@ -394,31 +547,20 @@ impl<'ast, T: IdentList> Visitor<'ast> for BoundNamesVisitor<'_, T> { match node { ExportDeclaration::VarStatement(var) => try_break!(self.visit_var_declaration(var)), ExportDeclaration::Declaration(decl) => try_break!(self.visit_declaration(decl)), - ExportDeclaration::DefaultFunction(f) => { - self.0 - .add(f.name().map_or(Sym::DEFAULT_EXPORT, Identifier::sym), true); + ExportDeclaration::DefaultFunctionDeclaration(f) => { + self.0.add(f.name().sym(), true); } - ExportDeclaration::DefaultGenerator(g) => { - self.0 - .add(g.name().map_or(Sym::DEFAULT_EXPORT, Identifier::sym), false); + ExportDeclaration::DefaultGeneratorDeclaration(g) => { + self.0.add(g.name().sym(), false); } - ExportDeclaration::DefaultAsyncFunction(af) => { - self.0.add( - af.name().map_or(Sym::DEFAULT_EXPORT, Identifier::sym), - false, - ); + ExportDeclaration::DefaultAsyncFunctionDeclaration(af) => { + self.0.add(af.name().sym(), false); } - ExportDeclaration::DefaultAsyncGenerator(ag) => { - self.0.add( - ag.name().map_or(Sym::DEFAULT_EXPORT, Identifier::sym), - false, - ); + ExportDeclaration::DefaultAsyncGeneratorDeclaration(ag) => { + self.0.add(ag.name().sym(), false); } ExportDeclaration::DefaultClassDeclaration(cl) => { - self.0.add( - cl.name().map_or(Sym::DEFAULT_EXPORT, Identifier::sym), - false, - ); + self.0.add(cl.name().sym(), false); } ExportDeclaration::DefaultAssignmentExpression(_) => { self.0.add(Sym::DEFAULT_EXPORT, false); @@ -502,24 +644,66 @@ impl<'ast, T: IdentList> Visitor<'ast> for LexicallyDeclaredNamesVisitor<'_, T> fn visit_labelled_item(&mut self, node: &'ast LabelledItem) -> ControlFlow { match node { - LabelledItem::Function(f) => BoundNamesVisitor(self.0).visit_function(f), + LabelledItem::FunctionDeclaration(f) => { + BoundNamesVisitor(self.0).visit_function_declaration(f) + } LabelledItem::Statement(_) => ControlFlow::Continue(()), } } - fn visit_function(&mut self, node: &'ast Function) -> ControlFlow { + fn visit_function_expression( + &mut self, + node: &'ast FunctionExpression, + ) -> ControlFlow { self.visit_script(node.body()) } - fn visit_async_function(&mut self, node: &'ast AsyncFunction) -> ControlFlow { + fn visit_function_declaration( + &mut self, + node: &'ast FunctionDeclaration, + ) -> ControlFlow { self.visit_script(node.body()) } - fn visit_generator(&mut self, node: &'ast Generator) -> ControlFlow { + fn visit_async_function_expression( + &mut self, + node: &'ast AsyncFunctionExpression, + ) -> ControlFlow { self.visit_script(node.body()) } - fn visit_async_generator(&mut self, node: &'ast AsyncGenerator) -> ControlFlow { + fn visit_async_function_declaration( + &mut self, + node: &'ast AsyncFunctionDeclaration, + ) -> ControlFlow { + self.visit_script(node.body()) + } + + fn visit_generator_expression( + &mut self, + node: &'ast GeneratorExpression, + ) -> ControlFlow { + self.visit_script(node.body()) + } + + fn visit_generator_declaration( + &mut self, + node: &'ast GeneratorDeclaration, + ) -> ControlFlow { + self.visit_script(node.body()) + } + + fn visit_async_generator_expression( + &mut self, + node: &'ast AsyncGeneratorExpression, + ) -> ControlFlow { + self.visit_script(node.body()) + } + + fn visit_async_generator_declaration( + &mut self, + node: &'ast AsyncGeneratorDeclaration, + ) -> ControlFlow { self.visit_script(node.body()) } @@ -730,7 +914,7 @@ impl<'ast> Visitor<'ast> for VarDeclaredNamesVisitor<'_> { fn visit_labelled_item(&mut self, node: &'ast LabelledItem) -> ControlFlow { match node { - LabelledItem::Function(_) => ControlFlow::Continue(()), + LabelledItem::FunctionDeclaration(_) => ControlFlow::Continue(()), LabelledItem::Statement(stmt) => self.visit(stmt), } } @@ -745,19 +929,59 @@ impl<'ast> Visitor<'ast> for VarDeclaredNamesVisitor<'_> { self.visit(node.block()) } - fn visit_function(&mut self, node: &'ast Function) -> ControlFlow { + fn visit_function_expression( + &mut self, + node: &'ast FunctionExpression, + ) -> ControlFlow { + self.visit_script(node.body()) + } + + fn visit_function_declaration( + &mut self, + node: &'ast FunctionDeclaration, + ) -> ControlFlow { self.visit_script(node.body()) } - fn visit_async_function(&mut self, node: &'ast AsyncFunction) -> ControlFlow { + fn visit_async_function_expression( + &mut self, + node: &'ast AsyncFunctionExpression, + ) -> ControlFlow { self.visit_script(node.body()) } - fn visit_generator(&mut self, node: &'ast Generator) -> ControlFlow { + fn visit_async_function_declaration( + &mut self, + node: &'ast AsyncFunctionDeclaration, + ) -> ControlFlow { self.visit_script(node.body()) } - fn visit_async_generator(&mut self, node: &'ast AsyncGenerator) -> ControlFlow { + fn visit_generator_expression( + &mut self, + node: &'ast GeneratorExpression, + ) -> ControlFlow { + self.visit_script(node.body()) + } + + fn visit_generator_declaration( + &mut self, + node: &'ast GeneratorDeclaration, + ) -> ControlFlow { + self.visit_script(node.body()) + } + + fn visit_async_generator_expression( + &mut self, + node: &'ast AsyncGeneratorExpression, + ) -> ControlFlow { + self.visit_script(node.body()) + } + + fn visit_async_generator_declaration( + &mut self, + node: &'ast AsyncGeneratorDeclaration, + ) -> ControlFlow { self.visit_script(node.body()) } @@ -815,12 +1039,12 @@ fn top_level_lexicals(stmts: &StatementList, names: &mut T) { // Note // At the top level of a function, or script, function declarations are treated like // var declarations rather than like lexical declarations. - Declaration::Function(_) - | Declaration::Generator(_) - | Declaration::AsyncFunction(_) - | Declaration::AsyncGenerator(_) => {} - Declaration::Class(class) => { - BoundNamesVisitor(names).visit_class(class); + Declaration::FunctionDeclaration(_) + | Declaration::GeneratorDeclaration(_) + | Declaration::AsyncFunctionDeclaration(_) + | Declaration::AsyncGeneratorDeclaration(_) => {} + Declaration::ClassDeclaration(class) => { + BoundNamesVisitor(names).visit_class_declaration(class); } Declaration::Lexical(decl) => { BoundNamesVisitor(names).visit_lexical_declaration(decl); @@ -843,27 +1067,27 @@ fn top_level_vars(stmts: &StatementList, names: &mut FxHashSet) { // Note // At the top level of a function, or script, function declarations are treated like // var declarations rather than like lexical declarations. - Declaration::Function(f) => { - BoundNamesVisitor(names).visit_function(f); + Declaration::FunctionDeclaration(f) => { + BoundNamesVisitor(names).visit_function_declaration(f); } - Declaration::Generator(f) => { - BoundNamesVisitor(names).visit_generator(f); + Declaration::GeneratorDeclaration(f) => { + BoundNamesVisitor(names).visit_generator_declaration(f); } - Declaration::AsyncFunction(f) => { - BoundNamesVisitor(names).visit_async_function(f); + Declaration::AsyncFunctionDeclaration(f) => { + BoundNamesVisitor(names).visit_async_function_declaration(f); } - Declaration::AsyncGenerator(f) => { - BoundNamesVisitor(names).visit_async_generator(f); + Declaration::AsyncGeneratorDeclaration(f) => { + BoundNamesVisitor(names).visit_async_generator_declaration(f); } - Declaration::Class(_) | Declaration::Lexical(_) => {} + Declaration::ClassDeclaration(_) | Declaration::Lexical(_) => {} } } StatementListItem::Statement(stmt) => { let mut stmt = Some(stmt); while let Some(Statement::Labelled(labelled)) = stmt { match labelled.item() { - LabelledItem::Function(f) => { - BoundNamesVisitor(names).visit_function(f); + LabelledItem::FunctionDeclaration(f) => { + BoundNamesVisitor(names).visit_function_declaration(f); stmt = None; } LabelledItem::Statement(s) => stmt = Some(s), @@ -898,7 +1122,10 @@ struct AllPrivateIdentifiersValidVisitor(Vec); impl<'ast> Visitor<'ast> for AllPrivateIdentifiersValidVisitor { type BreakTy = (); - fn visit_class(&mut self, node: &'ast Class) -> ControlFlow { + fn visit_class_expression( + &mut self, + node: &'ast ClassExpression, + ) -> ControlFlow { if let Some(node) = node.super_ref() { try_break!(self.visit(node)); } @@ -906,9 +1133,12 @@ impl<'ast> Visitor<'ast> for AllPrivateIdentifiersValidVisitor { let mut names = self.0.clone(); for element in node.elements() { match element { - ClassElement::PrivateMethodDefinition(name, _) - | ClassElement::PrivateStaticMethodDefinition(name, _) - | ClassElement::PrivateFieldDefinition(name, _) + ClassElement::MethodDefinition(m) => { + if let ClassElementName::PrivateName(name) = m.name() { + names.push(name.description()); + } + } + ClassElement::PrivateFieldDefinition(name, _) | ClassElement::PrivateStaticFieldDefinition(name, _) => { names.push(name.description()); } @@ -924,10 +1154,12 @@ impl<'ast> Visitor<'ast> for AllPrivateIdentifiersValidVisitor { for element in node.elements() { match element { - ClassElement::MethodDefinition(name, method) - | ClassElement::StaticMethodDefinition(name, method) => { - try_break!(visitor.visit(name)); - try_break!(visitor.visit(method)); + ClassElement::MethodDefinition(m) => { + if let ClassElementName::PropertyName(name) = m.name() { + try_break!(visitor.visit(name)); + } + try_break!(visitor.visit(m.parameters())); + try_break!(visitor.visit(m.body())); } ClassElement::FieldDefinition(name, expression) | ClassElement::StaticFieldDefinition(name, expression) => { @@ -936,9 +1168,66 @@ impl<'ast> Visitor<'ast> for AllPrivateIdentifiersValidVisitor { try_break!(visitor.visit(expression)); } } - ClassElement::PrivateMethodDefinition(_, method) - | ClassElement::PrivateStaticMethodDefinition(_, method) => { - try_break!(visitor.visit(method)); + ClassElement::PrivateFieldDefinition(_, expression) + | ClassElement::PrivateStaticFieldDefinition(_, expression) => { + if let Some(expression) = expression { + try_break!(visitor.visit(expression)); + } + } + ClassElement::StaticBlock(statement_list) => { + try_break!(visitor.visit(statement_list)); + } + } + } + + ControlFlow::Continue(()) + } + + fn visit_class_declaration( + &mut self, + node: &'ast ClassDeclaration, + ) -> ControlFlow { + if let Some(node) = node.super_ref() { + try_break!(self.visit(node)); + } + + let mut names = self.0.clone(); + for element in node.elements() { + match element { + ClassElement::MethodDefinition(m) => { + if let ClassElementName::PrivateName(name) = m.name() { + names.push(name.description()); + } + } + ClassElement::PrivateFieldDefinition(name, _) + | ClassElement::PrivateStaticFieldDefinition(name, _) => { + names.push(name.description()); + } + _ => {} + } + } + + let mut visitor = Self(names); + + if let Some(node) = node.constructor() { + try_break!(visitor.visit(node)); + } + + for element in node.elements() { + match element { + ClassElement::MethodDefinition(m) => { + if let ClassElementName::PropertyName(name) = m.name() { + try_break!(visitor.visit(name)); + } + try_break!(visitor.visit(m.parameters())); + try_break!(visitor.visit(m.body())); + } + ClassElement::FieldDefinition(name, expression) + | ClassElement::StaticFieldDefinition(name, expression) => { + try_break!(visitor.visit(name)); + if let Some(expression) = expression { + try_break!(visitor.visit(expression)); + } } ClassElement::PrivateFieldDefinition(_, expression) | ClassElement::PrivateStaticFieldDefinition(_, expression) => { @@ -1297,7 +1586,7 @@ where fn visit_labelled_item(&mut self, node: &'ast LabelledItem) -> ControlFlow { match node { LabelledItem::Statement(stmt) => self.visit_statement(stmt), - LabelledItem::Function(_) => ControlFlow::Continue(()), + LabelledItem::FunctionDeclaration(_) => ControlFlow::Continue(()), } } @@ -1388,20 +1677,20 @@ pub enum LexicallyScopedDeclaration<'a> { /// See [`LexicalDeclaration`] LexicalDeclaration(&'a LexicalDeclaration), - /// See [`Function`] - Function(&'a Function), + /// See [`FunctionDeclaration`] + FunctionDeclaration(&'a FunctionDeclaration), - /// See [`Generator`] - Generator(&'a Generator), + /// See [`GeneratorDeclaration`] + GeneratorDeclaration(&'a GeneratorDeclaration), - /// See [`AsyncFunction`] - AsyncFunction(&'a AsyncFunction), + /// See [`AsyncFunctionDeclaration`] + AsyncFunctionDeclaration(&'a AsyncFunctionDeclaration), - /// See [`AsyncGenerator`] - AsyncGenerator(&'a AsyncGenerator), + /// See [`AsyncGeneratorDeclaration`] + AsyncGeneratorDeclaration(&'a AsyncGeneratorDeclaration), - /// See [`Class`] - Class(&'a Class), + /// See [`ClassDeclaration`] + ClassDeclaration(&'a ClassDeclaration), /// A default assignment expression as an export declaration. /// @@ -1415,11 +1704,11 @@ impl LexicallyScopedDeclaration<'_> { pub fn bound_names(&self) -> Vec { match *self { Self::LexicalDeclaration(v) => bound_names(v), - Self::Function(f) => bound_names(f), - Self::Generator(g) => bound_names(g), - Self::AsyncFunction(f) => bound_names(f), - Self::AsyncGenerator(g) => bound_names(g), - Self::Class(cl) => bound_names(cl), + Self::FunctionDeclaration(f) => bound_names(f), + Self::GeneratorDeclaration(g) => bound_names(g), + Self::AsyncFunctionDeclaration(f) => bound_names(f), + Self::AsyncGeneratorDeclaration(g) => bound_names(g), + Self::ClassDeclaration(cl) => bound_names(cl), Self::AssignmentExpression(expr) => bound_names(expr), } } @@ -1428,11 +1717,11 @@ impl LexicallyScopedDeclaration<'_> { impl<'ast> From<&'ast Declaration> for LexicallyScopedDeclaration<'ast> { fn from(value: &'ast Declaration) -> LexicallyScopedDeclaration<'ast> { match value { - Declaration::Function(f) => Self::Function(f), - Declaration::Generator(g) => Self::Generator(g), - Declaration::AsyncFunction(af) => Self::AsyncFunction(af), - Declaration::AsyncGenerator(ag) => Self::AsyncGenerator(ag), - Declaration::Class(c) => Self::Class(c), + Declaration::FunctionDeclaration(f) => Self::FunctionDeclaration(f), + Declaration::GeneratorDeclaration(g) => Self::GeneratorDeclaration(g), + Declaration::AsyncFunctionDeclaration(af) => Self::AsyncFunctionDeclaration(af), + Declaration::AsyncGeneratorDeclaration(ag) => Self::AsyncGeneratorDeclaration(ag), + Declaration::ClassDeclaration(c) => Self::ClassDeclaration(c), Declaration::Lexical(lex) => Self::LexicalDeclaration(lex), } } @@ -1490,19 +1779,23 @@ impl<'ast> Visitor<'ast> for LexicallyScopedDeclarationsVisitor<'_, 'ast> { // ExportDeclaration : export default HoistableDeclaration // 1. Return a List whose sole element is DeclarationPart of HoistableDeclaration. - ExportDeclaration::DefaultFunction(f) => LexicallyScopedDeclaration::Function(f), - ExportDeclaration::DefaultGenerator(g) => LexicallyScopedDeclaration::Generator(g), - ExportDeclaration::DefaultAsyncFunction(af) => { - LexicallyScopedDeclaration::AsyncFunction(af) + ExportDeclaration::DefaultFunctionDeclaration(f) => { + LexicallyScopedDeclaration::FunctionDeclaration(f) + } + ExportDeclaration::DefaultGeneratorDeclaration(g) => { + LexicallyScopedDeclaration::GeneratorDeclaration(g) } - ExportDeclaration::DefaultAsyncGenerator(ag) => { - LexicallyScopedDeclaration::AsyncGenerator(ag) + ExportDeclaration::DefaultAsyncFunctionDeclaration(af) => { + LexicallyScopedDeclaration::AsyncFunctionDeclaration(af) + } + ExportDeclaration::DefaultAsyncGeneratorDeclaration(ag) => { + LexicallyScopedDeclaration::AsyncGeneratorDeclaration(ag) } // ExportDeclaration : export default ClassDeclaration ExportDeclaration::DefaultClassDeclaration(c) => { // 1. Return a List whose sole element is ClassDeclaration. - LexicallyScopedDeclaration::Class(c) + LexicallyScopedDeclaration::ClassDeclaration(c) } // ExportDeclaration : export default AssignmentExpression ; @@ -1544,9 +1837,10 @@ impl<'ast> Visitor<'ast> for LexicallyScopedDeclarationsVisitor<'_, 'ast> { fn visit_labelled_item(&mut self, node: &'ast LabelledItem) -> ControlFlow { match node { // LabelledItem : FunctionDeclaration - LabelledItem::Function(f) => { + LabelledItem::FunctionDeclaration(f) => { // 1. Return « FunctionDeclaration ». - self.0.push(LexicallyScopedDeclaration::Function(f)); + self.0 + .push(LexicallyScopedDeclaration::FunctionDeclaration(f)); } // LabelledItem : Statement @@ -1591,16 +1885,17 @@ impl<'ast> Visitor<'ast> for TopLevelLexicallyScopedDeclarationsVisitor<'_, 'ast // StatementListItem : Declaration StatementListItem::Declaration(d) => match d { // 1. If Declaration is Declaration : HoistableDeclaration , then - Declaration::Function(_) - | Declaration::Generator(_) - | Declaration::AsyncFunction(_) - | Declaration::AsyncGenerator(_) => { + Declaration::FunctionDeclaration(_) + | Declaration::GeneratorDeclaration(_) + | Declaration::AsyncFunctionDeclaration(_) + | Declaration::AsyncGeneratorDeclaration(_) => { // a. Return a new empty List. } // 2. Return « Declaration ». - Declaration::Class(cl) => { - self.0.push(LexicallyScopedDeclaration::Class(cl)); + Declaration::ClassDeclaration(cl) => { + self.0 + .push(LexicallyScopedDeclaration::ClassDeclaration(cl)); } Declaration::Lexical(lex) => { self.0 @@ -1624,17 +1919,17 @@ pub enum VarScopedDeclaration { /// See [`VarDeclaration`] VariableDeclaration(Variable), - /// See [`Function`] - Function(Function), + /// See [`FunctionDeclaration`] + FunctionDeclaration(FunctionDeclaration), - /// See [`Generator`] - Generator(Generator), + /// See [`GeneratorDeclaration`] + GeneratorDeclaration(GeneratorDeclaration), - /// See [`AsyncFunction`] - AsyncFunction(AsyncFunction), + /// See [`AsyncFunctionDeclaration`] + AsyncFunctionDeclaration(AsyncFunctionDeclaration), - /// See [`AsyncGenerator`] - AsyncGenerator(AsyncGenerator), + /// See [`AsyncGeneratorDeclaration`] + AsyncGeneratorDeclaration(AsyncGeneratorDeclaration), } impl VarScopedDeclaration { @@ -1643,10 +1938,10 @@ impl VarScopedDeclaration { pub fn bound_names(&self) -> Vec { match self { Self::VariableDeclaration(v) => bound_names(v), - Self::Function(f) => bound_names(f), - Self::Generator(g) => bound_names(g), - Self::AsyncFunction(f) => bound_names(f), - Self::AsyncGenerator(g) => bound_names(g), + Self::FunctionDeclaration(f) => bound_names(f), + Self::GeneratorDeclaration(g) => bound_names(g), + Self::AsyncFunctionDeclaration(f) => bound_names(f), + Self::AsyncGeneratorDeclaration(g) => bound_names(g), } } } @@ -1802,7 +2097,7 @@ impl<'ast> Visitor<'ast> for VarScopedDeclarationsVisitor<'_> { fn visit_labelled_item(&mut self, node: &'ast LabelledItem) -> ControlFlow { match node { LabelledItem::Statement(s) => self.visit(s), - LabelledItem::Function(_) => ControlFlow::Continue(()), + LabelledItem::FunctionDeclaration(_) => ControlFlow::Continue(()), } } @@ -1851,17 +2146,21 @@ impl<'ast> Visitor<'ast> for TopLevelVarScopedDeclarationsVisitor<'_> { match node { StatementListItem::Declaration(d) => { match d { - Declaration::Function(f) => { - self.0.push(VarScopedDeclaration::Function(f.clone())); + Declaration::FunctionDeclaration(f) => { + self.0 + .push(VarScopedDeclaration::FunctionDeclaration(f.clone())); } - Declaration::Generator(f) => { - self.0.push(VarScopedDeclaration::Generator(f.clone())); + Declaration::GeneratorDeclaration(f) => { + self.0 + .push(VarScopedDeclaration::GeneratorDeclaration(f.clone())); } - Declaration::AsyncFunction(f) => { - self.0.push(VarScopedDeclaration::AsyncFunction(f.clone())); + Declaration::AsyncFunctionDeclaration(f) => { + self.0 + .push(VarScopedDeclaration::AsyncFunctionDeclaration(f.clone())); } - Declaration::AsyncGenerator(f) => { - self.0.push(VarScopedDeclaration::AsyncGenerator(f.clone())); + Declaration::AsyncGeneratorDeclaration(f) => { + self.0 + .push(VarScopedDeclaration::AsyncGeneratorDeclaration(f.clone())); } _ => {} } @@ -1882,8 +2181,9 @@ impl<'ast> Visitor<'ast> for TopLevelVarScopedDeclarationsVisitor<'_> { VarScopedDeclarationsVisitor(self.0).visit(s); ControlFlow::Continue(()) } - LabelledItem::Function(f) => { - self.0.push(VarScopedDeclaration::Function(f.clone())); + LabelledItem::FunctionDeclaration(f) => { + self.0 + .push(VarScopedDeclaration::FunctionDeclaration(f.clone())); ControlFlow::Continue(()) } } @@ -1949,10 +2249,10 @@ impl<'ast> Visitor<'ast> for AnnexBFunctionDeclarationNamesVisitor<'_> { fn visit_block(&mut self, node: &'ast crate::statement::Block) -> ControlFlow { self.visit(node.statement_list()); for statement in node.statement_list().statements() { - if let StatementListItem::Declaration(Declaration::Function(function)) = statement { - let name = function - .name() - .expect("function declaration must have name"); + if let StatementListItem::Declaration(Declaration::FunctionDeclaration(function)) = + statement + { + let name = function.name(); self.0.push(name); } } @@ -1969,10 +2269,10 @@ impl<'ast> Visitor<'ast> for AnnexBFunctionDeclarationNamesVisitor<'_> { for case in node.cases() { self.visit(case); for statement in case.body().statements() { - if let StatementListItem::Declaration(Declaration::Function(function)) = statement { - let name = function - .name() - .expect("function declaration must have name"); + if let StatementListItem::Declaration(Declaration::FunctionDeclaration(function)) = + statement + { + let name = function.name(); self.0.push(name); } } @@ -1980,10 +2280,10 @@ impl<'ast> Visitor<'ast> for AnnexBFunctionDeclarationNamesVisitor<'_> { if let Some(default) = node.default() { self.visit(default); for statement in default.statements() { - if let StatementListItem::Declaration(Declaration::Function(function)) = statement { - let name = function - .name() - .expect("function declaration must have name"); + if let StatementListItem::Declaration(Declaration::FunctionDeclaration(function)) = + statement + { + let name = function.name(); self.0.push(name); } } @@ -2152,7 +2452,7 @@ impl<'ast> Visitor<'ast> for ReturnsValueVisitor { ) -> ControlFlow { match node.item() { LabelledItem::Statement(node) => try_break!(self.visit(node)), - LabelledItem::Function(_) => {} + LabelledItem::FunctionDeclaration(_) => {} } ControlFlow::Continue(()) } diff --git a/core/ast/src/property.rs b/core/ast/src/property.rs index 00e6f119a6..ec7b1ab659 100644 --- a/core/ast/src/property.rs +++ b/core/ast/src/property.rs @@ -1,245 +1,10 @@ //! Property definition related types, used in object literals and class definitions. -use crate::function::PrivateName; -use crate::try_break; +use super::{expression::literal::Literal, Expression}; use crate::visitor::{VisitWith, Visitor, VisitorMut}; use boa_interner::{Interner, Sym, ToInternedString}; use core::ops::ControlFlow; -use super::{ - expression::{literal::Literal, Identifier}, - function::{AsyncFunction, AsyncGenerator, Function, Generator}, - Expression, -}; - -/// Describes the definition of a property within an object literal. -/// -/// A property has a name (a string) and a value (primitive, method, or object reference). -/// Note that when we say that "a property holds an object", that is shorthand for "a property holds an object reference". -/// This distinction matters because the original referenced object remains unchanged when you change the property's value. -/// -/// More information: -/// - [ECMAScript reference][spec] -/// - [MDN documentation][mdn] -/// -/// [spec]: https://tc39.es/ecma262/#prod-PropertyDefinition -/// [mdn]: https://developer.mozilla.org/en-US/docs/Glossary/property/JavaScript -// TODO: Support all features: https://tc39.es/ecma262/#prod-PropertyDefinition -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[derive(Clone, Debug, PartialEq)] -pub enum PropertyDefinition { - /// Puts a variable into an object. - /// - /// More information: - /// - [ECMAScript reference][spec] - /// - [MDN documentation][mdn] - /// - /// [spec]: https://tc39.es/ecma262/#prod-IdentifierReference - /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#Property_definitions - IdentifierReference(Identifier), - - /// Binds a property name to a JavaScript value. - /// - /// More information: - /// - [ECMAScript reference][spec] - /// - [MDN documentation][mdn] - /// - /// [spec]: https://tc39.es/ecma262/#prod-PropertyDefinition - /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#Property_definitions - Property(PropertyName, Expression), - - /// A property of an object can also refer to a function or a getter or setter method. - /// - /// More information: - /// - [ECMAScript reference][spec] - /// - [MDN documentation][mdn] - /// - /// [spec]: https://tc39.es/ecma262/#prod-MethodDefinition - /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#Method_definitions - MethodDefinition(PropertyName, MethodDefinition), - - /// The Rest/Spread Properties for ECMAScript proposal (stage 4) adds spread properties to object literals. - /// It copies own enumerable properties from a provided object onto a new object. - /// - /// Shallow-cloning (excluding `prototype`) or merging objects is now possible using a shorter syntax than `Object.assign()`. - /// - /// More information: - /// - [ECMAScript reference][spec] - /// - [MDN documentation][mdn] - /// - /// [spec]: https://tc39.es/ecma262/#prod-PropertyDefinition - /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#Spread_properties - SpreadObject(Expression), - - /// Cover grammar for when an object literal is used as an object binding pattern. - /// - /// More information: - /// - [ECMAScript reference][spec] - /// - /// [spec]: https://tc39.es/ecma262/#prod-CoverInitializedName - CoverInitializedName(Identifier, Expression), -} - -impl VisitWith for PropertyDefinition { - fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow - where - V: Visitor<'a>, - { - match self { - Self::IdentifierReference(id) => visitor.visit_identifier(id), - Self::Property(pn, expr) => { - try_break!(visitor.visit_property_name(pn)); - visitor.visit_expression(expr) - } - Self::MethodDefinition(pn, md) => { - try_break!(visitor.visit_property_name(pn)); - visitor.visit_method_definition(md) - } - Self::SpreadObject(expr) => visitor.visit_expression(expr), - Self::CoverInitializedName(id, expr) => { - try_break!(visitor.visit_identifier(id)); - visitor.visit_expression(expr) - } - } - } - - fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow - where - V: VisitorMut<'a>, - { - match self { - Self::IdentifierReference(id) => visitor.visit_identifier_mut(id), - Self::Property(pn, expr) => { - try_break!(visitor.visit_property_name_mut(pn)); - visitor.visit_expression_mut(expr) - } - Self::MethodDefinition(pn, md) => { - try_break!(visitor.visit_property_name_mut(pn)); - visitor.visit_method_definition_mut(md) - } - Self::SpreadObject(expr) => visitor.visit_expression_mut(expr), - Self::CoverInitializedName(id, expr) => { - try_break!(visitor.visit_identifier_mut(id)); - visitor.visit_expression_mut(expr) - } - } - } -} - -/// Method definition. -/// -/// Starting with ECMAScript 2015, a shorter syntax for method definitions on objects initializers is introduced. -/// It is a shorthand for a function assigned to the method's name. -/// -/// More information: -/// - [ECMAScript reference][spec] -/// - [MDN documentation][mdn] -/// -/// [spec]: https://tc39.es/ecma262/#prod-MethodDefinition -/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Method_definitions -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] -#[derive(Clone, Debug, PartialEq)] -pub enum MethodDefinition { - /// The `get` syntax binds an object property to a function that will be called when that property is looked up. - /// - /// Sometimes it is desirable to allow access to a property that returns a dynamically computed value, - /// or you may want to reflect the status of an internal variable without requiring the use of explicit method calls. - /// In JavaScript, this can be accomplished with the use of a getter. - /// - /// It is not possible to simultaneously have a getter bound to a property and have that property actually hold a value, - /// although it is possible to use a getter and a setter in conjunction to create a type of pseudo-property. - /// - /// More information: - /// - [ECMAScript reference][spec] - /// - [MDN documentation][mdn] - /// - /// [spec]: https://tc39.es/ecma262/#prod-MethodDefinition - /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get - Get(Function), - - /// The `set` syntax binds an object property to a function to be called when there is an attempt to set that property. - /// - /// In JavaScript, a setter can be used to execute a function whenever a specified property is attempted to be changed. - /// Setters are most often used in conjunction with getters to create a type of pseudo-property. - /// It is not possible to simultaneously have a setter on a property that holds an actual value. - /// - /// More information: - /// - [ECMAScript reference][spec] - /// - [MDN documentation][mdn] - /// - /// [spec]: https://tc39.es/ecma262/#prod-MethodDefinition - /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/set - Set(Function), - - /// Starting with ECMAScript 2015, you are able to define own methods in a shorter syntax, similar to the getters and setters. - /// - /// More information: - /// - [ECMAScript reference][spec] - /// - [MDN documentation][mdn] - /// - /// [spec]: https://tc39.es/ecma262/#prod-MethodDefinition - /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions#Method_definition_syntax - Ordinary(Function), - - /// Starting with ECMAScript 2015, you are able to define own methods in a shorter syntax, similar to the getters and setters. - /// - /// More information: - /// - [ECMAScript reference][spec] - /// - [MDN documentation][mdn] - /// - /// [spec]: https://tc39.es/ecma262/#prod-MethodDefinition - /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Method_definitions#generator_methods - Generator(Generator), - - /// Async generators can be used to define a method - /// - /// More information - /// - [ECMAScript reference][spec] - /// - [MDN documentation][mdn] - /// - /// [spec]: https://tc39.es/ecma262/#prod-AsyncGeneratorMethod - /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Method_definitions#async_generator_methods - AsyncGenerator(AsyncGenerator), - - /// Async function can be used to define a method - /// - /// More information - /// - [ECMAScript reference][spec] - /// - [MDN documentation][mdn] - /// - /// [spec]: https://tc39.es/ecma262/#prod-AsyncMethod - /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Method_definitions#async_methods - Async(AsyncFunction), -} - -impl VisitWith for MethodDefinition { - fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow - where - V: Visitor<'a>, - { - match self { - Self::Get(f) | Self::Set(f) | Self::Ordinary(f) => visitor.visit_function(f), - Self::Generator(g) => visitor.visit_generator(g), - Self::AsyncGenerator(ag) => visitor.visit_async_generator(ag), - Self::Async(af) => visitor.visit_async_function(af), - } - } - - fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow - where - V: VisitorMut<'a>, - { - match self { - Self::Get(f) | Self::Set(f) | Self::Ordinary(f) => visitor.visit_function_mut(f), - Self::Generator(g) => visitor.visit_generator_mut(g), - Self::AsyncGenerator(ag) => visitor.visit_async_generator_mut(ag), - Self::Async(af) => visitor.visit_async_function_mut(af), - } - } -} - /// `PropertyName` can be either a literal or computed. /// /// More information: @@ -343,29 +108,26 @@ impl VisitWith for PropertyName { } } -/// `ClassElementName` can be either a property name or a private identifier. -/// -/// More information: -/// - [ECMAScript reference][spec] -/// -/// [spec]: https://tc39.es/ecma262/#prod-ClassElementName +/// The kind of a method definition. #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[derive(Clone, Debug, PartialEq)] -pub enum ClassElementName { - /// A public property. - PropertyName(PropertyName), - /// A private property. - PrivateIdentifier(PrivateName), -} +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +#[derive(Copy, Clone, Debug, PartialEq)] +pub enum MethodDefinitionKind { + /// A getter method. + Get, -impl ClassElementName { - /// Returns the property name if it exists. - #[must_use] - pub const fn literal(&self) -> Option { - if let Self::PropertyName(name) = self { - name.literal() - } else { - None - } - } + /// A setter method. + Set, + + /// An ordinary method. + Ordinary, + + /// A generator method. + Generator, + + /// An async generator method. + AsyncGenerator, + + /// An async method. + Async, } diff --git a/core/ast/src/statement/labelled.rs b/core/ast/src/statement/labelled.rs index 317fb71574..541397d736 100644 --- a/core/ast/src/statement/labelled.rs +++ b/core/ast/src/statement/labelled.rs @@ -1,5 +1,5 @@ use crate::{ - function::Function, + function::FunctionDeclaration, try_break, visitor::{VisitWith, Visitor, VisitorMut}, Statement, @@ -12,7 +12,7 @@ use core::ops::ControlFlow; /// Semantically, a [`Labelled`] statement should only wrap [`Statement`] nodes. However, /// old ECMAScript implementations supported [labelled function declarations][label-fn] as an extension /// of the grammar. In the ECMAScript 2015 spec, the production of `LabelledStatement` was -/// modified to include labelled [`Function`]s as a valid node. +/// modified to include labelled [`FunctionDeclaration`]s as a valid node. /// /// [spec]: https://tc39.es/ecma262/#prod-LabelledItem /// [label-fn]: https://tc39.es/ecma262/#sec-labelled-function-declarations @@ -20,8 +20,9 @@ use core::ops::ControlFlow; #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive(Clone, Debug, PartialEq)] pub enum LabelledItem { - /// A labelled [`Function`]. - Function(Function), + /// A labelled [`FunctionDeclaration`]. + FunctionDeclaration(FunctionDeclaration), + /// A labelled [`Statement`]. Statement(Statement), } @@ -29,7 +30,7 @@ pub enum LabelledItem { impl LabelledItem { pub(crate) fn to_indented_string(&self, interner: &Interner, indentation: usize) -> String { match self { - Self::Function(f) => f.to_indented_string(interner, indentation), + Self::FunctionDeclaration(f) => f.to_indented_string(interner, indentation), Self::Statement(stmt) => stmt.to_indented_string(interner, indentation), } } @@ -41,9 +42,9 @@ impl ToInternedString for LabelledItem { } } -impl From for LabelledItem { - fn from(f: Function) -> Self { - Self::Function(f) +impl From for LabelledItem { + fn from(f: FunctionDeclaration) -> Self { + Self::FunctionDeclaration(f) } } @@ -59,7 +60,7 @@ impl VisitWith for LabelledItem { V: Visitor<'a>, { match self { - Self::Function(f) => visitor.visit_function(f), + Self::FunctionDeclaration(f) => visitor.visit_function_declaration(f), Self::Statement(s) => visitor.visit_statement(s), } } @@ -69,7 +70,7 @@ impl VisitWith for LabelledItem { V: VisitorMut<'a>, { match self { - Self::Function(f) => visitor.visit_function_mut(f), + Self::FunctionDeclaration(f) => visitor.visit_function_declaration_mut(f), Self::Statement(s) => visitor.visit_statement_mut(s), } } diff --git a/core/ast/src/statement/mod.rs b/core/ast/src/statement/mod.rs index d6c920c492..9c2e942c5c 100644 --- a/core/ast/src/statement/mod.rs +++ b/core/ast/src/statement/mod.rs @@ -156,7 +156,7 @@ impl Statement { pub fn is_labelled_function(&self) -> bool { match self { Self::Labelled(stmt) => match stmt.item() { - LabelledItem::Function(_) => true, + LabelledItem::FunctionDeclaration(_) => true, LabelledItem::Statement(stmt) => stmt.is_labelled_function(), }, _ => false, diff --git a/core/ast/src/visitor.rs b/core/ast/src/visitor.rs index ded44fe7b8..351f52fe45 100644 --- a/core/ast/src/visitor.rs +++ b/core/ast/src/visitor.rs @@ -16,7 +16,10 @@ use crate::{ PrivatePropertyAccess, PropertyAccess, PropertyAccessField, SimplePropertyAccess, SuperPropertyAccess, }, - literal::{ArrayLiteral, Literal, ObjectLiteral, TemplateElement, TemplateLiteral}, + literal::{ + ArrayLiteral, Literal, ObjectLiteral, ObjectMethodDefinition, PropertyDefinition, + TemplateElement, TemplateLiteral, + }, operator::{ assign::{Assign, AssignTarget}, Binary, BinaryInPrivate, Conditional, Unary, Update, @@ -26,11 +29,13 @@ use crate::{ Yield, }, function::{ - ArrowFunction, AsyncArrowFunction, AsyncFunction, AsyncGenerator, Class, ClassElement, - FormalParameter, FormalParameterList, Function, Generator, PrivateName, + ArrowFunction, AsyncArrowFunction, AsyncFunctionDeclaration, AsyncFunctionExpression, + AsyncGeneratorDeclaration, AsyncGeneratorExpression, ClassDeclaration, ClassElement, + ClassExpression, FormalParameter, FormalParameterList, FunctionDeclaration, + FunctionExpression, GeneratorDeclaration, GeneratorExpression, PrivateName, }, pattern::{ArrayPattern, ArrayPatternElement, ObjectPattern, ObjectPatternElement, Pattern}, - property::{MethodDefinition, PropertyDefinition, PropertyName}, + property::PropertyName, statement::{ iteration::{ Break, Continue, DoWhileLoop, ForInLoop, ForLoop, ForLoopInitializer, ForOfLoop, @@ -125,11 +130,16 @@ node_ref! { StatementListItem, Statement, Declaration, - Function, - Generator, - AsyncFunction, - AsyncGenerator, - Class, + FunctionExpression, + FunctionDeclaration, + GeneratorExpression, + GeneratorDeclaration, + AsyncFunctionExpression, + AsyncFunctionDeclaration, + AsyncGeneratorExpression, + AsyncGeneratorDeclaration, + ClassExpression, + ClassDeclaration, LexicalDeclaration, Block, VarDeclaration, @@ -189,7 +199,7 @@ node_ref! { Finally, FormalParameter, PropertyName, - MethodDefinition, + ObjectMethodDefinition, ObjectPattern, ArrayPattern, PropertyDefinition, @@ -228,11 +238,16 @@ pub trait Visitor<'ast>: Sized { define_visit!(visit_statement_list_item, StatementListItem); define_visit!(visit_statement, Statement); define_visit!(visit_declaration, Declaration); - define_visit!(visit_function, Function); - define_visit!(visit_generator, Generator); - define_visit!(visit_async_function, AsyncFunction); - define_visit!(visit_async_generator, AsyncGenerator); - define_visit!(visit_class, Class); + define_visit!(visit_function_expression, FunctionExpression); + define_visit!(visit_function_declaration, FunctionDeclaration); + define_visit!(visit_generator_expression, GeneratorExpression); + define_visit!(visit_generator_declaration, GeneratorDeclaration); + define_visit!(visit_async_function_expression, AsyncFunctionExpression); + define_visit!(visit_async_function_declaration, AsyncFunctionDeclaration); + define_visit!(visit_async_generator_expression, AsyncGeneratorExpression); + define_visit!(visit_async_generator_declaration, AsyncGeneratorDeclaration); + define_visit!(visit_class_expression, ClassExpression); + define_visit!(visit_class_declaration, ClassDeclaration); define_visit!(visit_lexical_declaration, LexicalDeclaration); define_visit!(visit_block, Block); define_visit!(visit_var_declaration, VarDeclaration); @@ -292,7 +307,7 @@ pub trait Visitor<'ast>: Sized { define_visit!(visit_finally, Finally); define_visit!(visit_formal_parameter, FormalParameter); define_visit!(visit_property_name, PropertyName); - define_visit!(visit_method_definition, MethodDefinition); + define_visit!(visit_object_method_definition, ObjectMethodDefinition); define_visit!(visit_object_pattern, ObjectPattern); define_visit!(visit_array_pattern, ArrayPattern); define_visit!(visit_property_definition, PropertyDefinition); @@ -328,11 +343,16 @@ pub trait Visitor<'ast>: Sized { NodeRef::StatementListItem(n) => self.visit_statement_list_item(n), NodeRef::Statement(n) => self.visit_statement(n), NodeRef::Declaration(n) => self.visit_declaration(n), - NodeRef::Function(n) => self.visit_function(n), - NodeRef::Generator(n) => self.visit_generator(n), - NodeRef::AsyncFunction(n) => self.visit_async_function(n), - NodeRef::AsyncGenerator(n) => self.visit_async_generator(n), - NodeRef::Class(n) => self.visit_class(n), + NodeRef::FunctionExpression(n) => self.visit_function_expression(n), + NodeRef::FunctionDeclaration(n) => self.visit_function_declaration(n), + NodeRef::GeneratorExpression(n) => self.visit_generator_expression(n), + NodeRef::GeneratorDeclaration(n) => self.visit_generator_declaration(n), + NodeRef::AsyncFunctionExpression(n) => self.visit_async_function_expression(n), + NodeRef::AsyncFunctionDeclaration(n) => self.visit_async_function_declaration(n), + NodeRef::AsyncGeneratorExpression(n) => self.visit_async_generator_expression(n), + NodeRef::AsyncGeneratorDeclaration(n) => self.visit_async_generator_declaration(n), + NodeRef::ClassExpression(n) => self.visit_class_expression(n), + NodeRef::ClassDeclaration(n) => self.visit_class_declaration(n), NodeRef::LexicalDeclaration(n) => self.visit_lexical_declaration(n), NodeRef::Block(n) => self.visit_block(n), NodeRef::VarDeclaration(n) => self.visit_var_declaration(n), @@ -392,7 +412,7 @@ pub trait Visitor<'ast>: Sized { NodeRef::Finally(n) => self.visit_finally(n), NodeRef::FormalParameter(n) => self.visit_formal_parameter(n), NodeRef::PropertyName(n) => self.visit_property_name(n), - NodeRef::MethodDefinition(n) => self.visit_method_definition(n), + NodeRef::ObjectMethodDefinition(n) => self.visit_object_method_definition(n), NodeRef::ObjectPattern(n) => self.visit_object_pattern(n), NodeRef::ArrayPattern(n) => self.visit_array_pattern(n), NodeRef::PropertyDefinition(n) => self.visit_property_definition(n), @@ -433,11 +453,25 @@ pub trait VisitorMut<'ast>: Sized { define_visit_mut!(visit_statement_list_item_mut, StatementListItem); define_visit_mut!(visit_statement_mut, Statement); define_visit_mut!(visit_declaration_mut, Declaration); - define_visit_mut!(visit_function_mut, Function); - define_visit_mut!(visit_generator_mut, Generator); - define_visit_mut!(visit_async_function_mut, AsyncFunction); - define_visit_mut!(visit_async_generator_mut, AsyncGenerator); - define_visit_mut!(visit_class_mut, Class); + define_visit_mut!(visit_function_expression_mut, FunctionExpression); + define_visit_mut!(visit_function_declaration_mut, FunctionDeclaration); + define_visit_mut!(visit_generator_expression_mut, GeneratorExpression); + define_visit_mut!(visit_generator_declaration_mut, GeneratorDeclaration); + define_visit_mut!(visit_async_function_expression_mut, AsyncFunctionExpression); + define_visit_mut!( + visit_async_function_declaration_mut, + AsyncFunctionDeclaration + ); + define_visit_mut!( + visit_async_generator_expression_mut, + AsyncGeneratorExpression + ); + define_visit_mut!( + visit_async_generator_declaration_mut, + AsyncGeneratorDeclaration + ); + define_visit_mut!(visit_class_expression_mut, ClassExpression); + define_visit_mut!(visit_class_declaration_mut, ClassDeclaration); define_visit_mut!(visit_lexical_declaration_mut, LexicalDeclaration); define_visit_mut!(visit_block_mut, Block); define_visit_mut!(visit_var_declaration_mut, VarDeclaration); @@ -497,7 +531,7 @@ pub trait VisitorMut<'ast>: Sized { define_visit_mut!(visit_finally_mut, Finally); define_visit_mut!(visit_formal_parameter_mut, FormalParameter); define_visit_mut!(visit_property_name_mut, PropertyName); - define_visit_mut!(visit_method_definition_mut, MethodDefinition); + define_visit_mut!(visit_object_method_definition_mut, ObjectMethodDefinition); define_visit_mut!(visit_object_pattern_mut, ObjectPattern); define_visit_mut!(visit_array_pattern_mut, ArrayPattern); define_visit_mut!(visit_property_definition_mut, PropertyDefinition); @@ -533,11 +567,18 @@ pub trait VisitorMut<'ast>: Sized { NodeRefMut::StatementListItem(n) => self.visit_statement_list_item_mut(n), NodeRefMut::Statement(n) => self.visit_statement_mut(n), NodeRefMut::Declaration(n) => self.visit_declaration_mut(n), - NodeRefMut::Function(n) => self.visit_function_mut(n), - NodeRefMut::Generator(n) => self.visit_generator_mut(n), - NodeRefMut::AsyncFunction(n) => self.visit_async_function_mut(n), - NodeRefMut::AsyncGenerator(n) => self.visit_async_generator_mut(n), - NodeRefMut::Class(n) => self.visit_class_mut(n), + NodeRefMut::FunctionExpression(n) => self.visit_function_expression_mut(n), + NodeRefMut::FunctionDeclaration(n) => self.visit_function_declaration_mut(n), + NodeRefMut::GeneratorExpression(n) => self.visit_generator_expression_mut(n), + NodeRefMut::GeneratorDeclaration(n) => self.visit_generator_declaration_mut(n), + NodeRefMut::AsyncFunctionExpression(n) => self.visit_async_function_expression_mut(n), + NodeRefMut::AsyncFunctionDeclaration(n) => self.visit_async_function_declaration_mut(n), + NodeRefMut::AsyncGeneratorExpression(n) => self.visit_async_generator_expression_mut(n), + NodeRefMut::AsyncGeneratorDeclaration(n) => { + self.visit_async_generator_declaration_mut(n) + } + NodeRefMut::ClassExpression(n) => self.visit_class_expression_mut(n), + NodeRefMut::ClassDeclaration(n) => self.visit_class_declaration_mut(n), NodeRefMut::LexicalDeclaration(n) => self.visit_lexical_declaration_mut(n), NodeRefMut::Block(n) => self.visit_block_mut(n), NodeRefMut::VarDeclaration(n) => self.visit_var_declaration_mut(n), @@ -597,7 +638,7 @@ pub trait VisitorMut<'ast>: Sized { NodeRefMut::Finally(n) => self.visit_finally_mut(n), NodeRefMut::FormalParameter(n) => self.visit_formal_parameter_mut(n), NodeRefMut::PropertyName(n) => self.visit_property_name_mut(n), - NodeRefMut::MethodDefinition(n) => self.visit_method_definition_mut(n), + NodeRefMut::ObjectMethodDefinition(n) => self.visit_object_method_definition_mut(n), NodeRefMut::ObjectPattern(n) => self.visit_object_pattern_mut(n), NodeRefMut::ArrayPattern(n) => self.visit_array_pattern_mut(n), NodeRefMut::PropertyDefinition(n) => self.visit_property_definition_mut(n), diff --git a/core/engine/src/builtins/function/mod.rs b/core/engine/src/builtins/function/mod.rs index cd1c0ffa4f..a94022b2ad 100644 --- a/core/engine/src/builtins/function/mod.rs +++ b/core/engine/src/builtins/function/mod.rs @@ -140,7 +140,7 @@ impl ConstructorKind { #[derive(Clone, Debug, Finalize)] pub enum ClassFieldDefinition { /// A class field definition with a `string` or `symbol` as a name. - Public(PropertyKey, JsFunction), + Public(PropertyKey, JsFunction, Option), /// A class field definition with a private name. Private(PrivateName, JsFunction), @@ -149,7 +149,7 @@ pub enum ClassFieldDefinition { unsafe impl Trace for ClassFieldDefinition { custom_trace! {this, mark, { match this { - Self::Public(_key, func) => { + Self::Public(_key, func, _) => { mark(func); } Self::Private(_, func) => { @@ -265,8 +265,14 @@ impl OrdinaryFunction { } /// Pushes a value to the `[[Fields]]` internal slot if present. - pub(crate) fn push_field(&mut self, key: PropertyKey, value: JsFunction) { - self.fields.push(ClassFieldDefinition::Public(key, value)); + pub(crate) fn push_field( + &mut self, + key: PropertyKey, + value: JsFunction, + function_name: Option, + ) { + self.fields + .push(ClassFieldDefinition::Public(key, value, function_name)); } /// Pushes a private value to the `[[Fields]]` internal slot if present. diff --git a/core/engine/src/bytecompiler/class.rs b/core/engine/src/bytecompiler/class.rs index 04d3087548..baddbf1bfd 100644 --- a/core/engine/src/bytecompiler/class.rs +++ b/core/engine/src/bytecompiler/class.rs @@ -5,8 +5,12 @@ use crate::{ }; use boa_ast::{ expression::Identifier, - function::{Class, ClassElement, FormalParameterList}, - property::{MethodDefinition, PropertyName}, + function::{ + ClassDeclaration, ClassElement, ClassElementName, ClassExpression, FormalParameterList, + FunctionExpression, + }, + property::{MethodDefinitionKind, PropertyName}, + Expression, }; use boa_gc::Gc; use boa_interner::Sym; @@ -16,8 +20,42 @@ enum StaticElement { // A static class block with it's function code. StaticBlock(Gc), - // A static class field with it's function code and optional name index. - StaticField((Gc, Option)), + // A static class field with it's function code, an optional name index and the information if the function is an anonymous function. + StaticField((Gc, Option, bool)), +} + +/// Describes the complete specification of a class. +#[derive(Debug, Clone, Copy, PartialEq)] +pub(crate) struct ClassSpec<'a> { + name: Option, + super_ref: Option<&'a Expression>, + constructor: Option<&'a FunctionExpression>, + elements: &'a [ClassElement], + has_binding_identifier: bool, +} + +impl<'a> From<&'a ClassDeclaration> for ClassSpec<'a> { + fn from(class: &'a ClassDeclaration) -> Self { + Self { + name: Some(class.name()), + super_ref: class.super_ref(), + constructor: class.constructor(), + elements: class.elements(), + has_binding_identifier: true, + } + } +} + +impl<'a> From<&'a ClassExpression> for ClassSpec<'a> { + fn from(class: &'a ClassExpression) -> Self { + Self { + name: class.name(), + super_ref: class.super_ref(), + constructor: class.constructor(), + elements: class.elements(), + has_binding_identifier: class.name().is_some(), + } + } } impl ByteCompiler<'_> { @@ -26,18 +64,18 @@ impl ByteCompiler<'_> { /// The compilation of a class declaration and expression is mostly equal. /// A class declaration binds the resulting class object to it's identifier. /// A class expression leaves the resulting class object on the stack for following operations. - pub(crate) fn compile_class(&mut self, class: &Class, expression: bool) { + pub(crate) fn compile_class(&mut self, class: ClassSpec<'_>, expression: bool) { // 11.2.2 Strict Mode Code - // - All parts of a ClassDeclaration or a ClassExpression are strict mode code. let strict = self.strict(); self.code_block_flags |= CodeBlockFlags::STRICT; let class_name = class - .name() + .name .map_or(Sym::EMPTY_STRING, Identifier::sym) .to_js_string(self.interner()); - let old_lex_env = if class.has_binding_identifier() { + let old_lex_env = if class.has_binding_identifier { let old_lex_env = self.lexical_environment.clone(); let env_index = self.push_compile_environment(false); self.emit_with_varying_operand(Opcode::PushDeclarativeEnvironment, env_index); @@ -63,7 +101,7 @@ impl ByteCompiler<'_> { // Function environment let _ = compiler.push_compile_environment(true); - if let Some(expr) = class.constructor() { + if let Some(expr) = &class.constructor { compiler.length = expr.parameters().length(); compiler.params = expr.parameters().clone(); @@ -78,7 +116,7 @@ impl ByteCompiler<'_> { compiler.compile_statement_list(expr.body().statements(), false, false); compiler.emit_opcode(Opcode::PushUndefined); - } else if class.super_ref().is_some() { + } else if class.super_ref.is_some() { compiler.emit_opcode(Opcode::SuperCallDerived); compiler.emit_opcode(Opcode::BindThisValue); } else { @@ -89,7 +127,7 @@ impl ByteCompiler<'_> { // 17. If ClassHeritageopt is present, set F.[[ConstructorKind]] to derived. compiler.code_block_flags.set( CodeBlockFlags::IS_DERIVED_CONSTRUCTOR, - class.super_ref().is_some(), + class.super_ref.is_some(), ); let code = Gc::new(compiler.finish()); @@ -97,7 +135,7 @@ impl ByteCompiler<'_> { self.emit_with_varying_operand(Opcode::GetFunction, index); self.emit_opcode(Opcode::Dup); - if let Some(node) = class.super_ref() { + if let Some(node) = &class.super_ref { self.compile_expr(node, true); self.emit_opcode(Opcode::PushClassPrototype); } else { @@ -108,11 +146,16 @@ impl ByteCompiler<'_> { let count_label = self.emit_opcode_with_operand(Opcode::PushPrivateEnvironment); let mut count = 0; - for element in class.elements() { + for element in class.elements { match element { - ClassElement::PrivateMethodDefinition(name, _) - | ClassElement::PrivateStaticMethodDefinition(name, _) - | ClassElement::PrivateFieldDefinition(name, _) + ClassElement::MethodDefinition(m) => { + if let ClassElementName::PrivateName(name) = m.name() { + count += 1; + let index = self.get_or_insert_private_name(*name); + self.emit_u32(index); + } + } + ClassElement::PrivateFieldDefinition(name, _) | ClassElement::PrivateStaticFieldDefinition(name, _) => { count += 1; let index = self.get_or_insert_private_name(*name); @@ -131,144 +174,87 @@ impl ByteCompiler<'_> { self.emit_binding(BindingOpcode::InitLexical, class_name.clone()); } - // TODO: set function name for getter and setters - for element in class.elements() { + for element in class.elements { match element { - ClassElement::StaticMethodDefinition(name, method_definition) => { - self.emit_opcode(Opcode::Dup); - match method_definition { - MethodDefinition::Get(expr) => match name { - PropertyName::Literal(name) => { - self.method(expr.into()); - let index = self.get_or_insert_name((*name).into()); - self.emit_with_varying_operand( - Opcode::DefineClassStaticGetterByName, - index, - ); - } - PropertyName::Computed(name_node) => { - self.compile_expr(name_node, true); - self.emit_opcode(Opcode::ToPropertyKey); - self.method(expr.into()); - self.emit_opcode(Opcode::DefineClassStaticGetterByValue); - } - }, - MethodDefinition::Set(expr) => match name { - PropertyName::Literal(name) => { - self.method(expr.into()); - let index = self.get_or_insert_name((*name).into()); - self.emit_with_varying_operand( - Opcode::DefineClassStaticSetterByName, - index, - ); - } - PropertyName::Computed(name_node) => { - self.compile_expr(name_node, true); - self.emit_opcode(Opcode::ToPropertyKey); - self.method(expr.into()); - self.emit_opcode(Opcode::DefineClassStaticSetterByValue); - } - }, - MethodDefinition::Ordinary(expr) => match name { - PropertyName::Literal(name) => { - self.method(expr.into()); - let index = self.get_or_insert_name((*name).into()); - self.emit_with_varying_operand( - Opcode::DefineClassStaticMethodByName, - index, - ); - } - PropertyName::Computed(name_node) => { - self.compile_expr(name_node, true); - self.emit_opcode(Opcode::ToPropertyKey); - self.method(expr.into()); - self.emit_opcode(Opcode::DefineClassStaticMethodByValue); - } - }, - MethodDefinition::Async(expr) => match name { - PropertyName::Literal(name) => { - self.method(expr.into()); - let index = self.get_or_insert_name((*name).into()); - self.emit_with_varying_operand( - Opcode::DefineClassStaticMethodByName, - index, - ); - } - PropertyName::Computed(name_node) => { - self.compile_expr(name_node, true); - self.emit_opcode(Opcode::ToPropertyKey); - self.method(expr.into()); - self.emit_opcode(Opcode::DefineClassStaticMethodByValue); - } - }, - MethodDefinition::Generator(expr) => match name { - PropertyName::Literal(name) => { - self.method(expr.into()); - let index = self.get_or_insert_name((*name).into()); - self.emit_with_varying_operand( - Opcode::DefineClassStaticMethodByName, - index, - ); - } - PropertyName::Computed(name_node) => { - self.compile_expr(name_node, true); - self.emit_opcode(Opcode::ToPropertyKey); - self.method(expr.into()); - self.emit_opcode(Opcode::DefineClassStaticMethodByValue); - } - }, - MethodDefinition::AsyncGenerator(expr) => match name { - PropertyName::Literal(name) => { - self.method(expr.into()); - let index = self.get_or_insert_name((*name).into()); - self.emit_with_varying_operand( - Opcode::DefineClassStaticMethodByName, - index, - ); - } - PropertyName::Computed(name_node) => { - self.compile_expr(name_node, true); - self.emit_opcode(Opcode::ToPropertyKey); - self.method(expr.into()); - self.emit_opcode(Opcode::DefineClassStaticMethodByValue); - } - }, + ClassElement::MethodDefinition(m) => { + if !m.is_static() && !m.is_private() { + self.emit_opcode(Opcode::Swap); + self.emit_opcode(Opcode::Dup); + } else { + self.emit_opcode(Opcode::Dup); } - } - ClassElement::PrivateStaticMethodDefinition(name, method_definition) => { - self.emit_opcode(Opcode::Dup); - match method_definition { - MethodDefinition::Get(expr) => { - self.method(expr.into()); - let index = self.get_or_insert_private_name(*name); - self.emit_with_varying_operand(Opcode::SetPrivateGetter, index); - } - MethodDefinition::Set(expr) => { - self.method(expr.into()); - let index = self.get_or_insert_private_name(*name); - self.emit_with_varying_operand(Opcode::SetPrivateSetter, index); - } - MethodDefinition::Ordinary(expr) => { - self.method(expr.into()); - let index = self.get_or_insert_private_name(*name); - self.emit_with_varying_operand(Opcode::SetPrivateMethod, index); - } - MethodDefinition::Async(expr) => { - self.method(expr.into()); - let index = self.get_or_insert_private_name(*name); - self.emit_with_varying_operand(Opcode::SetPrivateMethod, index); + + match m.name() { + ClassElementName::PropertyName(PropertyName::Literal(name)) => { + self.method(m.into()); + let index = self.get_or_insert_name((*name).into()); + let opcode = match (m.is_static(), m.kind()) { + (true, MethodDefinitionKind::Get) => { + Opcode::DefineClassStaticGetterByName + } + (true, MethodDefinitionKind::Set) => { + Opcode::DefineClassStaticSetterByName + } + (true, _) => Opcode::DefineClassStaticMethodByName, + (false, MethodDefinitionKind::Get) => { + Opcode::DefineClassGetterByName + } + (false, MethodDefinitionKind::Set) => { + Opcode::DefineClassSetterByName + } + (false, _) => Opcode::DefineClassMethodByName, + }; + self.emit_with_varying_operand(opcode, index); } - MethodDefinition::Generator(expr) => { - self.method(expr.into()); - let index = self.get_or_insert_private_name(*name); - self.emit_with_varying_operand(Opcode::SetPrivateMethod, index); + ClassElementName::PropertyName(PropertyName::Computed(name)) => { + self.compile_expr(name, true); + self.emit_opcode(Opcode::ToPropertyKey); + self.method(m.into()); + let opcode = match (m.is_static(), m.kind()) { + (true, MethodDefinitionKind::Get) => { + Opcode::DefineClassStaticGetterByValue + } + (true, MethodDefinitionKind::Set) => { + Opcode::DefineClassStaticSetterByValue + } + (true, _) => Opcode::DefineClassStaticMethodByValue, + (false, MethodDefinitionKind::Get) => { + Opcode::DefineClassGetterByValue + } + (false, MethodDefinitionKind::Set) => { + Opcode::DefineClassSetterByValue + } + (false, _) => Opcode::DefineClassMethodByValue, + }; + self.emit_opcode(opcode); } - MethodDefinition::AsyncGenerator(expr) => { - self.method(expr.into()); + ClassElementName::PrivateName(name) => { let index = self.get_or_insert_private_name(*name); - self.emit_with_varying_operand(Opcode::SetPrivateMethod, index); + let opcode = match (m.is_static(), m.kind()) { + (true, MethodDefinitionKind::Get) => Opcode::SetPrivateGetter, + (true, MethodDefinitionKind::Set) => Opcode::SetPrivateSetter, + (true, _) => Opcode::SetPrivateMethod, + (false, MethodDefinitionKind::Get) => { + Opcode::PushClassPrivateGetter + } + (false, MethodDefinitionKind::Set) => { + Opcode::PushClassPrivateSetter + } + (false, _) => { + self.emit(Opcode::RotateLeft, &[Operand::U8(3)]); + self.emit_opcode(Opcode::Dup); + self.emit(Opcode::RotateRight, &[Operand::U8(4)]); + Opcode::PushClassPrivateMethod + } + }; + self.method(m.into()); + self.emit_with_varying_operand(opcode, index); } } + + if !m.is_static() && !m.is_private() { + self.emit_opcode(Opcode::Swap); + } } ClassElement::FieldDefinition(name, field) => { self.emit_opcode(Opcode::Dup); @@ -294,11 +280,13 @@ impl ByteCompiler<'_> { // Function environment let _ = field_compiler.push_compile_environment(true); - if let Some(node) = field { + let is_anonymous_function = if let Some(node) = field { field_compiler.compile_expr(node, true); + node.is_anonymous_function_definition() } else { field_compiler.emit_opcode(Opcode::PushUndefined); - } + false + }; field_compiler.emit_opcode(Opcode::SetReturnValue); field_compiler.code_block_flags |= CodeBlockFlags::IN_CLASS_FIELD_INITIALIZER; @@ -306,7 +294,10 @@ impl ByteCompiler<'_> { let code = Gc::new(field_compiler.finish()); let index = self.push_function_to_constants(code); self.emit_with_varying_operand(Opcode::GetFunction, index); - self.emit_opcode(Opcode::PushClassField); + self.emit( + Opcode::PushClassField, + &[Operand::Bool(is_anonymous_function)], + ); } ClassElement::PrivateFieldDefinition(name, field) => { self.emit_opcode(Opcode::Dup); @@ -360,11 +351,13 @@ impl ByteCompiler<'_> { self.in_with, ); let _ = field_compiler.push_compile_environment(true); - if let Some(node) = field { + let is_anonymous_function = if let Some(node) = field { field_compiler.compile_expr(node, true); + node.is_anonymous_function_definition() } else { field_compiler.emit_opcode(Opcode::PushUndefined); - } + false + }; field_compiler.emit_opcode(Opcode::SetReturnValue); field_compiler.code_block_flags |= CodeBlockFlags::IN_CLASS_FIELD_INITIALIZER; @@ -372,7 +365,11 @@ impl ByteCompiler<'_> { let code = field_compiler.finish(); let code = Gc::new(code); - static_elements.push(StaticElement::StaticField((code, name_index))); + static_elements.push(StaticElement::StaticField(( + code, + name_index, + is_anonymous_function, + ))); } ClassElement::PrivateStaticFieldDefinition(name, field) => { self.emit_opcode(Opcode::Dup); @@ -409,156 +406,6 @@ impl ByteCompiler<'_> { let code = Gc::new(compiler.finish()); static_elements.push(StaticElement::StaticBlock(code)); } - ClassElement::PrivateMethodDefinition(name, method_definition) => { - self.emit_opcode(Opcode::Dup); - match method_definition { - MethodDefinition::Get(expr) => { - self.method(expr.into()); - let index = self.get_or_insert_private_name(*name); - self.emit_with_varying_operand(Opcode::PushClassPrivateGetter, index); - } - MethodDefinition::Set(expr) => { - self.method(expr.into()); - let index = self.get_or_insert_private_name(*name); - self.emit_with_varying_operand(Opcode::PushClassPrivateSetter, index); - } - MethodDefinition::Ordinary(expr) => { - self.emit(Opcode::RotateLeft, &[Operand::U8(3)]); - self.emit_opcode(Opcode::Dup); - self.emit(Opcode::RotateRight, &[Operand::U8(4)]); - self.method(expr.into()); - let index = self.get_or_insert_private_name(*name); - self.emit_with_varying_operand(Opcode::PushClassPrivateMethod, index); - } - MethodDefinition::Async(expr) => { - self.emit(Opcode::RotateLeft, &[Operand::U8(3)]); - self.emit_opcode(Opcode::Dup); - self.emit(Opcode::RotateRight, &[Operand::U8(4)]); - self.method(expr.into()); - let index = self.get_or_insert_private_name(*name); - self.emit_with_varying_operand(Opcode::PushClassPrivateMethod, index); - } - MethodDefinition::Generator(expr) => { - self.emit(Opcode::RotateLeft, &[Operand::U8(3)]); - self.emit_opcode(Opcode::Dup); - self.emit(Opcode::RotateRight, &[Operand::U8(4)]); - self.method(expr.into()); - let index = self.get_or_insert_private_name(*name); - self.emit_with_varying_operand(Opcode::PushClassPrivateMethod, index); - } - MethodDefinition::AsyncGenerator(expr) => { - self.emit(Opcode::RotateLeft, &[Operand::U8(3)]); - self.emit_opcode(Opcode::Dup); - self.emit(Opcode::RotateRight, &[Operand::U8(4)]); - self.method(expr.into()); - let index = self.get_or_insert_private_name(*name); - self.emit_with_varying_operand(Opcode::PushClassPrivateMethod, index); - } - } - } - ClassElement::MethodDefinition(name, method_definition) => { - self.emit_opcode(Opcode::Swap); - self.emit_opcode(Opcode::Dup); - match method_definition { - MethodDefinition::Get(expr) => match name { - PropertyName::Literal(name) => { - self.method(expr.into()); - let index = self.get_or_insert_name((*name).into()); - self.emit_with_varying_operand( - Opcode::DefineClassGetterByName, - index, - ); - } - PropertyName::Computed(name_node) => { - self.compile_expr(name_node, true); - self.emit_opcode(Opcode::ToPropertyKey); - self.method(expr.into()); - self.emit_opcode(Opcode::DefineClassGetterByValue); - } - }, - MethodDefinition::Set(expr) => match name { - PropertyName::Literal(name) => { - self.method(expr.into()); - let index = self.get_or_insert_name((*name).into()); - self.emit_with_varying_operand( - Opcode::DefineClassSetterByName, - index, - ); - } - PropertyName::Computed(name_node) => { - self.compile_expr(name_node, true); - self.emit_opcode(Opcode::ToPropertyKey); - self.method(expr.into()); - self.emit_opcode(Opcode::DefineClassSetterByValue); - } - }, - MethodDefinition::Ordinary(expr) => match name { - PropertyName::Literal(name) => { - self.method(expr.into()); - let index = self.get_or_insert_name((*name).into()); - self.emit_with_varying_operand( - Opcode::DefineClassMethodByName, - index, - ); - } - PropertyName::Computed(name_node) => { - self.compile_expr(name_node, true); - self.emit_opcode(Opcode::ToPropertyKey); - self.method(expr.into()); - self.emit_opcode(Opcode::DefineClassMethodByValue); - } - }, - MethodDefinition::Async(expr) => match name { - PropertyName::Literal(name) => { - self.method(expr.into()); - let index = self.get_or_insert_name((*name).into()); - self.emit_with_varying_operand( - Opcode::DefineClassMethodByName, - index, - ); - } - PropertyName::Computed(name_node) => { - self.compile_expr(name_node, true); - self.emit_opcode(Opcode::ToPropertyKey); - self.method(expr.into()); - self.emit_opcode(Opcode::DefineClassMethodByValue); - } - }, - MethodDefinition::Generator(expr) => match name { - PropertyName::Literal(name) => { - self.method(expr.into()); - let index = self.get_or_insert_name((*name).into()); - self.emit_with_varying_operand( - Opcode::DefineClassMethodByName, - index, - ); - } - PropertyName::Computed(name_node) => { - self.compile_expr(name_node, true); - self.emit_opcode(Opcode::ToPropertyKey); - self.method(expr.into()); - self.emit_opcode(Opcode::DefineClassMethodByValue); - } - }, - MethodDefinition::AsyncGenerator(expr) => match name { - PropertyName::Literal(name) => { - self.method(expr.into()); - let index = self.get_or_insert_name((*name).into()); - self.emit_with_varying_operand( - Opcode::DefineClassMethodByName, - index, - ); - } - PropertyName::Computed(name_node) => { - self.compile_expr(name_node, true); - self.emit_opcode(Opcode::ToPropertyKey); - self.method(expr.into()); - self.emit_opcode(Opcode::DefineClassMethodByValue); - } - }, - } - self.emit_opcode(Opcode::Swap); - } } } @@ -572,7 +419,7 @@ impl ByteCompiler<'_> { self.emit_with_varying_operand(Opcode::Call, 0); self.emit_opcode(Opcode::Pop); } - StaticElement::StaticField((code, name_index)) => { + StaticElement::StaticField((code, name_index, is_anonymous_function)) => { self.emit_opcode(Opcode::Dup); self.emit_opcode(Opcode::Dup); let index = self.push_function_to_constants(code); @@ -583,7 +430,16 @@ impl ByteCompiler<'_> { self.emit_with_varying_operand(Opcode::DefineOwnPropertyByName, name_index); } else { self.emit(Opcode::RotateLeft, &[Operand::U8(5)]); - self.emit_opcode(Opcode::Swap); + if is_anonymous_function { + self.emit_opcode(Opcode::Dup); + self.emit(Opcode::RotateLeft, &[Operand::U8(3)]); + self.emit_opcode(Opcode::Swap); + self.emit_opcode(Opcode::ToPropertyKey); + self.emit_opcode(Opcode::Swap); + self.emit(Opcode::SetFunctionName, &[Operand::U8(0)]); + } else { + self.emit_opcode(Opcode::Swap); + } self.emit_opcode(Opcode::DefineOwnPropertyByValue); } } diff --git a/core/engine/src/bytecompiler/declarations.rs b/core/engine/src/bytecompiler/declarations.rs index d5616fbf00..439e7de5a2 100644 --- a/core/engine/src/bytecompiler/declarations.rs +++ b/core/engine/src/bytecompiler/declarations.rs @@ -81,19 +81,15 @@ pub(crate) fn global_declaration_instantiation_context( // a. If d is not either a VariableDeclaration, a ForBinding, or a BindingIdentifier, then // a.i. Assert: d is either a FunctionDeclaration, a GeneratorDeclaration, an AsyncFunctionDeclaration, or an AsyncGeneratorDeclaration. // a.ii. NOTE: If there are multiple function declarations for the same name, the last declaration is used. + // a.iii. Let fn be the sole element of the BoundNames of d. let name = match declaration { - VarScopedDeclaration::Function(f) => f.name(), - VarScopedDeclaration::Generator(f) => f.name(), - VarScopedDeclaration::AsyncFunction(f) => f.name(), - VarScopedDeclaration::AsyncGenerator(f) => f.name(), - VarScopedDeclaration::VariableDeclaration(_) => { - continue; - } + VarScopedDeclaration::FunctionDeclaration(f) => f.name(), + VarScopedDeclaration::GeneratorDeclaration(f) => f.name(), + VarScopedDeclaration::AsyncFunctionDeclaration(f) => f.name(), + VarScopedDeclaration::AsyncGeneratorDeclaration(f) => f.name(), + VarScopedDeclaration::VariableDeclaration(_) => continue, }; - // a.iii. Let fn be the sole element of the BoundNames of d. - let name = name.expect("function declaration must have a name"); - // a.iv. If declaredFunctionNames does not contain fn, then if !declared_function_names.contains(&name) { // SKIP: 1. Let fnDefinable be ? env.CanDeclareGlobalFunction(fn). @@ -255,19 +251,15 @@ pub(crate) fn eval_declaration_instantiation_context( // a. If d is not either a VariableDeclaration, a ForBinding, or a BindingIdentifier, then // a.i. Assert: d is either a FunctionDeclaration, a GeneratorDeclaration, an AsyncFunctionDeclaration, or an AsyncGeneratorDeclaration. // a.ii. NOTE: If there are multiple function declarations for the same name, the last declaration is used. + // a.iii. Let fn be the sole element of the BoundNames of d. let name = match &declaration { - VarScopedDeclaration::Function(f) => f.name(), - VarScopedDeclaration::Generator(f) => f.name(), - VarScopedDeclaration::AsyncFunction(f) => f.name(), - VarScopedDeclaration::AsyncGenerator(f) => f.name(), - VarScopedDeclaration::VariableDeclaration(_) => { - continue; - } + VarScopedDeclaration::FunctionDeclaration(f) => f.name(), + VarScopedDeclaration::GeneratorDeclaration(f) => f.name(), + VarScopedDeclaration::AsyncFunctionDeclaration(f) => f.name(), + VarScopedDeclaration::AsyncGeneratorDeclaration(f) => f.name(), + VarScopedDeclaration::VariableDeclaration(_) => continue, }; - // a.iii. Let fn be the sole element of the BoundNames of d. - let name = name.expect("function declaration must have a name"); - // a.iv. If declaredFunctionNames does not contain fn, then if !declared_function_names.contains(&name) { // SKIP: 1. If varEnv is a Global Environment Record, then @@ -448,19 +440,15 @@ impl ByteCompiler<'_> { // a. If d is not either a VariableDeclaration, a ForBinding, or a BindingIdentifier, then // a.i. Assert: d is either a FunctionDeclaration, a GeneratorDeclaration, an AsyncFunctionDeclaration, or an AsyncGeneratorDeclaration. // a.ii. NOTE: If there are multiple function declarations for the same name, the last declaration is used. + // a.iii. Let fn be the sole element of the BoundNames of d. let name = match declaration { - VarScopedDeclaration::Function(f) => f.name(), - VarScopedDeclaration::Generator(f) => f.name(), - VarScopedDeclaration::AsyncFunction(f) => f.name(), - VarScopedDeclaration::AsyncGenerator(f) => f.name(), - VarScopedDeclaration::VariableDeclaration(_) => { - continue; - } + VarScopedDeclaration::FunctionDeclaration(f) => f.name(), + VarScopedDeclaration::GeneratorDeclaration(f) => f.name(), + VarScopedDeclaration::AsyncFunctionDeclaration(f) => f.name(), + VarScopedDeclaration::AsyncGeneratorDeclaration(f) => f.name(), + VarScopedDeclaration::VariableDeclaration(_) => continue, }; - // a.iii. Let fn be the sole element of the BoundNames of d. - let name = name.expect("function declaration must have a name"); - // a.iv. If declaredFunctionNames does not contain fn, then if !declared_function_names.contains(&name) { // 1. Let fnDefinable be ? env.CanDeclareGlobalFunction(fn). @@ -536,7 +524,7 @@ impl ByteCompiler<'_> { // 1. Perform ? env.CreateMutableBinding(dn, false). if let StatementListItem::Declaration(declaration) = statement { match declaration { - Declaration::Class(class) => { + Declaration::ClassDeclaration(class) => { for name in bound_names(class) { let name = name.to_js_string(self.interner()); env.create_mutable_binding(name, false); @@ -563,23 +551,20 @@ impl ByteCompiler<'_> { for function in functions_to_initialize { // a. Let fn be the sole element of the BoundNames of f. let (name, generator, r#async, parameters, body) = match &function { - VarScopedDeclaration::Function(f) => { + VarScopedDeclaration::FunctionDeclaration(f) => { (f.name(), false, false, f.parameters(), f.body()) } - VarScopedDeclaration::Generator(f) => { + VarScopedDeclaration::GeneratorDeclaration(f) => { (f.name(), true, false, f.parameters(), f.body()) } - VarScopedDeclaration::AsyncFunction(f) => { + VarScopedDeclaration::AsyncFunctionDeclaration(f) => { (f.name(), false, true, f.parameters(), f.body()) } - VarScopedDeclaration::AsyncGenerator(f) => { + VarScopedDeclaration::AsyncGeneratorDeclaration(f) => { (f.name(), true, true, f.parameters(), f.body()) } - VarScopedDeclaration::VariableDeclaration(_) => { - continue; - } + VarScopedDeclaration::VariableDeclaration(_) => continue, }; - let name = name.expect("function declaration must have a name"); let code = FunctionCompiler::new() .name(name.sym().to_js_string(self.interner())) @@ -684,16 +669,16 @@ impl ByteCompiler<'_> { // TODO: Support B.3.2.6. for d in declarations { match d { - LexicallyScopedDeclaration::Function(function) => { + LexicallyScopedDeclaration::FunctionDeclaration(function) => { self.function_with_binding(function.into(), NodeKind::Declaration, false); } - LexicallyScopedDeclaration::Generator(function) => { + LexicallyScopedDeclaration::GeneratorDeclaration(function) => { self.function_with_binding(function.into(), NodeKind::Declaration, false); } - LexicallyScopedDeclaration::AsyncFunction(function) => { + LexicallyScopedDeclaration::AsyncFunctionDeclaration(function) => { self.function_with_binding(function.into(), NodeKind::Declaration, false); } - LexicallyScopedDeclaration::AsyncGenerator(function) => { + LexicallyScopedDeclaration::AsyncGeneratorDeclaration(function) => { self.function_with_binding(function.into(), NodeKind::Declaration, false); } _ => {} @@ -795,19 +780,14 @@ impl ByteCompiler<'_> { // a. If d is not either a VariableDeclaration, a ForBinding, or a BindingIdentifier, then // a.i. Assert: d is either a FunctionDeclaration, a GeneratorDeclaration, an AsyncFunctionDeclaration, or an AsyncGeneratorDeclaration. // a.ii. NOTE: If there are multiple function declarations for the same name, the last declaration is used. + // a.iii. Let fn be the sole element of the BoundNames of d. let name = match &declaration { - VarScopedDeclaration::Function(f) => f.name(), - VarScopedDeclaration::Generator(f) => f.name(), - VarScopedDeclaration::AsyncFunction(f) => f.name(), - VarScopedDeclaration::AsyncGenerator(f) => f.name(), - VarScopedDeclaration::VariableDeclaration(_) => { - continue; - } + VarScopedDeclaration::FunctionDeclaration(f) => f.name(), + VarScopedDeclaration::GeneratorDeclaration(f) => f.name(), + VarScopedDeclaration::AsyncFunctionDeclaration(f) => f.name(), + VarScopedDeclaration::AsyncGeneratorDeclaration(f) => f.name(), + VarScopedDeclaration::VariableDeclaration(_) => continue, }; - - // a.iii. Let fn be the sole element of the BoundNames of d. - let name = name.expect("function declaration must have a name"); - // a.iv. If declaredFunctionNames does not contain fn, then if !declared_function_names.contains(&name) { // 1. If varEnv is a Global Environment Record, then @@ -906,7 +886,7 @@ impl ByteCompiler<'_> { // 1. Perform ? lexEnv.CreateMutableBinding(dn, false). if let StatementListItem::Declaration(declaration) = statement { match declaration { - Declaration::Class(class) => { + Declaration::ClassDeclaration(class) => { for name in bound_names(class) { let name = name.to_js_string(self.interner()); lex_env.create_mutable_binding(name, false); @@ -933,23 +913,23 @@ impl ByteCompiler<'_> { for function in functions_to_initialize { // a. Let fn be the sole element of the BoundNames of f. let (name, generator, r#async, parameters, body) = match &function { - VarScopedDeclaration::Function(f) => { + VarScopedDeclaration::FunctionDeclaration(f) => { (f.name(), false, false, f.parameters(), f.body()) } - VarScopedDeclaration::Generator(f) => { + VarScopedDeclaration::GeneratorDeclaration(f) => { (f.name(), true, false, f.parameters(), f.body()) } - VarScopedDeclaration::AsyncFunction(f) => { + VarScopedDeclaration::AsyncFunctionDeclaration(f) => { (f.name(), false, true, f.parameters(), f.body()) } - VarScopedDeclaration::AsyncGenerator(f) => { + VarScopedDeclaration::AsyncGeneratorDeclaration(f) => { (f.name(), true, true, f.parameters(), f.body()) } VarScopedDeclaration::VariableDeclaration(_) => { continue; } }; - let name = name.expect("function declaration must have a name"); + let code = FunctionCompiler::new() .name(name.sym().to_js_string(self.interner())) .generator(generator) @@ -1094,19 +1074,19 @@ impl ByteCompiler<'_> { for declaration in var_declarations.iter().rev() { // a. If d is neither a VariableDeclaration nor a ForBinding nor a BindingIdentifier, then // a.i. Assert: d is either a FunctionDeclaration, a GeneratorDeclaration, an AsyncFunctionDeclaration, or an AsyncGeneratorDeclaration. - let function = match declaration { - VarScopedDeclaration::Function(f) => FunctionSpec::from(f), - VarScopedDeclaration::Generator(f) => FunctionSpec::from(f), - VarScopedDeclaration::AsyncFunction(f) => FunctionSpec::from(f), - VarScopedDeclaration::AsyncGenerator(f) => FunctionSpec::from(f), + // a.ii. Let fn be the sole element of the BoundNames of d. + let (name, function) = match declaration { + VarScopedDeclaration::FunctionDeclaration(f) => (f.name(), FunctionSpec::from(f)), + VarScopedDeclaration::GeneratorDeclaration(f) => (f.name(), FunctionSpec::from(f)), + VarScopedDeclaration::AsyncFunctionDeclaration(f) => { + (f.name(), FunctionSpec::from(f)) + } + VarScopedDeclaration::AsyncGeneratorDeclaration(f) => { + (f.name(), FunctionSpec::from(f)) + } VarScopedDeclaration::VariableDeclaration(_) => continue, }; - // a.ii. Let fn be the sole element of the BoundNames of d. - let name = function - .name - .expect("function declaration must have a name"); - // a.iii. If functionNames does not contain fn, then if !function_names.contains(&name) { // 1. Insert fn as the first element of functionNames. @@ -1427,7 +1407,7 @@ impl ByteCompiler<'_> { for statement in &**body.statements() { if let StatementListItem::Declaration(declaration) = statement { match declaration { - Declaration::Class(class) => { + Declaration::ClassDeclaration(class) => { for name in bound_names(class) { let name = name.to_js_string(self.interner()); lex_env.create_mutable_binding(name, false); diff --git a/core/engine/src/bytecompiler/expression/mod.rs b/core/engine/src/bytecompiler/expression/mod.rs index fb229b41c6..c5f72b8205 100644 --- a/core/engine/src/bytecompiler/expression/mod.rs +++ b/core/engine/src/bytecompiler/expression/mod.rs @@ -4,6 +4,8 @@ mod object_literal; mod unary; mod update; +use std::ops::Deref; + use super::{Access, Callable, NodeKind, Operand, ToJsString}; use crate::{ bytecompiler::{ByteCompiler, Literal}, @@ -133,7 +135,7 @@ impl ByteCompiler<'_> { self.access_get(Access::This, use_expr); } Expression::Spread(spread) => self.compile_expr(spread.target(), true), - Expression::Function(function) => { + Expression::FunctionExpression(function) => { self.function_with_binding(function.into(), NodeKind::Expression, use_expr); } Expression::ArrowFunction(function) => { @@ -142,13 +144,13 @@ impl ByteCompiler<'_> { Expression::AsyncArrowFunction(function) => { self.function_with_binding(function.into(), NodeKind::Expression, use_expr); } - Expression::Generator(function) => { + Expression::GeneratorExpression(function) => { self.function_with_binding(function.into(), NodeKind::Expression, use_expr); } - Expression::AsyncFunction(function) => { + Expression::AsyncFunctionExpression(function) => { self.function_with_binding(function.into(), NodeKind::Expression, use_expr); } - Expression::AsyncGenerator(function) => { + Expression::AsyncGeneratorExpression(function) => { self.function_with_binding(function.into(), NodeKind::Expression, use_expr); } Expression::Call(call) => self.call(Callable::Call(call), use_expr), @@ -289,7 +291,7 @@ impl ByteCompiler<'_> { self.emit_with_varying_operand(Opcode::Call, template.exprs().len() as u32 + 1); } - Expression::Class(class) => self.class(class, true), + Expression::ClassExpression(class) => self.class(class.deref().into(), true), Expression::SuperCall(super_call) => { self.emit_opcode(Opcode::SuperCallPrepare); diff --git a/core/engine/src/bytecompiler/expression/object_literal.rs b/core/engine/src/bytecompiler/expression/object_literal.rs index 29b67ce327..faa165ec4c 100644 --- a/core/engine/src/bytecompiler/expression/object_literal.rs +++ b/core/engine/src/bytecompiler/expression/object_literal.rs @@ -3,8 +3,8 @@ use crate::{ vm::Opcode, }; use boa_ast::{ - expression::literal::ObjectLiteral, - property::{MethodDefinition, PropertyDefinition, PropertyName}, + expression::literal::{ObjectLiteral, PropertyDefinition}, + property::{MethodDefinitionKind, PropertyName}, Expression, }; use boa_interner::Sym; @@ -43,110 +43,29 @@ impl ByteCompiler<'_> { self.emit_opcode(Opcode::DefineOwnPropertyByValue); } }, - PropertyDefinition::MethodDefinition(name, kind) => match kind { - MethodDefinition::Get(expr) => match name { + PropertyDefinition::MethodDefinition(m) => { + let kind = match m.kind() { + MethodDefinitionKind::Get => MethodKind::Get, + MethodDefinitionKind::Set => MethodKind::Set, + _ => MethodKind::Ordinary, + }; + match m.name() { PropertyName::Literal(name) => { - let mut method: FunctionSpec<'_> = expr.into(); - method.name = Some((*name).into()); - self.object_method(method, MethodKind::Get); + let opcode = match kind { + MethodKind::Get => Opcode::SetPropertyGetterByName, + MethodKind::Set => Opcode::SetPropertySetterByName, + MethodKind::Ordinary => Opcode::DefineOwnPropertyByName, + }; + self.object_method((m, *name).into(), kind); self.emit_opcode(Opcode::SetHomeObject); let index = self.get_or_insert_name((*name).into()); - self.emit_with_varying_operand(Opcode::SetPropertyGetterByName, index); + self.emit_with_varying_operand(opcode, index); } PropertyName::Computed(name_node) => { - self.compile_object_literal_computed_method( - name_node, - expr.into(), - MethodKind::Get, - ); + self.compile_object_literal_computed_method(name_node, m.into(), kind); } - }, - MethodDefinition::Set(expr) => match name { - PropertyName::Literal(name) => { - let mut method: FunctionSpec<'_> = expr.into(); - method.name = Some((*name).into()); - self.object_method(method, MethodKind::Set); - self.emit_opcode(Opcode::SetHomeObject); - let index = self.get_or_insert_name((*name).into()); - self.emit_with_varying_operand(Opcode::SetPropertySetterByName, index); - } - PropertyName::Computed(name_node) => { - self.compile_object_literal_computed_method( - name_node, - expr.into(), - MethodKind::Set, - ); - } - }, - MethodDefinition::Ordinary(expr) => match name { - PropertyName::Literal(name) => { - let mut method: FunctionSpec<'_> = expr.into(); - method.name = Some((*name).into()); - self.object_method(method, MethodKind::Ordinary); - self.emit_opcode(Opcode::SetHomeObject); - let index = self.get_or_insert_name((*name).into()); - self.emit_with_varying_operand(Opcode::DefineOwnPropertyByName, index); - } - PropertyName::Computed(name_node) => { - self.compile_object_literal_computed_method( - name_node, - expr.into(), - MethodKind::Ordinary, - ); - } - }, - MethodDefinition::Async(expr) => match name { - PropertyName::Literal(name) => { - let mut method: FunctionSpec<'_> = expr.into(); - method.name = Some((*name).into()); - self.object_method(method, MethodKind::Ordinary); - self.emit_opcode(Opcode::SetHomeObject); - let index = self.get_or_insert_name((*name).into()); - self.emit_with_varying_operand(Opcode::DefineOwnPropertyByName, index); - } - PropertyName::Computed(name_node) => { - self.compile_object_literal_computed_method( - name_node, - expr.into(), - MethodKind::Ordinary, - ); - } - }, - MethodDefinition::Generator(expr) => match name { - PropertyName::Literal(name) => { - let mut method: FunctionSpec<'_> = expr.into(); - method.name = Some((*name).into()); - self.object_method(method, MethodKind::Ordinary); - self.emit_opcode(Opcode::SetHomeObject); - let index = self.get_or_insert_name((*name).into()); - self.emit_with_varying_operand(Opcode::DefineOwnPropertyByName, index); - } - PropertyName::Computed(name_node) => { - self.compile_object_literal_computed_method( - name_node, - expr.into(), - MethodKind::Ordinary, - ); - } - }, - MethodDefinition::AsyncGenerator(expr) => match name { - PropertyName::Literal(name) => { - let mut method: FunctionSpec<'_> = expr.into(); - method.name = Some((*name).into()); - self.object_method(method, MethodKind::Ordinary); - self.emit_opcode(Opcode::SetHomeObject); - let index = self.get_or_insert_name((*name).into()); - self.emit_with_varying_operand(Opcode::DefineOwnPropertyByName, index); - } - PropertyName::Computed(name_node) => { - self.compile_object_literal_computed_method( - name_node, - expr.into(), - MethodKind::Ordinary, - ); - } - }, - }, + } + } PropertyDefinition::SpreadObject(expr) => { self.compile_expr(expr, true); self.emit_opcode(Opcode::Swap); diff --git a/core/engine/src/bytecompiler/mod.rs b/core/engine/src/bytecompiler/mod.rs index 4ba14b79a7..2d9f3000aa 100644 --- a/core/engine/src/bytecompiler/mod.rs +++ b/core/engine/src/bytecompiler/mod.rs @@ -27,20 +27,25 @@ use boa_ast::{ declaration::{Binding, LexicalDeclaration, VarDeclaration}, expression::{ access::{PropertyAccess, PropertyAccessField}, + literal::ObjectMethodDefinition, operator::{assign::AssignTarget, update::UpdateTarget}, Call, Identifier, New, Optional, OptionalOperationKind, }, function::{ - ArrowFunction, AsyncArrowFunction, AsyncFunction, AsyncGenerator, Class, - FormalParameterList, Function, FunctionBody, Generator, PrivateName, + ArrowFunction, AsyncArrowFunction, AsyncFunctionDeclaration, AsyncFunctionExpression, + AsyncGeneratorDeclaration, AsyncGeneratorExpression, ClassMethodDefinition, + FormalParameterList, FunctionBody, FunctionDeclaration, FunctionExpression, + GeneratorDeclaration, GeneratorExpression, PrivateName, }, operations::returns_value, pattern::Pattern, + property::MethodDefinitionKind, Declaration, Expression, Statement, StatementList, StatementListItem, }; use boa_gc::Gc; use boa_interner::{Interner, Sym}; use boa_macros::js_str; +use class::ClassSpec; use rustc_hash::FxHashMap; use thin_vec::ThinVec; @@ -116,8 +121,56 @@ pub(crate) struct FunctionSpec<'a> { pub(crate) has_binding_identifier: bool, } -impl<'a> From<&'a Function> for FunctionSpec<'a> { - fn from(function: &'a Function) -> Self { +impl<'a> From<&'a FunctionDeclaration> for FunctionSpec<'a> { + fn from(function: &'a FunctionDeclaration) -> Self { + FunctionSpec { + kind: FunctionKind::Ordinary, + name: Some(function.name()), + parameters: function.parameters(), + body: function.body(), + has_binding_identifier: true, + } + } +} + +impl<'a> From<&'a GeneratorDeclaration> for FunctionSpec<'a> { + fn from(function: &'a GeneratorDeclaration) -> Self { + FunctionSpec { + kind: FunctionKind::Generator, + name: Some(function.name()), + parameters: function.parameters(), + body: function.body(), + has_binding_identifier: true, + } + } +} + +impl<'a> From<&'a AsyncFunctionDeclaration> for FunctionSpec<'a> { + fn from(function: &'a AsyncFunctionDeclaration) -> Self { + FunctionSpec { + kind: FunctionKind::Async, + name: Some(function.name()), + parameters: function.parameters(), + body: function.body(), + has_binding_identifier: true, + } + } +} + +impl<'a> From<&'a AsyncGeneratorDeclaration> for FunctionSpec<'a> { + fn from(function: &'a AsyncGeneratorDeclaration) -> Self { + FunctionSpec { + kind: FunctionKind::AsyncGenerator, + name: Some(function.name()), + parameters: function.parameters(), + body: function.body(), + has_binding_identifier: true, + } + } +} + +impl<'a> From<&'a FunctionExpression> for FunctionSpec<'a> { + fn from(function: &'a FunctionExpression) -> Self { FunctionSpec { kind: FunctionKind::Ordinary, name: function.name(), @@ -152,8 +205,8 @@ impl<'a> From<&'a AsyncArrowFunction> for FunctionSpec<'a> { } } -impl<'a> From<&'a AsyncFunction> for FunctionSpec<'a> { - fn from(function: &'a AsyncFunction) -> Self { +impl<'a> From<&'a AsyncFunctionExpression> for FunctionSpec<'a> { + fn from(function: &'a AsyncFunctionExpression) -> Self { FunctionSpec { kind: FunctionKind::Async, name: function.name(), @@ -164,8 +217,8 @@ impl<'a> From<&'a AsyncFunction> for FunctionSpec<'a> { } } -impl<'a> From<&'a Generator> for FunctionSpec<'a> { - fn from(function: &'a Generator) -> Self { +impl<'a> From<&'a GeneratorExpression> for FunctionSpec<'a> { + fn from(function: &'a GeneratorExpression) -> Self { FunctionSpec { kind: FunctionKind::Generator, name: function.name(), @@ -176,8 +229,8 @@ impl<'a> From<&'a Generator> for FunctionSpec<'a> { } } -impl<'a> From<&'a AsyncGenerator> for FunctionSpec<'a> { - fn from(function: &'a AsyncGenerator) -> Self { +impl<'a> From<&'a AsyncGeneratorExpression> for FunctionSpec<'a> { + fn from(function: &'a AsyncGeneratorExpression) -> Self { FunctionSpec { kind: FunctionKind::AsyncGenerator, name: function.name(), @@ -188,6 +241,63 @@ impl<'a> From<&'a AsyncGenerator> for FunctionSpec<'a> { } } +impl<'a> From<&'a ClassMethodDefinition> for FunctionSpec<'a> { + fn from(method: &'a ClassMethodDefinition) -> Self { + let kind = match method.kind() { + MethodDefinitionKind::Generator => FunctionKind::Generator, + MethodDefinitionKind::AsyncGenerator => FunctionKind::AsyncGenerator, + MethodDefinitionKind::Async => FunctionKind::Async, + _ => FunctionKind::Ordinary, + }; + + FunctionSpec { + kind, + name: None, + parameters: method.parameters(), + body: method.body(), + has_binding_identifier: false, + } + } +} + +impl<'a> From<&'a ObjectMethodDefinition> for FunctionSpec<'a> { + fn from(method: &'a ObjectMethodDefinition) -> Self { + let kind = match method.kind() { + MethodDefinitionKind::Generator => FunctionKind::Generator, + MethodDefinitionKind::AsyncGenerator => FunctionKind::AsyncGenerator, + MethodDefinitionKind::Async => FunctionKind::Async, + _ => FunctionKind::Ordinary, + }; + + FunctionSpec { + kind, + name: None, + parameters: method.parameters(), + body: method.body(), + has_binding_identifier: false, + } + } +} + +impl<'a> From<(&'a ObjectMethodDefinition, Sym)> for FunctionSpec<'a> { + fn from(method: (&'a ObjectMethodDefinition, Sym)) -> Self { + let kind = match method.0.kind() { + MethodDefinitionKind::Generator => FunctionKind::Generator, + MethodDefinitionKind::AsyncGenerator => FunctionKind::AsyncGenerator, + MethodDefinitionKind::Async => FunctionKind::Async, + _ => FunctionKind::Ordinary, + }; + + FunctionSpec { + kind, + name: Some(Identifier::new(method.1)), + parameters: method.0.parameters(), + body: method.0.body(), + has_binding_identifier: true, + } + } +} + #[derive(Debug, Clone, Copy)] pub(crate) enum MethodKind { Get, @@ -1267,10 +1377,8 @@ impl<'ctx> ByteCompiler<'ctx> { pub fn compile_decl(&mut self, decl: &Declaration, block: bool) { match decl { #[cfg(feature = "annex-b")] - Declaration::Function(function) if block => { - let name = function - .name() - .expect("function declaration must have name"); + Declaration::FunctionDeclaration(function) if block => { + let name = function.name(); if self.annex_b_function_names.contains(&name) { let name = name.to_js_string(self.interner()); let binding = self @@ -1297,7 +1405,7 @@ impl<'ctx> ByteCompiler<'ctx> { } } } - Declaration::Class(class) => self.class(class, false), + Declaration::ClassDeclaration(class) => self.class(class.into(), false), Declaration::Lexical(lexical) => self.compile_lexical_decl(lexical), _ => {} } @@ -1622,7 +1730,7 @@ impl<'ctx> ByteCompiler<'ctx> { self.compile_declaration_pattern_impl(pattern, def); } - fn class(&mut self, class: &Class, expression: bool) { + fn class(&mut self, class: ClassSpec<'_>, expression: bool) { self.compile_class(class, expression); } } diff --git a/core/engine/src/bytecompiler/module.rs b/core/engine/src/bytecompiler/module.rs index 843311c97b..06f9521cce 100644 --- a/core/engine/src/bytecompiler/module.rs +++ b/core/engine/src/bytecompiler/module.rs @@ -34,23 +34,15 @@ impl ByteCompiler<'_> { // export NamedExports ; // 1. Return empty. } - ExportDeclaration::DefaultFunction(_) - | ExportDeclaration::DefaultGenerator(_) - | ExportDeclaration::DefaultAsyncFunction(_) - | ExportDeclaration::DefaultAsyncGenerator(_) => { + ExportDeclaration::DefaultFunctionDeclaration(_) + | ExportDeclaration::DefaultGeneratorDeclaration(_) + | ExportDeclaration::DefaultAsyncFunctionDeclaration(_) + | ExportDeclaration::DefaultAsyncGeneratorDeclaration(_) => { // Already instantiated in `initialize_environment`. } ExportDeclaration::VarStatement(var) => self.compile_var_decl(var), ExportDeclaration::Declaration(decl) => self.compile_decl(decl, false), - ExportDeclaration::DefaultClassDeclaration(cl) => { - self.class(cl, cl.name().is_none()); - if cl.name().is_none() { - self.emit_binding( - BindingOpcode::InitLexical, - Sym::DEFAULT_EXPORT.to_js_string(self.interner()), - ); - } - } + ExportDeclaration::DefaultClassDeclaration(cl) => self.class(cl.into(), false), ExportDeclaration::DefaultAssignmentExpression(expr) => { let name = Sym::DEFAULT_EXPORT.to_js_string(self.interner()); self.lexical_environment diff --git a/core/engine/src/bytecompiler/statement/labelled.rs b/core/engine/src/bytecompiler/statement/labelled.rs index a723edab9e..3041c996a9 100644 --- a/core/engine/src/bytecompiler/statement/labelled.rs +++ b/core/engine/src/bytecompiler/statement/labelled.rs @@ -29,7 +29,7 @@ impl ByteCompiler<'_> { } stmt => self.compile_stmt(stmt, use_expr, true), }, - LabelledItem::Function(f) => { + LabelledItem::FunctionDeclaration(f) => { self.function_with_binding(f.into(), NodeKind::Declaration, false); } } diff --git a/core/engine/src/module/source.rs b/core/engine/src/module/source.rs index 0e488f9ddb..c8a22437e3 100644 --- a/core/engine/src/module/source.rs +++ b/core/engine/src/module/source.rs @@ -1549,31 +1549,31 @@ impl SourceTextModule { // // deferred to below. let (mut spec, locator): (FunctionSpec<'_>, _) = match declaration { - LexicallyScopedDeclaration::Function(f) => { + LexicallyScopedDeclaration::FunctionDeclaration(f) => { let name = bound_names(f)[0].to_js_string(compiler.interner()); let locator = env.create_mutable_binding(name, false); (f.into(), locator) } - LexicallyScopedDeclaration::Generator(g) => { + LexicallyScopedDeclaration::GeneratorDeclaration(g) => { let name = bound_names(g)[0].to_js_string(compiler.interner()); let locator = env.create_mutable_binding(name, false); (g.into(), locator) } - LexicallyScopedDeclaration::AsyncFunction(af) => { + LexicallyScopedDeclaration::AsyncFunctionDeclaration(af) => { let name = bound_names(af)[0].to_js_string(compiler.interner()); let locator = env.create_mutable_binding(name, false); (af.into(), locator) } - LexicallyScopedDeclaration::AsyncGenerator(ag) => { + LexicallyScopedDeclaration::AsyncGeneratorDeclaration(ag) => { let name = bound_names(ag)[0].to_js_string(compiler.interner()); let locator = env.create_mutable_binding(name, false); (ag.into(), locator) } - LexicallyScopedDeclaration::Class(class) => { + LexicallyScopedDeclaration::ClassDeclaration(class) => { for name in bound_names(class) { let name = name.to_js_string(compiler.interner()); env.create_mutable_binding(name, false); diff --git a/core/engine/src/object/operations.rs b/core/engine/src/object/operations.rs index 5d4e7a7f57..9a989b5cc2 100644 --- a/core/engine/src/object/operations.rs +++ b/core/engine/src/object/operations.rs @@ -1,6 +1,6 @@ use crate::{ builtins::{ - function::{BoundFunction, ClassFieldDefinition, OrdinaryFunction}, + function::{set_function_name, BoundFunction, ClassFieldDefinition, OrdinaryFunction}, Array, Proxy, }, context::intrinsics::{StandardConstructor, StandardConstructors}, @@ -1077,7 +1077,7 @@ impl JsObject { ) -> JsResult<()> { // 2. Let initializer be fieldRecord.[[Initializer]]. let initializer = match field_record { - ClassFieldDefinition::Public(_, function) + ClassFieldDefinition::Public(_, function, _) | ClassFieldDefinition::Private(_, function) => function, }; @@ -1095,7 +1095,18 @@ impl JsObject { } // 1. Let fieldName be fieldRecord.[[Name]]. // 6. Else, - ClassFieldDefinition::Public(field_name, _) => { + ClassFieldDefinition::Public(field_name, _, function_name) => { + if let Some(function_name) = function_name { + set_function_name( + init_value + .as_object() + .expect("init value must be a function object"), + function_name, + None, + context, + ); + } + // a. Assert: IsPropertyKey(fieldName) is true. // b. Perform ? CreateDataPropertyOrThrow(receiver, fieldName, initValue). self.create_data_property_or_throw(field_name.clone(), init_value, context)?; diff --git a/core/engine/src/tests/class.rs b/core/engine/src/tests/class.rs new file mode 100644 index 0000000000..782b55dadc --- /dev/null +++ b/core/engine/src/tests/class.rs @@ -0,0 +1,38 @@ +use crate::{run_test_actions, TestAction}; +use boa_macros::js_str; +use indoc::indoc; + +#[test] +fn class_field_initializer_name_static() { + run_test_actions([ + TestAction::run(indoc! {r#" + class C { + static a = function() {}; + static ["b"] = function() {}; + static #c = function() {}; + static c = this.#c + } + "#}), + TestAction::assert_eq("C.a.name", js_str!("a")), + TestAction::assert_eq("C.b.name", js_str!("b")), + TestAction::assert_eq("C.c.name", js_str!("#c")), + ]); +} + +#[test] +fn class_field_initializer_name() { + run_test_actions([ + TestAction::run(indoc! {r#" + class C { + a = function() {}; + ["b"] = function() {}; + #c = function() {}; + c = this.#c + } + let c = new C(); + "#}), + TestAction::assert_eq("c.a.name", js_str!("a")), + TestAction::assert_eq("c.b.name", js_str!("b")), + TestAction::assert_eq("c.c.name", js_str!("#c")), + ]); +} diff --git a/core/engine/src/tests/mod.rs b/core/engine/src/tests/mod.rs index 1bc7712fab..ca9d285946 100644 --- a/core/engine/src/tests/mod.rs +++ b/core/engine/src/tests/mod.rs @@ -4,6 +4,7 @@ use boa_macros::js_str; use indoc::indoc; mod async_generator; +mod class; mod control_flow; mod env; mod function; diff --git a/core/engine/src/vm/code_block.rs b/core/engine/src/vm/code_block.rs index b3fbb40a78..cf899f6c37 100644 --- a/core/engine/src/vm/code_block.rs +++ b/core/engine/src/vm/code_block.rs @@ -544,6 +544,11 @@ impl CodeBlock { .to_std_string_escaped(); format!("name: {name}, configurable: {configurable}") } + Instruction::PushClassField { + is_anonymous_function, + } => { + format!("is_anonymous_function: {is_anonymous_function}") + } Instruction::Pop | Instruction::Dup | Instruction::Swap @@ -645,7 +650,6 @@ impl CodeBlock { | Instruction::GeneratorYield | Instruction::AsyncGeneratorYield | Instruction::GeneratorNext - | Instruction::PushClassField | Instruction::SuperCallDerived | Instruction::Await | Instruction::NewTarget diff --git a/core/engine/src/vm/flowgraph/mod.rs b/core/engine/src/vm/flowgraph/mod.rs index 5ed0326f59..f2b540c0c4 100644 --- a/core/engine/src/vm/flowgraph/mod.rs +++ b/core/engine/src/vm/flowgraph/mod.rs @@ -429,7 +429,7 @@ impl CodeBlock { | Instruction::CreatePromiseCapability | Instruction::CompletePromiseCapability | Instruction::GeneratorNext - | Instruction::PushClassField + | Instruction::PushClassField { .. } | Instruction::SuperCallDerived | Instruction::Await | Instruction::NewTarget diff --git a/core/engine/src/vm/opcode/mod.rs b/core/engine/src/vm/opcode/mod.rs index b1dd51d9ce..70fbdde554 100644 --- a/core/engine/src/vm/opcode/mod.rs +++ b/core/engine/src/vm/opcode/mod.rs @@ -1420,10 +1420,10 @@ generate_opcodes! { /// Push a field to a class. /// - /// Operands: + /// Operands: is_anonymous_function: `bool` /// /// Stack: class, field_name, field_function **=>** - PushClassField, + PushClassField { is_anonymous_function: bool }, /// Push a private field to the class. /// diff --git a/core/engine/src/vm/opcode/push/class/field.rs b/core/engine/src/vm/opcode/push/class/field.rs index de5d1bca20..3614e41700 100644 --- a/core/engine/src/vm/opcode/push/class/field.rs +++ b/core/engine/src/vm/opcode/push/class/field.rs @@ -18,6 +18,7 @@ impl Operation for PushClassField { const COST: u8 = 6; fn execute(context: &mut Context) -> JsResult { + let is_annonymus_function = context.vm.read::() != 0; let field_function_value = context.vm.pop(); let field_name_value = context.vm.pop(); let class_value = context.vm.pop(); @@ -39,8 +40,13 @@ impl Operation for PushClassField { .downcast_mut::() .expect("class must be function object") .push_field( - field_name_key, + field_name_key.clone(), JsFunction::from_object_unchecked(field_function_object.clone()), + if is_annonymus_function { + Some(field_name_key) + } else { + None + }, ); Ok(CompletionType::Normal) } diff --git a/core/parser/src/parser/expression/assignment/arrow_function.rs b/core/parser/src/parser/expression/assignment/arrow_function.rs index d82ab442cd..2193187432 100644 --- a/core/parser/src/parser/expression/assignment/arrow_function.rs +++ b/core/parser/src/parser/expression/assignment/arrow_function.rs @@ -23,7 +23,6 @@ use ast::operations::{bound_names, lexically_declared_names}; use boa_ast::{ self as ast, declaration::Variable, - expression::Identifier, function::{FormalParameter, FormalParameterList}, operations::{contains, ContainsSymbol}, statement::Return, @@ -42,7 +41,6 @@ use boa_profiler::Profiler; /// [spec]: https://tc39.es/ecma262/#prod-ArrowFunction #[derive(Debug, Clone, Copy)] pub(in crate::parser) struct ArrowFunction { - name: Option, allow_in: AllowIn, allow_yield: AllowYield, allow_await: AllowAwait, @@ -50,20 +48,13 @@ pub(in crate::parser) struct ArrowFunction { impl ArrowFunction { /// Creates a new `ArrowFunction` parser. - pub(in crate::parser) fn new( - name: N, - allow_in: I, - allow_yield: Y, - allow_await: A, - ) -> Self + pub(in crate::parser) fn new(allow_in: I, allow_yield: Y, allow_await: A) -> Self where - N: Into>, I: Into, Y: Into, A: Into, { Self { - name: name.into(), allow_in: allow_in.into(), allow_yield: allow_yield.into(), allow_await: allow_await.into(), @@ -162,7 +153,7 @@ where interner, )?; - Ok(ast::function::ArrowFunction::new(self.name, params, body)) + Ok(ast::function::ArrowFunction::new(None, params, body)) } } @@ -241,7 +232,6 @@ where type Output = Expression; fn parse(self, cursor: &mut Cursor, interner: &mut Interner) -> ParseResult { - AssignmentExpression::new(None, self.allow_in, false, self.allow_await) - .parse(cursor, interner) + AssignmentExpression::new(self.allow_in, false, self.allow_await).parse(cursor, interner) } } diff --git a/core/parser/src/parser/expression/assignment/async_arrow_function.rs b/core/parser/src/parser/expression/assignment/async_arrow_function.rs index 500a7d9d3f..1698993f36 100644 --- a/core/parser/src/parser/expression/assignment/async_arrow_function.rs +++ b/core/parser/src/parser/expression/assignment/async_arrow_function.rs @@ -25,7 +25,6 @@ use ast::{ use boa_ast::{ self as ast, declaration::Variable, - expression::Identifier, function::{FormalParameter, FormalParameterList}, statement::Return, Punctuator, StatementList, @@ -43,21 +42,18 @@ use boa_profiler::Profiler; /// [spec]: https://tc39.es/ecma262/#prod-AsyncArrowFunction #[derive(Debug, Clone, Copy)] pub(in crate::parser) struct AsyncArrowFunction { - name: Option, allow_in: AllowIn, allow_yield: AllowYield, } impl AsyncArrowFunction { /// Creates a new `AsyncArrowFunction` parser. - pub(in crate::parser) fn new(name: N, allow_in: I, allow_yield: Y) -> Self + pub(in crate::parser) fn new(allow_in: I, allow_yield: Y) -> Self where - N: Into>, I: Into, Y: Into, { Self { - name: name.into(), allow_in: allow_in.into(), allow_yield: allow_yield.into(), } @@ -148,9 +144,7 @@ where interner, )?; - Ok(ast::function::AsyncArrowFunction::new( - self.name, params, body, - )) + Ok(ast::function::AsyncArrowFunction::new(None, params, body)) } } diff --git a/core/parser/src/parser/expression/assignment/conditional.rs b/core/parser/src/parser/expression/assignment/conditional.rs index 4258c135ef..01b1088532 100644 --- a/core/parser/src/parser/expression/assignment/conditional.rs +++ b/core/parser/src/parser/expression/assignment/conditional.rs @@ -15,10 +15,7 @@ use crate::{ }, source::ReadChar, }; -use boa_ast::{ - expression::{operator::Conditional, Identifier}, - Expression, Punctuator, -}; +use boa_ast::{expression::operator::Conditional, Expression, Punctuator}; use boa_interner::Interner; use boa_profiler::Profiler; @@ -32,7 +29,6 @@ use boa_profiler::Profiler; /// [spec]: https://tc39.es/ecma262/#prod-ConditionalExpression #[derive(Debug, Clone, Copy)] pub(in crate::parser::expression) struct ConditionalExpression { - name: Option, allow_in: AllowIn, allow_yield: AllowYield, allow_await: AllowAwait, @@ -40,20 +36,17 @@ pub(in crate::parser::expression) struct ConditionalExpression { impl ConditionalExpression { /// Creates a new `ConditionalExpression` parser. - pub(in crate::parser::expression) fn new( - name: N, + pub(in crate::parser::expression) fn new( allow_in: I, allow_yield: Y, allow_await: A, ) -> Self where - N: Into>, I: Into, Y: Into, A: Into, { Self { - name: name.into(), allow_in: allow_in.into(), allow_yield: allow_yield.into(), allow_await: allow_await.into(), @@ -69,29 +62,20 @@ where fn parse(self, cursor: &mut Cursor, interner: &mut Interner) -> ParseResult { let _timer = Profiler::global().start_event("ConditionalExpression", "Parsing"); - let lhs = ShortCircuitExpression::new( - self.name, - self.allow_in, - self.allow_yield, - self.allow_await, - ) - .parse(cursor, interner)?; + let lhs = ShortCircuitExpression::new(self.allow_in, self.allow_yield, self.allow_await) + .parse(cursor, interner)?; if let Some(tok) = cursor.peek(0, interner)? { if tok.kind() == &TokenKind::Punctuator(Punctuator::Question) { cursor.advance(interner); let then_clause = - AssignmentExpression::new(None, true, self.allow_yield, self.allow_await) + AssignmentExpression::new(true, self.allow_yield, self.allow_await) .parse(cursor, interner)?; cursor.expect(Punctuator::Colon, "conditional expression", interner)?; - let else_clause = AssignmentExpression::new( - None, - self.allow_in, - self.allow_yield, - self.allow_await, - ) - .parse(cursor, interner)?; + let else_clause = + AssignmentExpression::new(self.allow_in, self.allow_yield, self.allow_await) + .parse(cursor, interner)?; return Ok(Conditional::new(lhs, then_clause, else_clause).into()); } } diff --git a/core/parser/src/parser/expression/assignment/exponentiation.rs b/core/parser/src/parser/expression/assignment/exponentiation.rs index 0dcffe7ef0..60b8605959 100644 --- a/core/parser/src/parser/expression/assignment/exponentiation.rs +++ b/core/parser/src/parser/expression/assignment/exponentiation.rs @@ -16,10 +16,7 @@ use crate::{ source::ReadChar, }; use boa_ast::{ - expression::{ - operator::{binary::ArithmeticOp, Binary}, - Identifier, - }, + expression::operator::{binary::ArithmeticOp, Binary}, Expression, Keyword, Punctuator, }; use boa_interner::Interner; @@ -35,25 +32,18 @@ use boa_profiler::Profiler; /// [spec]: https://tc39.es/ecma262/#prod-ExponentiationExpression #[derive(Debug, Clone, Copy)] pub(in crate::parser::expression) struct ExponentiationExpression { - name: Option, allow_yield: AllowYield, allow_await: AllowAwait, } impl ExponentiationExpression { /// Creates a new `ExponentiationExpression` parser. - pub(in crate::parser::expression) fn new( - name: N, - allow_yield: Y, - allow_await: A, - ) -> Self + pub(in crate::parser::expression) fn new(allow_yield: Y, allow_await: A) -> Self where - N: Into>, Y: Into, A: Into, { Self { - name: name.into(), allow_yield: allow_yield.into(), allow_await: allow_await.into(), } @@ -75,18 +65,18 @@ where | TokenKind::Punctuator( Punctuator::Add | Punctuator::Sub | Punctuator::Not | Punctuator::Neg, ) => { - return UnaryExpression::new(self.name, self.allow_yield, self.allow_await) + return UnaryExpression::new(self.allow_yield, self.allow_await) .parse(cursor, interner); } TokenKind::Keyword((Keyword::Await, _)) if self.allow_await.0 => { - return UnaryExpression::new(self.name, self.allow_yield, self.allow_await) + return UnaryExpression::new(self.allow_yield, self.allow_await) .parse(cursor, interner); } _ => {} } - let lhs = UpdateExpression::new(self.name, self.allow_yield, self.allow_await) - .parse(cursor, interner)?; + let lhs = + UpdateExpression::new(self.allow_yield, self.allow_await).parse(cursor, interner)?; if let Some(tok) = cursor.peek(0, interner)? { if tok.kind() == &TokenKind::Punctuator(Punctuator::Exp) { cursor.advance(interner); diff --git a/core/parser/src/parser/expression/assignment/mod.rs b/core/parser/src/parser/expression/assignment/mod.rs index 3137a19306..4ee2786b68 100644 --- a/core/parser/src/parser/expression/assignment/mod.rs +++ b/core/parser/src/parser/expression/assignment/mod.rs @@ -29,10 +29,7 @@ use crate::{ Error, }; use boa_ast::{ - expression::{ - operator::assign::{Assign, AssignOp, AssignTarget}, - Identifier, - }, + expression::operator::assign::{Assign, AssignOp, AssignTarget}, operations::{bound_names, contains, lexically_declared_names, ContainsSymbol}, Expression, Keyword, Punctuator, }; @@ -61,7 +58,6 @@ pub(super) use exponentiation::ExponentiationExpression; /// [lhs]: ../lhs_expression/struct.LeftHandSideExpression.html #[derive(Debug, Clone, Copy)] pub(in crate::parser) struct AssignmentExpression { - name: Option, allow_in: AllowIn, allow_yield: AllowYield, allow_await: AllowAwait, @@ -69,20 +65,13 @@ pub(in crate::parser) struct AssignmentExpression { impl AssignmentExpression { /// Creates a new `AssignmentExpression` parser. - pub(in crate::parser) fn new( - name: N, - allow_in: I, - allow_yield: Y, - allow_await: A, - ) -> Self + pub(in crate::parser) fn new(allow_in: I, allow_yield: Y, allow_await: A) -> Self where - N: Into>, I: Into, Y: Into, A: Into, { Self { - name: name.into(), allow_in: allow_in.into(), allow_yield: allow_yield.into(), allow_await: allow_await.into(), @@ -96,7 +85,7 @@ where { type Output = Expression; - fn parse(mut self, cursor: &mut Cursor, interner: &mut Interner) -> ParseResult { + fn parse(self, cursor: &mut Cursor, interner: &mut Interner) -> ParseResult { let _timer = Profiler::global().start_event("AssignmentExpression", "Parsing"); cursor.set_goal(InputElement::RegExp); @@ -123,7 +112,6 @@ where { if tok.kind() == &TokenKind::Punctuator(Punctuator::Arrow) { return ArrowFunction::new( - self.name, self.allow_in, self.allow_yield, self.allow_await, @@ -158,11 +146,9 @@ where TokenKind::Punctuator(Punctuator::Arrow) ))) { - return Ok( - AsyncArrowFunction::new(self.name, self.allow_in, self.allow_yield) - .parse(cursor, interner)? - .into(), - ); + return Ok(AsyncArrowFunction::new(self.allow_in, self.allow_yield) + .parse(cursor, interner)? + .into()); } } _ => {} @@ -171,13 +157,8 @@ where cursor.set_goal(InputElement::Div); let position = cursor.peek(0, interner).or_abrupt()?.span().start(); - let mut lhs = ConditionalExpression::new( - self.name, - self.allow_in, - self.allow_yield, - self.allow_await, - ) - .parse(cursor, interner)?; + let mut lhs = ConditionalExpression::new(self.allow_in, self.allow_yield, self.allow_await) + .parse(cursor, interner)?; // If the left hand side is a parameter list, we must parse an arrow function. if let Expression::FormalParameterList(parameters) = lhs { @@ -237,7 +218,7 @@ where interner, )?; - return Ok(boa_ast::function::ArrowFunction::new(self.name, parameters, body).into()); + return Ok(boa_ast::function::ArrowFunction::new(None, parameters, body).into()); } // Review if we are trying to assign to an invalid left hand side expression. @@ -247,11 +228,17 @@ where cursor.advance(interner); cursor.set_goal(InputElement::RegExp); + let lhs_name = if let Expression::Identifier(ident) = lhs { + Some(ident) + } else { + None + }; + if let Some(target) = AssignTarget::from_expression(&lhs, cursor.strict()) { - if let Expression::Identifier(ident) = lhs { - self.name = Some(ident); + let mut expr = self.parse(cursor, interner)?; + if let Some(ident) = lhs_name { + expr.set_anonymous_function_definition_name(&ident); } - let expr = self.parse(cursor, interner)?; lhs = Assign::new(AssignOp::Assign, target, expr).into(); } else { return Err(Error::lex(LexError::Syntax( @@ -266,16 +253,16 @@ where AssignTarget::from_expression_simple(&lhs, cursor.strict()) { let assignop = p.as_assign_op().expect("assignop disappeared"); + + let mut rhs = self.parse(cursor, interner)?; if assignop == AssignOp::BoolAnd || assignop == AssignOp::BoolOr || assignop == AssignOp::Coalesce { if let AssignTarget::Identifier(ident) = target { - self.name = Some(ident); + rhs.set_anonymous_function_definition_name(&ident); } } - - let rhs = self.parse(cursor, interner)?; lhs = Assign::new(assignop, target, rhs).into(); } else { return Err(Error::lex(LexError::Syntax( diff --git a/core/parser/src/parser/expression/assignment/yield.rs b/core/parser/src/parser/expression/assignment/yield.rs index babe38836e..ff59cd4af2 100644 --- a/core/parser/src/parser/expression/assignment/yield.rs +++ b/core/parser/src/parser/expression/assignment/yield.rs @@ -71,7 +71,7 @@ where match token.kind() { TokenKind::Punctuator(Punctuator::Mul) => { cursor.advance(interner); - let expr = AssignmentExpression::new(None, self.allow_in, true, self.allow_await) + let expr = AssignmentExpression::new(self.allow_in, true, self.allow_await) .parse(cursor, interner)?; Ok(Yield::new(Some(expr), true).into()) } @@ -110,7 +110,7 @@ where | TokenKind::NumericLiteral(_) | TokenKind::RegularExpressionLiteral(_, _) | TokenKind::TemplateMiddle(_) => { - let expr = AssignmentExpression::new(None, self.allow_in, true, self.allow_await) + let expr = AssignmentExpression::new(self.allow_in, true, self.allow_await) .parse(cursor, interner)?; Ok(Yield::new(Some(expr), false).into()) } diff --git a/core/parser/src/parser/expression/await_expr.rs b/core/parser/src/parser/expression/await_expr.rs index cb073443aa..47f495d2c0 100644 --- a/core/parser/src/parser/expression/await_expr.rs +++ b/core/parser/src/parser/expression/await_expr.rs @@ -53,7 +53,7 @@ where "Await expression parsing", interner, )?; - let expr = UnaryExpression::new(None, self.allow_yield, true).parse(cursor, interner)?; + let expr = UnaryExpression::new(self.allow_yield, true).parse(cursor, interner)?; Ok(expr.into()) } } diff --git a/core/parser/src/parser/expression/left_hand_side/arguments.rs b/core/parser/src/parser/expression/left_hand_side/arguments.rs index e43442418a..672d2aa729 100644 --- a/core/parser/src/parser/expression/left_hand_side/arguments.rs +++ b/core/parser/src/parser/expression/left_hand_side/arguments.rs @@ -99,14 +99,14 @@ where if cursor.next_if(Punctuator::Spread, interner)?.is_some() { args.push( Spread::new( - AssignmentExpression::new(None, true, self.allow_yield, self.allow_await) + AssignmentExpression::new(true, self.allow_yield, self.allow_await) .parse(cursor, interner)?, ) .into(), ); } else { args.push( - AssignmentExpression::new(None, true, self.allow_yield, self.allow_await) + AssignmentExpression::new(true, self.allow_yield, self.allow_await) .parse(cursor, interner)?, ); } diff --git a/core/parser/src/parser/expression/left_hand_side/call.rs b/core/parser/src/parser/expression/left_hand_side/call.rs index 5555a2a028..c17a79391d 100644 --- a/core/parser/src/parser/expression/left_hand_side/call.rs +++ b/core/parser/src/parser/expression/left_hand_side/call.rs @@ -166,7 +166,7 @@ where } TokenKind::Punctuator(Punctuator::OpenBracket) => { cursor.advance(interner); - let idx = Expression::new(None, true, self.allow_yield, self.allow_await) + let idx = Expression::new(true, self.allow_yield, self.allow_await) .parse(cursor, interner)?; cursor.expect(Punctuator::CloseBracket, "call expression", interner)?; lhs = diff --git a/core/parser/src/parser/expression/left_hand_side/member.rs b/core/parser/src/parser/expression/left_hand_side/member.rs index daa214b628..029c220621 100644 --- a/core/parser/src/parser/expression/left_hand_side/member.rs +++ b/core/parser/src/parser/expression/left_hand_side/member.rs @@ -24,7 +24,7 @@ use boa_ast::{ access::{ PrivatePropertyAccess, PropertyAccessField, SimplePropertyAccess, SuperPropertyAccess, }, - Call, Identifier, New, + Call, New, }, Keyword, Punctuator, }; @@ -39,21 +39,18 @@ use boa_profiler::Profiler; /// [spec]: https://tc39.es/ecma262/#prod-MemberExpression #[derive(Debug, Clone, Copy)] pub(super) struct MemberExpression { - name: Option, allow_yield: AllowYield, allow_await: AllowAwait, } impl MemberExpression { /// Creates a new `MemberExpression` parser. - pub(super) fn new(name: N, allow_yield: Y, allow_await: A) -> Self + pub(super) fn new(allow_yield: Y, allow_await: A) -> Self where - N: Into>, Y: Into, A: Into, { Self { - name: name.into(), allow_yield: allow_yield.into(), allow_await: allow_await.into(), } @@ -195,7 +192,7 @@ where ast::Expression::PropertyAccess(field.into()) } TokenKind::Punctuator(Punctuator::OpenBracket) => { - let expr = Expression::new(None, true, self.allow_yield, self.allow_await) + let expr = Expression::new(true, self.allow_yield, self.allow_await) .parse(cursor, interner)?; cursor.expect(Punctuator::CloseBracket, "super property", interner)?; ast::Expression::PropertyAccess( @@ -211,7 +208,7 @@ where } } } - _ => PrimaryExpression::new(self.name, self.allow_yield, self.allow_await) + _ => PrimaryExpression::new(self.allow_yield, self.allow_await) .parse(cursor, interner)?, }; @@ -261,7 +258,7 @@ where cursor .next(interner)? .expect("open bracket punctuator token disappeared"); // We move the parser forward. - let idx = Expression::new(None, true, self.allow_yield, self.allow_await) + let idx = Expression::new(true, self.allow_yield, self.allow_await) .parse(cursor, interner)?; cursor.expect(Punctuator::CloseBracket, "member expression", interner)?; lhs = diff --git a/core/parser/src/parser/expression/left_hand_side/mod.rs b/core/parser/src/parser/expression/left_hand_side/mod.rs index 537ecab04d..18046fd638 100644 --- a/core/parser/src/parser/expression/left_hand_side/mod.rs +++ b/core/parser/src/parser/expression/left_hand_side/mod.rs @@ -34,7 +34,7 @@ use crate::{ Error, }; use boa_ast::{ - expression::{Identifier, ImportCall, SuperCall}, + expression::{ImportCall, SuperCall}, Expression, Keyword, Punctuator, }; use boa_interner::Interner; @@ -50,21 +50,18 @@ use boa_profiler::Profiler; /// [spec]: https://tc39.es/ecma262/#prod-LeftHandSideExpression #[derive(Debug, Clone, Copy)] pub(in crate::parser) struct LeftHandSideExpression { - name: Option, allow_yield: AllowYield, allow_await: AllowAwait, } impl LeftHandSideExpression { /// Creates a new `LeftHandSideExpression` parser. - pub(in crate::parser) fn new(name: N, allow_yield: Y, allow_await: A) -> Self + pub(in crate::parser) fn new(allow_yield: Y, allow_await: A) -> Self where - N: Into>, Y: Into, A: Into, { Self { - name: name.into(), allow_yield: allow_yield.into(), allow_await: allow_await.into(), } @@ -130,7 +127,7 @@ where // `(` cursor.advance(interner); - let arg = AssignmentExpression::new(None, true, self.allow_yield, self.allow_await) + let arg = AssignmentExpression::new(true, self.allow_yield, self.allow_await) .parse(cursor, interner)?; cursor.expect( @@ -146,7 +143,7 @@ where ) .parse(cursor, interner)? } else { - let mut member = MemberExpression::new(self.name, self.allow_yield, self.allow_await) + let mut member = MemberExpression::new(self.allow_yield, self.allow_await) .parse(cursor, interner)?; if let Some(tok) = cursor.peek(0, interner)? { if tok.kind() == &TokenKind::Punctuator(Punctuator::OpenParen) { diff --git a/core/parser/src/parser/expression/left_hand_side/optional/mod.rs b/core/parser/src/parser/expression/left_hand_side/optional/mod.rs index a79ac502c3..adb88f90c1 100644 --- a/core/parser/src/parser/expression/left_hand_side/optional/mod.rs +++ b/core/parser/src/parser/expression/left_hand_side/optional/mod.rs @@ -143,7 +143,7 @@ where cursor .next(interner)? .expect("open bracket punctuator token disappeared"); // We move the parser forward. - let idx = Expression::new(None, true, self.allow_yield, self.allow_await) + let idx = Expression::new(true, self.allow_yield, self.allow_await) .parse(cursor, interner)?; cursor.expect(Punctuator::CloseBracket, "optional chain", interner)?; OptionalOperationKind::SimplePropertyAccess { diff --git a/core/parser/src/parser/expression/left_hand_side/template.rs b/core/parser/src/parser/expression/left_hand_side/template.rs index db160d14bc..5dbe6fb4d8 100644 --- a/core/parser/src/parser/expression/left_hand_side/template.rs +++ b/core/parser/src/parser/expression/left_hand_side/template.rs @@ -67,7 +67,7 @@ where raws.push(template_string.raw()); cookeds.push(template_string.cooked()); exprs.push( - Expression::new(None, true, self.allow_yield, self.allow_await) + Expression::new(true, self.allow_yield, self.allow_await) .parse(cursor, interner)?, ); cursor.expect( diff --git a/core/parser/src/parser/expression/mod.rs b/core/parser/src/parser/expression/mod.rs index adf553c849..fe5cbb70ef 100644 --- a/core/parser/src/parser/expression/mod.rs +++ b/core/parser/src/parser/expression/mod.rs @@ -77,7 +77,7 @@ macro_rules! expression { { type Output = ast::Expression; - fn parse(mut self, cursor: &mut Cursor, interner: &mut Interner)-> ParseResult { + fn parse(self, cursor: &mut Cursor, interner: &mut Interner)-> ParseResult { let _timer = Profiler::global().start_event(stringify!($name), "Parsing"); if $goal.is_some() { @@ -85,7 +85,6 @@ macro_rules! expression { } let mut lhs = $lower::new($( self.$low_param ),*).parse(cursor, interner)?; - self.name = None; while let Some(tok) = cursor.peek(0, interner)? { match *tok.kind() { TokenKind::Punctuator(op) if $( op == $op )||* => { @@ -116,7 +115,6 @@ macro_rules! expression { /// [spec]: https://tc39.es/ecma262/#prod-Expression #[derive(Debug, Clone, Copy)] pub(super) struct Expression { - name: Option, allow_in: AllowIn, allow_yield: AllowYield, allow_await: AllowAwait, @@ -124,15 +122,13 @@ pub(super) struct Expression { impl Expression { /// Creates a new `Expression` parser. - pub(super) fn new(name: N, allow_in: I, allow_yield: Y, allow_await: A) -> Self + pub(super) fn new(allow_in: I, allow_yield: Y, allow_await: A) -> Self where - N: Into>, I: Into, Y: Into, A: Into, { Self { - name: name.into(), allow_in: allow_in.into(), allow_yield: allow_yield.into(), allow_await: allow_await.into(), @@ -146,17 +142,11 @@ where { type Output = ast::Expression; - fn parse( - mut self, - cursor: &mut Cursor, - interner: &mut Interner, - ) -> ParseResult { + fn parse(self, cursor: &mut Cursor, interner: &mut Interner) -> ParseResult { let _timer = Profiler::global().start_event("Expression", "Parsing"); - let mut lhs = - AssignmentExpression::new(self.name, self.allow_in, self.allow_yield, self.allow_await) - .parse(cursor, interner)?; - self.name = None; + let mut lhs = AssignmentExpression::new(self.allow_in, self.allow_yield, self.allow_await) + .parse(cursor, interner)?; while let Some(tok) = cursor.peek(0, interner)? { match *tok.kind() { TokenKind::Punctuator(Punctuator::Comma) => { @@ -180,7 +170,6 @@ where .expect("Could not get binary operation."), lhs, AssignmentExpression::new( - self.name, self.allow_in, self.allow_yield, self.allow_await, @@ -207,7 +196,6 @@ where /// [spec]: https://tc39.es/ecma262/#prod-ShortCircuitExpression #[derive(Debug, Clone, Copy)] struct ShortCircuitExpression { - name: Option, allow_in: AllowIn, allow_yield: AllowYield, allow_await: AllowAwait, @@ -223,15 +211,13 @@ enum PreviousExpr { impl ShortCircuitExpression { /// Creates a new `ShortCircuitExpression` parser. - pub(super) fn new(name: N, allow_in: I, allow_yield: Y, allow_await: A) -> Self + pub(super) fn new(allow_in: I, allow_yield: Y, allow_await: A) -> Self where - N: Into>, I: Into, Y: Into, A: Into, { Self { - name: name.into(), allow_in: allow_in.into(), allow_yield: allow_yield.into(), allow_await: allow_await.into(), @@ -239,21 +225,18 @@ impl ShortCircuitExpression { } } - fn with_previous( - name: N, + fn with_previous( allow_in: I, allow_yield: Y, allow_await: A, previous: PreviousExpr, ) -> Self where - N: Into>, I: Into, Y: Into, A: Into, { Self { - name: name.into(), allow_in: allow_in.into(), allow_yield: allow_yield.into(), allow_await: allow_await.into(), @@ -272,7 +255,7 @@ where let _timer = Profiler::global().start_event("ShortCircuitExpression", "Parsing"); let mut current_node = - BitwiseORExpression::new(self.name, self.allow_in, self.allow_yield, self.allow_await) + BitwiseORExpression::new(self.allow_in, self.allow_yield, self.allow_await) .parse(cursor, interner)?; let mut previous = self.previous; @@ -288,13 +271,9 @@ where } cursor.advance(interner); previous = PreviousExpr::Logical; - let rhs = BitwiseORExpression::new( - self.name, - self.allow_in, - self.allow_yield, - self.allow_await, - ) - .parse(cursor, interner)?; + let rhs = + BitwiseORExpression::new(self.allow_in, self.allow_yield, self.allow_await) + .parse(cursor, interner)?; current_node = Binary::new(BinaryOp::Logical(LogicalOp::And), current_node, rhs).into(); @@ -310,7 +289,6 @@ where cursor.advance(interner); previous = PreviousExpr::Logical; let rhs = Self::with_previous( - self.name, self.allow_in, self.allow_yield, self.allow_await, @@ -331,13 +309,9 @@ where } cursor.advance(interner); previous = PreviousExpr::Coalesce; - let rhs = BitwiseORExpression::new( - self.name, - self.allow_in, - self.allow_yield, - self.allow_await, - ) - .parse(cursor, interner)?; + let rhs = + BitwiseORExpression::new(self.allow_in, self.allow_yield, self.allow_await) + .parse(cursor, interner)?; current_node = Binary::new(BinaryOp::Logical(LogicalOp::Coalesce), current_node, rhs) .into(); @@ -359,7 +333,6 @@ where /// [spec]: https://tc39.es/ecma262/#prod-BitwiseORExpression #[derive(Debug, Clone, Copy)] struct BitwiseORExpression { - name: Option, allow_in: AllowIn, allow_yield: AllowYield, allow_await: AllowAwait, @@ -367,15 +340,13 @@ struct BitwiseORExpression { impl BitwiseORExpression { /// Creates a new `BitwiseORExpression` parser. - pub(super) fn new(name: N, allow_in: I, allow_yield: Y, allow_await: A) -> Self + pub(super) fn new(allow_in: I, allow_yield: Y, allow_await: A) -> Self where - N: Into>, I: Into, Y: Into, A: Into, { Self { - name: name.into(), allow_in: allow_in.into(), allow_yield: allow_yield.into(), allow_await: allow_await.into(), @@ -387,7 +358,7 @@ expression!( BitwiseORExpression, BitwiseXORExpression, [Punctuator::Or], - [name, allow_in, allow_yield, allow_await], + [allow_in, allow_yield, allow_await], None:: ); @@ -401,7 +372,6 @@ expression!( /// [spec]: https://tc39.es/ecma262/#prod-BitwiseXORExpression #[derive(Debug, Clone, Copy)] struct BitwiseXORExpression { - name: Option, allow_in: AllowIn, allow_yield: AllowYield, allow_await: AllowAwait, @@ -409,15 +379,13 @@ struct BitwiseXORExpression { impl BitwiseXORExpression { /// Creates a new `BitwiseXORExpression` parser. - pub(super) fn new(name: N, allow_in: I, allow_yield: Y, allow_await: A) -> Self + pub(super) fn new(allow_in: I, allow_yield: Y, allow_await: A) -> Self where - N: Into>, I: Into, Y: Into, A: Into, { Self { - name: name.into(), allow_in: allow_in.into(), allow_yield: allow_yield.into(), allow_await: allow_await.into(), @@ -429,7 +397,7 @@ expression!( BitwiseXORExpression, BitwiseANDExpression, [Punctuator::Xor], - [name, allow_in, allow_yield, allow_await], + [allow_in, allow_yield, allow_await], None:: ); @@ -443,7 +411,6 @@ expression!( /// [spec]: https://tc39.es/ecma262/#prod-BitwiseANDExpression #[derive(Debug, Clone, Copy)] struct BitwiseANDExpression { - name: Option, allow_in: AllowIn, allow_yield: AllowYield, allow_await: AllowAwait, @@ -451,15 +418,13 @@ struct BitwiseANDExpression { impl BitwiseANDExpression { /// Creates a new `BitwiseANDExpression` parser. - pub(super) fn new(name: N, allow_in: I, allow_yield: Y, allow_await: A) -> Self + pub(super) fn new(allow_in: I, allow_yield: Y, allow_await: A) -> Self where - N: Into>, I: Into, Y: Into, A: Into, { Self { - name: name.into(), allow_in: allow_in.into(), allow_yield: allow_yield.into(), allow_await: allow_await.into(), @@ -471,7 +436,7 @@ expression!( BitwiseANDExpression, EqualityExpression, [Punctuator::And], - [name, allow_in, allow_yield, allow_await], + [allow_in, allow_yield, allow_await], None:: ); @@ -485,7 +450,6 @@ expression!( /// [spec]: https://tc39.es/ecma262/#sec-equality-operators #[derive(Debug, Clone, Copy)] struct EqualityExpression { - name: Option, allow_in: AllowIn, allow_yield: AllowYield, allow_await: AllowAwait, @@ -493,15 +457,13 @@ struct EqualityExpression { impl EqualityExpression { /// Creates a new `EqualityExpression` parser. - pub(super) fn new(name: N, allow_in: I, allow_yield: Y, allow_await: A) -> Self + pub(super) fn new(allow_in: I, allow_yield: Y, allow_await: A) -> Self where - N: Into>, I: Into, Y: Into, A: Into, { Self { - name: name.into(), allow_in: allow_in.into(), allow_yield: allow_yield.into(), allow_await: allow_await.into(), @@ -518,7 +480,7 @@ expression!( Punctuator::StrictEq, Punctuator::StrictNotEq ], - [name, allow_in, allow_yield, allow_await], + [allow_in, allow_yield, allow_await], None:: ); @@ -532,7 +494,6 @@ expression!( /// [spec]: https://tc39.es/ecma262/#sec-relational-operators #[derive(Debug, Clone, Copy)] struct RelationalExpression { - name: Option, allow_in: AllowIn, allow_yield: AllowYield, allow_await: AllowAwait, @@ -540,15 +501,13 @@ struct RelationalExpression { impl RelationalExpression { /// Creates a new `RelationalExpression` parser. - pub(super) fn new(name: N, allow_in: I, allow_yield: Y, allow_await: A) -> Self + pub(super) fn new(allow_in: I, allow_yield: Y, allow_await: A) -> Self where - N: Into>, I: Into, Y: Into, A: Into, { Self { - name: name.into(), allow_in: allow_in.into(), allow_yield: allow_yield.into(), allow_await: allow_await.into(), @@ -581,9 +540,8 @@ where cursor.advance(interner); cursor.advance(interner); - let rhs = - ShiftExpression::new(self.name, self.allow_yield, self.allow_await) - .parse(cursor, interner)?; + let rhs = ShiftExpression::new(self.allow_yield, self.allow_await) + .parse(cursor, interner)?; return Ok(BinaryInPrivate::new(PrivateName::new(identifier), rhs).into()); } @@ -592,8 +550,8 @@ where } } - let mut lhs = ShiftExpression::new(self.name, self.allow_yield, self.allow_await) - .parse(cursor, interner)?; + let mut lhs = + ShiftExpression::new(self.allow_yield, self.allow_await).parse(cursor, interner)?; while let Some(tok) = cursor.peek(0, interner)? { match *tok.kind() { @@ -607,7 +565,7 @@ where lhs = Binary::new( op.as_binary_op().expect("Could not get binary operation."), lhs, - ShiftExpression::new(self.name, self.allow_yield, self.allow_await) + ShiftExpression::new(self.allow_yield, self.allow_await) .parse(cursor, interner)?, ) .into(); @@ -626,7 +584,7 @@ where lhs = Binary::new( op.as_binary_op().expect("Could not get binary operation."), lhs, - ShiftExpression::new(self.name, self.allow_yield, self.allow_await) + ShiftExpression::new(self.allow_yield, self.allow_await) .parse(cursor, interner)?, ) .into(); @@ -649,21 +607,18 @@ where /// [spec]: https://tc39.es/ecma262/#sec-bitwise-shift-operators #[derive(Debug, Clone, Copy)] struct ShiftExpression { - name: Option, allow_yield: AllowYield, allow_await: AllowAwait, } impl ShiftExpression { /// Creates a new `ShiftExpression` parser. - pub(super) fn new(name: N, allow_yield: Y, allow_await: A) -> Self + pub(super) fn new(allow_yield: Y, allow_await: A) -> Self where - N: Into>, Y: Into, A: Into, { Self { - name: name.into(), allow_yield: allow_yield.into(), allow_await: allow_await.into(), } @@ -678,7 +633,7 @@ expression!( Punctuator::RightSh, Punctuator::URightSh ], - [name, allow_yield, allow_await], + [allow_yield, allow_await], None:: ); @@ -694,21 +649,18 @@ expression!( /// [spec]: https://tc39.es/ecma262/#sec-additive-operators #[derive(Debug, Clone, Copy)] struct AdditiveExpression { - name: Option, allow_yield: AllowYield, allow_await: AllowAwait, } impl AdditiveExpression { /// Creates a new `AdditiveExpression` parser. - pub(super) fn new(name: N, allow_yield: Y, allow_await: A) -> Self + pub(super) fn new(allow_yield: Y, allow_await: A) -> Self where - N: Into>, Y: Into, A: Into, { Self { - name: name.into(), allow_yield: allow_yield.into(), allow_await: allow_await.into(), } @@ -719,7 +671,7 @@ expression!( AdditiveExpression, MultiplicativeExpression, [Punctuator::Add, Punctuator::Sub], - [name, allow_yield, allow_await], + [allow_yield, allow_await], None:: ); @@ -735,21 +687,18 @@ expression!( /// [spec]: https://tc39.es/ecma262/#sec-multiplicative-operators #[derive(Debug, Clone, Copy)] struct MultiplicativeExpression { - name: Option, allow_yield: AllowYield, allow_await: AllowAwait, } impl MultiplicativeExpression { /// Creates a new `MultiplicativeExpression` parser. - pub(super) fn new(name: N, allow_yield: Y, allow_await: A) -> Self + pub(super) fn new(allow_yield: Y, allow_await: A) -> Self where - N: Into>, Y: Into, A: Into, { Self { - name: name.into(), allow_yield: allow_yield.into(), allow_await: allow_await.into(), } @@ -760,7 +709,7 @@ expression!( MultiplicativeExpression, ExponentiationExpression, [Punctuator::Mul, Punctuator::Div, Punctuator::Mod], - [name, allow_yield, allow_await], + [allow_yield, allow_await], Some(InputElement::Div) ); diff --git a/core/parser/src/parser/expression/primary/array_initializer/mod.rs b/core/parser/src/parser/expression/primary/array_initializer/mod.rs index 3526b3a0b7..8ea85011bc 100644 --- a/core/parser/src/parser/expression/primary/array_initializer/mod.rs +++ b/core/parser/src/parser/expression/primary/array_initializer/mod.rs @@ -99,9 +99,8 @@ where } TokenKind::Punctuator(Punctuator::Spread) => { cursor.advance(interner); - let node = - AssignmentExpression::new(None, true, self.allow_yield, self.allow_await) - .parse(cursor, interner)?; + let node = AssignmentExpression::new(true, self.allow_yield, self.allow_await) + .parse(cursor, interner)?; elements.push(Some(Spread::new(node).into())); next_comma = true; last_spread = true; @@ -114,9 +113,8 @@ where )); } _ => { - let expr = - AssignmentExpression::new(None, true, self.allow_yield, self.allow_await) - .parse(cursor, interner)?; + let expr = AssignmentExpression::new(true, self.allow_yield, self.allow_await) + .parse(cursor, interner)?; elements.push(Some(expr)); next_comma = true; last_spread = false; diff --git a/core/parser/src/parser/expression/primary/async_function_expression/mod.rs b/core/parser/src/parser/expression/primary/async_function_expression/mod.rs index 7ea72cd54e..0458d16961 100644 --- a/core/parser/src/parser/expression/primary/async_function_expression/mod.rs +++ b/core/parser/src/parser/expression/primary/async_function_expression/mod.rs @@ -12,8 +12,7 @@ use crate::{ Error, }; use boa_ast::{ - expression::Identifier, - function::AsyncFunction, + function::AsyncFunctionExpression as AsyncFunctionExpressionNode, operations::{bound_names, contains, lexically_declared_names, ContainsSymbol}, Keyword, Punctuator, }; @@ -29,17 +28,12 @@ use boa_profiler::Profiler; /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/async_function /// [spec]: https://tc39.es/ecma262/#prod-AsyncFunctionExpression #[derive(Debug, Clone, Copy)] -pub(super) struct AsyncFunctionExpression { - name: Option, -} +pub(super) struct AsyncFunctionExpression {} impl AsyncFunctionExpression { /// Creates a new `AsyncFunctionExpression` parser. - pub(super) fn new(name: N) -> Self - where - N: Into>, - { - Self { name: name.into() } + pub(super) fn new() -> Self { + Self {} } } @@ -47,7 +41,7 @@ impl TokenParser for AsyncFunctionExpression where R: ReadChar, { - type Output = AsyncFunction; + type Output = AsyncFunctionExpressionNode; fn parse(self, cursor: &mut Cursor, interner: &mut Interner) -> ParseResult { let _timer = Profiler::global().start_event("AsyncFunctionExpression", "Parsing"); @@ -145,7 +139,7 @@ where interner, )?; - let function = AsyncFunction::new(name.or(self.name), params, body, name.is_some()); + let function = AsyncFunctionExpressionNode::new(name, params, body, name.is_some()); if contains(&function, ContainsSymbol::Super) { return Err(Error::lex(LexError::Syntax( diff --git a/core/parser/src/parser/expression/primary/async_function_expression/tests.rs b/core/parser/src/parser/expression/primary/async_function_expression/tests.rs index 259dc62acc..c4122e5ec3 100644 --- a/core/parser/src/parser/expression/primary/async_function_expression/tests.rs +++ b/core/parser/src/parser/expression/primary/async_function_expression/tests.rs @@ -2,7 +2,7 @@ use crate::parser::tests::check_script_parser; use boa_ast::{ declaration::{Declaration, LexicalDeclaration, Variable}, expression::literal::Literal, - function::{AsyncFunction, FormalParameterList, FunctionBody}, + function::{AsyncFunctionExpression, FormalParameterList, FunctionBody}, statement::Return, Statement, StatementListItem, }; @@ -23,7 +23,7 @@ fn check_async_expression() { vec![Variable::from_identifier( add.into(), Some( - AsyncFunction::new( + AsyncFunctionExpression::new( Some(add.into()), FormalParameterList::default(), FunctionBody::new( @@ -61,7 +61,7 @@ fn check_nested_async_expression() { vec![Variable::from_identifier( a.into(), Some( - AsyncFunction::new( + AsyncFunctionExpression::new( Some(a.into()), FormalParameterList::default(), FunctionBody::new( @@ -69,7 +69,7 @@ fn check_nested_async_expression() { vec![Variable::from_identifier( b.into(), Some( - AsyncFunction::new( + AsyncFunctionExpression::new( Some(b.into()), FormalParameterList::default(), FunctionBody::new( diff --git a/core/parser/src/parser/expression/primary/async_generator_expression/mod.rs b/core/parser/src/parser/expression/primary/async_generator_expression/mod.rs index 76b2bb659f..b904cc61a9 100644 --- a/core/parser/src/parser/expression/primary/async_generator_expression/mod.rs +++ b/core/parser/src/parser/expression/primary/async_generator_expression/mod.rs @@ -21,8 +21,7 @@ use crate::{ Error, }; use boa_ast::{ - expression::Identifier, - function::AsyncGenerator, + function::AsyncGeneratorExpression as AsyncGeneratorExpressionNode, operations::{bound_names, contains, lexically_declared_names, ContainsSymbol}, Keyword, Punctuator, }; @@ -36,17 +35,12 @@ use boa_profiler::Profiler; /// /// [spec]: https://tc39.es/ecma262/#prod-AsyncGeneratorExpression #[derive(Debug, Clone, Copy)] -pub(super) struct AsyncGeneratorExpression { - name: Option, -} +pub(super) struct AsyncGeneratorExpression {} impl AsyncGeneratorExpression { /// Creates a new `AsyncGeneratorExpression` parser. - pub(in crate::parser) fn new(name: N) -> Self - where - N: Into>, - { - Self { name: name.into() } + pub(in crate::parser) fn new() -> Self { + Self {} } } @@ -55,7 +49,7 @@ where R: ReadChar, { //The below needs to be implemented in ast::node - type Output = AsyncGenerator; + type Output = AsyncGeneratorExpressionNode; fn parse(self, cursor: &mut Cursor, interner: &mut Interner) -> ParseResult { let _timer = Profiler::global().start_event("AsyncGeneratorExpression", "Parsing"); @@ -182,7 +176,7 @@ where interner, )?; - let function = AsyncGenerator::new(name.or(self.name), params, body, name.is_some()); + let function = AsyncGeneratorExpressionNode::new(name, params, body, name.is_some()); if contains(&function, ContainsSymbol::Super) { return Err(Error::lex(LexError::Syntax( diff --git a/core/parser/src/parser/expression/primary/async_generator_expression/tests.rs b/core/parser/src/parser/expression/primary/async_generator_expression/tests.rs index df04d67d08..82a8fdc7c5 100644 --- a/core/parser/src/parser/expression/primary/async_generator_expression/tests.rs +++ b/core/parser/src/parser/expression/primary/async_generator_expression/tests.rs @@ -2,7 +2,7 @@ use crate::parser::tests::check_script_parser; use boa_ast::{ declaration::{LexicalDeclaration, Variable}, expression::literal::Literal, - function::{AsyncGenerator, FormalParameterList, FunctionBody}, + function::{AsyncGeneratorExpression, FormalParameterList, FunctionBody}, statement::Return, Declaration, Statement, StatementListItem, }; @@ -24,7 +24,7 @@ fn check_async_generator_expr() { vec![Variable::from_identifier( add.into(), Some( - AsyncGenerator::new( + AsyncGeneratorExpression::new( Some(add.into()), FormalParameterList::default(), FunctionBody::new( @@ -62,7 +62,7 @@ fn check_nested_async_generator_expr() { vec![Variable::from_identifier( a.into(), Some( - AsyncGenerator::new( + AsyncGeneratorExpression::new( Some(a.into()), FormalParameterList::default(), FunctionBody::new( @@ -70,7 +70,7 @@ fn check_nested_async_generator_expr() { vec![Variable::from_identifier( b.into(), Some( - AsyncGenerator::new( + AsyncGeneratorExpression::new( Some(b.into()), FormalParameterList::default(), FunctionBody::new( diff --git a/core/parser/src/parser/expression/primary/class_expression/mod.rs b/core/parser/src/parser/expression/primary/class_expression/mod.rs index ab6b17c0e8..3bd4921ab0 100644 --- a/core/parser/src/parser/expression/primary/class_expression/mod.rs +++ b/core/parser/src/parser/expression/primary/class_expression/mod.rs @@ -6,7 +6,7 @@ use crate::{ }, source::ReadChar, }; -use boa_ast::{expression::Identifier, function::Class, Keyword}; +use boa_ast::{function::ClassExpression as ClassExpressionNode, Keyword}; use boa_interner::Interner; use boa_profiler::Profiler; @@ -18,21 +18,18 @@ use boa_profiler::Profiler; /// [spec]: https://tc39.es/ecma262/#prod-ClassExpression #[derive(Debug, Clone, Copy)] pub(super) struct ClassExpression { - name: Option, allow_yield: AllowYield, allow_await: AllowAwait, } impl ClassExpression { /// Creates a new `ClassExpression` parser. - pub(in crate::parser) fn new(name: N, allow_yield: Y, allow_await: A) -> Self + pub(in crate::parser) fn new(allow_yield: Y, allow_await: A) -> Self where - N: Into>, Y: Into, A: Into, { Self { - name: name.into(), allow_yield: allow_yield.into(), allow_await: allow_await.into(), } @@ -43,33 +40,34 @@ impl TokenParser for ClassExpression where R: ReadChar, { - type Output = Class; + type Output = ClassExpressionNode; fn parse(self, cursor: &mut Cursor, interner: &mut Interner) -> ParseResult { let _timer = Profiler::global().start_event("ClassExpression", "Parsing"); let strict = cursor.strict(); cursor.set_strict(true); - let mut has_binding_identifier = false; let token = cursor.peek(0, interner).or_abrupt()?; let name = match token.kind() { TokenKind::IdentifierName(_) | TokenKind::Keyword((Keyword::Yield | Keyword::Await, _)) => { - has_binding_identifier = true; BindingIdentifier::new(self.allow_yield, self.allow_await) .parse(cursor, interner)? .into() } - _ => self.name, + _ => None, }; cursor.set_strict(strict); - ClassTail::new( + let (super_ref, constructor, elements) = + ClassTail::new(name, self.allow_yield, self.allow_await).parse(cursor, interner)?; + + Ok(ClassExpressionNode::new( name, - has_binding_identifier, - self.allow_yield, - self.allow_await, - ) - .parse(cursor, interner) + super_ref, + constructor, + elements.into_boxed_slice(), + name.is_some(), + )) } } diff --git a/core/parser/src/parser/expression/primary/function_expression/mod.rs b/core/parser/src/parser/expression/primary/function_expression/mod.rs index 01bb6bb3b5..88327a7910 100644 --- a/core/parser/src/parser/expression/primary/function_expression/mod.rs +++ b/core/parser/src/parser/expression/primary/function_expression/mod.rs @@ -21,8 +21,7 @@ use crate::{ Error, }; use boa_ast::{ - expression::Identifier, - function::Function, + function::FunctionExpression as FunctionExpressionNode, operations::{bound_names, contains, lexically_declared_names, ContainsSymbol}, Keyword, Punctuator, }; @@ -38,17 +37,12 @@ use boa_profiler::Profiler; /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/function /// [spec]: https://tc39.es/ecma262/#prod-FunctionExpression #[derive(Debug, Clone, Copy)] -pub(super) struct FunctionExpression { - name: Option, -} +pub(super) struct FunctionExpression {} impl FunctionExpression { /// Creates a new `FunctionExpression` parser. - pub(in crate::parser) fn new(name: N) -> Self - where - N: Into>, - { - Self { name: name.into() } + pub(in crate::parser) fn new() -> Self { + Self {} } } @@ -56,7 +50,7 @@ impl TokenParser for FunctionExpression where R: ReadChar, { - type Output = Function; + type Output = FunctionExpressionNode; fn parse(self, cursor: &mut Cursor, interner: &mut Interner) -> ParseResult { let _timer = Profiler::global().start_event("FunctionExpression", "Parsing"); @@ -140,8 +134,7 @@ where interner, )?; - let function = - Function::new_with_binding_identifier(name.or(self.name), params, body, name.is_some()); + let function = FunctionExpressionNode::new(name, params, body, name.is_some()); if contains(&function, ContainsSymbol::Super) { return Err(Error::lex(LexError::Syntax( diff --git a/core/parser/src/parser/expression/primary/function_expression/tests.rs b/core/parser/src/parser/expression/primary/function_expression/tests.rs index 40da9ca130..e56edc5bc8 100644 --- a/core/parser/src/parser/expression/primary/function_expression/tests.rs +++ b/core/parser/src/parser/expression/primary/function_expression/tests.rs @@ -2,7 +2,7 @@ use crate::parser::tests::check_script_parser; use boa_ast::{ declaration::{LexicalDeclaration, Variable}, expression::literal::Literal, - function::{FormalParameterList, Function, FunctionBody}, + function::{FormalParameterList, FunctionBody, FunctionExpression}, statement::Return, Declaration, Statement, StatementListItem, }; @@ -23,7 +23,7 @@ fn check_function_expression() { vec![Variable::from_identifier( add.into(), Some( - Function::new( + FunctionExpression::new( Some(add.into()), FormalParameterList::default(), FunctionBody::new( @@ -32,6 +32,7 @@ fn check_function_expression() { ))] .into(), ), + false, ) .into(), ), @@ -60,7 +61,7 @@ fn check_nested_function_expression() { vec![Variable::from_identifier( a.into(), Some( - Function::new( + FunctionExpression::new( Some(a.into()), FormalParameterList::default(), FunctionBody::new( @@ -68,7 +69,7 @@ fn check_nested_function_expression() { vec![Variable::from_identifier( b.into(), Some( - Function::new( + FunctionExpression::new( Some(b.into()), FormalParameterList::default(), FunctionBody::new( @@ -79,6 +80,7 @@ fn check_nested_function_expression() { )] .into(), ), + false, ) .into(), ), @@ -89,6 +91,7 @@ fn check_nested_function_expression() { .into()] .into(), ), + false, ) .into(), ), @@ -109,7 +112,7 @@ fn check_function_non_reserved_keyword() { vec![Variable::from_identifier( $interner.get_or_intern_static("add", utf16!("add")).into(), Some( - Function::new_with_binding_identifier( + FunctionExpression::new( Some($interner.get_or_intern_static($keyword, utf16!($keyword)).into()), FormalParameterList::default(), FunctionBody::new( diff --git a/core/parser/src/parser/expression/primary/generator_expression/mod.rs b/core/parser/src/parser/expression/primary/generator_expression/mod.rs index 27b6f24600..66920338a1 100644 --- a/core/parser/src/parser/expression/primary/generator_expression/mod.rs +++ b/core/parser/src/parser/expression/primary/generator_expression/mod.rs @@ -21,8 +21,7 @@ use crate::{ Error, }; use boa_ast::{ - expression::Identifier, - function::Generator, + function::GeneratorExpression as GeneratorExpressionNode, operations::{bound_names, contains, lexically_declared_names, ContainsSymbol}, Keyword, Punctuator, }; @@ -38,17 +37,12 @@ use boa_profiler::Profiler; /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/function* /// [spec]: https://tc39.es/ecma262/#prod-GeneratorExpression #[derive(Debug, Clone, Copy)] -pub(super) struct GeneratorExpression { - name: Option, -} +pub(super) struct GeneratorExpression {} impl GeneratorExpression { /// Creates a new `GeneratorExpression` parser. - pub(in crate::parser) fn new(name: N) -> Self - where - N: Into>, - { - Self { name: name.into() } + pub(in crate::parser) fn new() -> Self { + Self {} } } @@ -56,7 +50,7 @@ impl TokenParser for GeneratorExpression where R: ReadChar, { - type Output = Generator; + type Output = GeneratorExpressionNode; fn parse(self, cursor: &mut Cursor, interner: &mut Interner) -> ParseResult { let _timer = Profiler::global().start_event("GeneratorExpression", "Parsing"); @@ -157,7 +151,7 @@ where ))); } - let function = Generator::new(name.or(self.name), params, body, name.is_some()); + let function = GeneratorExpressionNode::new(name, params, body, name.is_some()); if contains(&function, ContainsSymbol::Super) { return Err(Error::lex(LexError::Syntax( diff --git a/core/parser/src/parser/expression/primary/generator_expression/tests.rs b/core/parser/src/parser/expression/primary/generator_expression/tests.rs index 3e80cfb274..5b633992ef 100644 --- a/core/parser/src/parser/expression/primary/generator_expression/tests.rs +++ b/core/parser/src/parser/expression/primary/generator_expression/tests.rs @@ -2,7 +2,7 @@ use crate::parser::tests::check_script_parser; use boa_ast::{ declaration::{LexicalDeclaration, Variable}, expression::{literal::Literal, Yield}, - function::{FormalParameterList, FunctionBody, Generator}, + function::{FormalParameterList, FunctionBody, GeneratorExpression}, Declaration, Expression, Statement, StatementListItem, }; use boa_interner::Interner; @@ -21,7 +21,7 @@ fn check_generator_function_expression() { vec![Variable::from_identifier( gen.into(), Some( - Generator::new( + GeneratorExpression::new( Some(gen.into()), FormalParameterList::default(), FunctionBody::new( @@ -56,7 +56,7 @@ fn check_generator_function_delegate_yield_expression() { vec![Variable::from_identifier( gen.into(), Some( - Generator::new( + GeneratorExpression::new( Some(gen.into()), FormalParameterList::default(), FunctionBody::new( diff --git a/core/parser/src/parser/expression/primary/mod.rs b/core/parser/src/parser/expression/primary/mod.rs index bc607fbc40..e3a0a27239 100644 --- a/core/parser/src/parser/expression/primary/mod.rs +++ b/core/parser/src/parser/expression/primary/mod.rs @@ -71,21 +71,18 @@ pub(in crate::parser) use object_initializer::Initializer; /// [spec]: https://tc39.es/ecma262/#prod-PrimaryExpression #[derive(Debug, Clone, Copy)] pub(super) struct PrimaryExpression { - name: Option, allow_yield: AllowYield, allow_await: AllowAwait, } impl PrimaryExpression { /// Creates a new `PrimaryExpression` parser. - pub(super) fn new(name: N, allow_yield: Y, allow_await: A) -> Self + pub(super) fn new(allow_yield: Y, allow_await: A) -> Self where - N: Into>, Y: Into, A: Into, { Self { - name: name.into(), allow_yield: allow_yield.into(), allow_await: allow_await.into(), } @@ -121,18 +118,18 @@ where cursor.advance(interner); let next_token = cursor.peek(0, interner).or_abrupt()?; if next_token.kind() == &TokenKind::Punctuator(Punctuator::Mul) { - GeneratorExpression::new(self.name) + GeneratorExpression::new() .parse(cursor, interner) .map(Into::into) } else { - FunctionExpression::new(self.name) + FunctionExpression::new() .parse(cursor, interner) .map(Into::into) } } TokenKind::Keyword((Keyword::Class, _)) => { cursor.advance(interner); - ClassExpression::new(self.name, self.allow_yield, self.allow_await) + ClassExpression::new(self.allow_yield, self.allow_await) .parse(cursor, interner) .map(Into::into) } @@ -154,11 +151,11 @@ where cursor.advance(interner); match cursor.peek(1, interner)?.map(Token::kind) { Some(TokenKind::Punctuator(Punctuator::Mul)) => { - AsyncGeneratorExpression::new(self.name) + AsyncGeneratorExpression::new() .parse(cursor, interner) .map(Into::into) } - _ => AsyncFunctionExpression::new(self.name) + _ => AsyncFunctionExpression::new() .parse(cursor, interner) .map(Into::into), } @@ -172,7 +169,6 @@ where cursor.advance(interner); cursor.set_goal(InputElement::RegExp); let expr = CoverParenthesizedExpressionAndArrowParameterList::new( - self.name, self.allow_yield, self.allow_await, ) @@ -295,21 +291,18 @@ where /// [spec]: https://tc39.es/ecma262/#prod-CoverParenthesizedExpressionAndArrowParameterList #[derive(Debug, Clone, Copy)] pub(super) struct CoverParenthesizedExpressionAndArrowParameterList { - name: Option, allow_yield: AllowYield, allow_await: AllowAwait, } impl CoverParenthesizedExpressionAndArrowParameterList { /// Creates a new `CoverParenthesizedExpressionAndArrowParameterList` parser. - pub(super) fn new(name: N, allow_yield: Y, allow_await: A) -> Self + pub(super) fn new(allow_yield: Y, allow_await: A) -> Self where - N: Into>, Y: Into, A: Into, { Self { - name: name.into(), allow_yield: allow_yield.into(), allow_await: allow_await.into(), } @@ -379,9 +372,8 @@ where .span() } _ => { - let expression = - Expression::new(self.name, true, self.allow_yield, self.allow_await) - .parse(cursor, interner)?; + let expression = Expression::new(true, self.allow_yield, self.allow_await) + .parse(cursor, interner)?; expressions.push(InnerExpression::Expression(expression)); let next = cursor.peek(0, interner).or_abrupt()?; diff --git a/core/parser/src/parser/expression/primary/object_initializer/mod.rs b/core/parser/src/parser/expression/primary/object_initializer/mod.rs index 46c27c77b7..8ec83d6c1d 100644 --- a/core/parser/src/parser/expression/primary/object_initializer/mod.rs +++ b/core/parser/src/parser/expression/primary/object_initializer/mod.rs @@ -26,17 +26,17 @@ use crate::{ }; use boa_ast::{ expression::{ - literal::{self, Literal}, + literal::{ + self, Literal, ObjectMethodDefinition, PropertyDefinition as PropertyDefinitionNode, + }, Identifier, }, - function::{ - AsyncFunction, AsyncGenerator, FormalParameterList, Function, Generator, PrivateName, - }, + function::{ClassElementName as ClassElementNameNode, FormalParameterList, PrivateName}, operations::{ - bound_names, contains, has_direct_super, lexically_declared_names, ContainsSymbol, + bound_names, contains, has_direct_super_new, lexically_declared_names, ContainsSymbol, }, - property::{self, MethodDefinition}, - Expression, Keyword, Punctuator, + property::{MethodDefinitionKind, PropertyName as PropertyNameNode}, + Expression, Keyword, Punctuator, Script, }; use boa_interner::{Interner, Sym}; use boa_profiler::Profiler; @@ -94,10 +94,7 @@ where if matches!( property, - property::PropertyDefinition::Property( - property::PropertyName::Literal(Sym::__PROTO__), - _ - ) + PropertyDefinitionNode::Property(PropertyNameNode::Literal(Sym::__PROTO__), _) ) { if has_proto && duplicate_proto_position.is_none() { duplicate_proto_position = Some(position); @@ -170,7 +167,7 @@ impl TokenParser for PropertyDefinition where R: ReadChar, { - type Output = property::PropertyDefinition; + type Output = PropertyDefinitionNode; fn parse(self, cursor: &mut Cursor, interner: &mut Interner) -> ParseResult { let _timer = Profiler::global().start_event("PropertyDefinition", "Parsing"); @@ -179,7 +176,7 @@ where TokenKind::Punctuator(Punctuator::CloseBlock | Punctuator::Comma) => { let ident = IdentifierReference::new(self.allow_yield, self.allow_await) .parse(cursor, interner)?; - return Ok(property::PropertyDefinition::IdentifierReference(ident)); + return Ok(PropertyDefinitionNode::IdentifierReference(ident)); } TokenKind::Punctuator(Punctuator::Assign) => { return CoverInitializedName::new(self.allow_yield, self.allow_await) @@ -190,9 +187,9 @@ where // ... AssignmentExpression[+In, ?Yield, ?Await] if cursor.next_if(Punctuator::Spread, interner)?.is_some() { - let node = AssignmentExpression::new(None, true, self.allow_yield, self.allow_await) + let node = AssignmentExpression::new(true, self.allow_yield, self.allow_await) .parse(cursor, interner)?; - return Ok(property::PropertyDefinition::SpreadObject(node)); + return Ok(PropertyDefinitionNode::SpreadObject(node)); } //Async [AsyncMethod, AsyncGeneratorMethod] object methods @@ -217,17 +214,11 @@ where let position = token.span().start(); if token.kind() == &TokenKind::Punctuator(Punctuator::Mul) { - let (class_element_name, method) = + let (class_element_name, params, body) = AsyncGeneratorMethod::new(self.allow_yield, self.allow_await) .parse(cursor, interner)?; - // It is a Syntax Error if HasDirectSuper of MethodDefinition is true. - if has_direct_super(&method) { - return Err(Error::general("invalid super usage", position)); - } - - let property::ClassElementName::PropertyName(property_name) = - class_element_name + let ClassElementNameNode::PropertyName(property_name) = class_element_name else { return Err(Error::general( "private identifiers not allowed in object literal", @@ -235,30 +226,48 @@ where )); }; - return Ok(property::PropertyDefinition::MethodDefinition( - property_name, - method, + // Early Error: It is a Syntax Error if HasDirectSuper of MethodDefinition is true. + if has_direct_super_new(¶ms, &body) { + return Err(Error::lex(LexError::Syntax( + "invalid super call usage".into(), + position, + ))); + } + + return Ok(PropertyDefinitionNode::MethodDefinition( + ObjectMethodDefinition::new( + property_name, + params, + body, + MethodDefinitionKind::AsyncGenerator, + ), )); } - let (class_element_name, method) = + let (class_element_name, params, body) = AsyncMethod::new(self.allow_yield, self.allow_await).parse(cursor, interner)?; - let property::ClassElementName::PropertyName(property_name) = class_element_name - else { + let ClassElementNameNode::PropertyName(property_name) = class_element_name else { return Err(Error::general( "private identifiers not allowed in object literal", position, )); }; - // It is a Syntax Error if HasDirectSuper of MethodDefinition is true. - if has_direct_super(&method) { - return Err(Error::general("invalid super usage", position)); + // Early Error: It is a Syntax Error if HasDirectSuper of MethodDefinition is true. + if has_direct_super_new(¶ms, &body) { + return Err(Error::lex(LexError::Syntax( + "invalid super call usage".into(), + position, + ))); } - return Ok(property::PropertyDefinition::MethodDefinition( - property_name, - method, + return Ok(PropertyDefinitionNode::MethodDefinition( + ObjectMethodDefinition::new( + property_name, + params, + body, + MethodDefinitionKind::Async, + ), )); } _ => {} @@ -268,28 +277,32 @@ where if token.kind() == &TokenKind::Punctuator(Punctuator::Mul) { let position = cursor.peek(0, interner).or_abrupt()?.span().start(); - let (class_element_name, method) = + let (class_element_name, params, body) = GeneratorMethod::new(self.allow_yield, self.allow_await).parse(cursor, interner)?; - // It is a Syntax Error if HasDirectSuper of MethodDefinition is true. - if has_direct_super(&method) { - return Err(Error::general("invalid super usage", position)); - } + let ClassElementNameNode::PropertyName(property_name) = class_element_name else { + return Err(Error::general( + "private identifier not allowed in object literal", + position, + )); + }; - match class_element_name { - property::ClassElementName::PropertyName(property_name) => { - return Ok(property::PropertyDefinition::MethodDefinition( - property_name, - method, - )) - } - property::ClassElementName::PrivateIdentifier(_) => { - return Err(Error::general( - "private identifier not allowed in object literal", - position, - )) - } + // Early Error: It is a Syntax Error if HasDirectSuper of MethodDefinition is true. + if has_direct_super_new(¶ms, &body) { + return Err(Error::lex(LexError::Syntax( + "invalid super call usage".into(), + position, + ))); } + + return Ok(PropertyDefinitionNode::MethodDefinition( + ObjectMethodDefinition::new( + property_name, + params, + body, + MethodDefinitionKind::Generator, + ), + )); } let set_or_get_escaped_position = match token.kind() { @@ -304,15 +317,16 @@ where // PropertyName[?Yield, ?Await] : AssignmentExpression[+In, ?Yield, ?Await] if cursor.next_if(Punctuator::Colon, interner)?.is_some() { - let name = property_name - .literal() - .filter(|name| *name != Sym::__PROTO__) - .map(Into::into); - - let value = AssignmentExpression::new(name, true, self.allow_yield, self.allow_await) + let mut value = AssignmentExpression::new(true, self.allow_yield, self.allow_await) .parse(cursor, interner)?; - return Ok(property::PropertyDefinition::Property(property_name, value)); + if let Some(name) = property_name.literal() { + if name != Sym::__PROTO__ { + value.set_anonymous_function_definition_name(&Identifier::new(name)); + } + } + + return Ok(PropertyDefinitionNode::Property(property_name, value)); } let ordinary_method = cursor.peek(0, interner).or_abrupt()?.kind() @@ -320,7 +334,7 @@ where match property_name { // MethodDefinition[?Yield, ?Await] -> get ClassElementName[?Yield, ?Await] ( ) { FunctionBody[~Yield, ~Await] } - property::PropertyName::Literal(str) if str == Sym::GET && !ordinary_method => { + PropertyNameNode::Literal(str) if str == Sym::GET && !ordinary_method => { if let Some(position) = set_or_get_escaped_position { return Err(Error::general( "Keyword must not contain escaped characters", @@ -356,24 +370,25 @@ where interner, )?; - let method = MethodDefinition::Get(Function::new( - None, - FormalParameterList::default(), - body, - )); - - // It is a Syntax Error if HasDirectSuper of MethodDefinition is true. - if has_direct_super(&method) { - return Err(Error::general("invalid super usage", position)); + // Early Error: It is a Syntax Error if HasDirectSuper of MethodDefinition is true. + if has_direct_super_new(&FormalParameterList::default(), &body) { + return Err(Error::lex(LexError::Syntax( + "invalid super call usage".into(), + position, + ))); } - Ok(property::PropertyDefinition::MethodDefinition( - property_name, - method, + Ok(PropertyDefinitionNode::MethodDefinition( + ObjectMethodDefinition::new( + property_name, + FormalParameterList::default(), + body, + MethodDefinitionKind::Get, + ), )) } // MethodDefinition[?Yield, ?Await] -> set ClassElementName[?Yield, ?Await] ( PropertySetParameterList ) { FunctionBody[~Yield, ~Await] } - property::PropertyName::Literal(str) if str == Sym::SET && !ordinary_method => { + PropertyNameNode::Literal(str) if str == Sym::SET && !ordinary_method => { if let Some(position) = set_or_get_escaped_position { return Err(Error::general( "Keyword must not contain escaped characters", @@ -392,7 +407,7 @@ where )? .span() .end(); - let parameters: FormalParameterList = FormalParameter::new(false, false) + let params: FormalParameterList = FormalParameter::new(false, false) .parse(cursor, interner)? .into(); cursor.expect( @@ -414,7 +429,7 @@ where )?; // Catch early error for BindingIdentifier. - if body.strict() && contains(¶meters, ContainsSymbol::EvalOrArguments) { + if body.strict() && contains(¶ms, ContainsSymbol::EvalOrArguments) { return Err(Error::lex(LexError::Syntax( "unexpected identifier 'eval' or 'arguments' in strict mode".into(), params_start_position, @@ -424,7 +439,7 @@ where // It is a Syntax Error if FunctionBodyContainsUseStrict of FunctionBody is true // and IsSimpleParameterList of PropertySetParameterList is false. // https://tc39.es/ecma262/#sec-method-definitions-static-semantics-early-errors - if body.strict() && !parameters.is_simple() { + if body.strict() && !params.is_simple() { return Err(Error::lex(LexError::Syntax( "Illegal 'use strict' directive in function with non-simple parameter list" .into(), @@ -436,23 +451,27 @@ where // occurs in the LexicallyDeclaredNames of FunctionBody. // https://tc39.es/ecma262/#sec-method-definitions-static-semantics-early-errors name_in_lexically_declared_names( - &bound_names(¶meters), + &bound_names(¶ms), &lexically_declared_names(&body), params_start_position, interner, )?; - let method = MethodDefinition::Set(Function::new(None, parameters, body)); - - // It is a Syntax Error if HasDirectSuper of MethodDefinition is true. - // https://tc39.es/ecma262/#sec-object-initializer-static-semantics-early-errors - if has_direct_super(&method) { - return Err(Error::general("invalid super usage", params_start_position)); + // Early Error: It is a Syntax Error if HasDirectSuper of MethodDefinition is true. + if has_direct_super_new(¶ms, &body) { + return Err(Error::lex(LexError::Syntax( + "invalid super call usage".into(), + params_start_position, + ))); } - Ok(property::PropertyDefinition::MethodDefinition( - property_name, - method, + Ok(PropertyDefinitionNode::MethodDefinition( + ObjectMethodDefinition::new( + property_name, + params, + body, + MethodDefinitionKind::Set, + ), )) } // MethodDefinition[?Yield, ?Await] -> ClassElementName[?Yield, ?Await] ( UniqueFormalParameters[~Yield, ~Await] ) { FunctionBody[~Yield, ~Await] } @@ -511,16 +530,21 @@ where interner, )?; - let method = MethodDefinition::Ordinary(Function::new(None, params, body)); - - // It is a Syntax Error if HasDirectSuper of MethodDefinition is true. - if has_direct_super(&method) { - return Err(Error::general("invalid super usage", params_start_position)); + // Early Error: It is a Syntax Error if HasDirectSuper of MethodDefinition is true. + if has_direct_super_new(¶ms, &body) { + return Err(Error::lex(LexError::Syntax( + "invalid super call usage".into(), + params_start_position, + ))); } - Ok(property::PropertyDefinition::MethodDefinition( - property_name, - method, + Ok(PropertyDefinitionNode::MethodDefinition( + ObjectMethodDefinition::new( + property_name, + params, + body, + MethodDefinitionKind::Ordinary, + ), )) } } @@ -557,7 +581,7 @@ impl TokenParser for PropertyName where R: ReadChar, { - type Output = property::PropertyName; + type Output = PropertyNameNode; fn parse(self, cursor: &mut Cursor, interner: &mut Interner) -> ParseResult { let _timer = Profiler::global().start_event("PropertyName", "Parsing"); @@ -566,9 +590,8 @@ where let name = match token.kind() { TokenKind::Punctuator(Punctuator::OpenBracket) => { cursor.advance(interner); - let node = - AssignmentExpression::new(None, true, self.allow_yield, self.allow_await) - .parse(cursor, interner)?; + let node = AssignmentExpression::new(true, self.allow_yield, self.allow_await) + .parse(cursor, interner)?; cursor.expect(Punctuator::CloseBracket, "expected token ']'", interner)?; return Ok(node.into()); } @@ -633,7 +656,7 @@ impl TokenParser for ClassElementName where R: ReadChar, { - type Output = property::ClassElementName; + type Output = ClassElementNameNode; fn parse(self, cursor: &mut Cursor, interner: &mut Interner) -> ParseResult { let _timer = Profiler::global().start_event("ClassElementName", "Parsing"); @@ -643,11 +666,9 @@ where TokenKind::PrivateIdentifier(ident) => { let ident = *ident; cursor.advance(interner); - Ok(property::ClassElementName::PrivateIdentifier( - PrivateName::new(ident), - )) + Ok(ClassElementNameNode::PrivateName(PrivateName::new(ident))) } - _ => Ok(property::ClassElementName::PropertyName( + _ => Ok(ClassElementNameNode::PropertyName( PropertyName::new(self.allow_yield, self.allow_await).parse(cursor, interner)?, )), } @@ -662,7 +683,6 @@ where /// [spec]: https://tc39.es/ecma262/#prod-Initializer #[derive(Debug, Clone, Copy)] pub(in crate::parser) struct Initializer { - name: Option, allow_in: AllowIn, allow_yield: AllowYield, allow_await: AllowAwait, @@ -670,20 +690,13 @@ pub(in crate::parser) struct Initializer { impl Initializer { /// Creates a new `Initializer` parser. - pub(in crate::parser) fn new( - name: N, - allow_in: I, - allow_yield: Y, - allow_await: A, - ) -> Self + pub(in crate::parser) fn new(allow_in: I, allow_yield: Y, allow_await: A) -> Self where - N: Into>, I: Into, Y: Into, A: Into, { Self { - name: name.into(), allow_in: allow_in.into(), allow_yield: allow_yield.into(), allow_await: allow_await.into(), @@ -701,7 +714,7 @@ where let _timer = Profiler::global().start_event("Initializer", "Parsing"); cursor.expect(Punctuator::Assign, "initializer", interner)?; - AssignmentExpression::new(self.name, self.allow_in, self.allow_yield, self.allow_await) + AssignmentExpression::new(self.allow_in, self.allow_yield, self.allow_await) .parse(cursor, interner) } } @@ -736,7 +749,7 @@ impl TokenParser for GeneratorMethod where R: ReadChar, { - type Output = (property::ClassElementName, MethodDefinition); + type Output = (ClassElementNameNode, FormalParameterList, Script); fn parse(self, cursor: &mut Cursor, interner: &mut Interner) -> ParseResult { let _timer = Profiler::global().start_event("GeneratorMethod", "Parsing"); @@ -790,16 +803,15 @@ where interner, )?; - let method = MethodDefinition::Generator(Generator::new(None, params, body, false)); - - if contains(&method, ContainsSymbol::Super) { + // Early Error: It is a Syntax Error if HasDirectSuper of AsyncMethod is true. + if has_direct_super_new(¶ms, &body) { return Err(Error::lex(LexError::Syntax( - "invalid super usage".into(), + "invalid super call usage".into(), body_start, ))); } - Ok((class_element_name, method)) + Ok((class_element_name, params, body)) } } @@ -833,7 +845,7 @@ impl TokenParser for AsyncGeneratorMethod where R: ReadChar, { - type Output = (property::ClassElementName, MethodDefinition); + type Output = (ClassElementNameNode, FormalParameterList, Script); fn parse(self, cursor: &mut Cursor, interner: &mut Interner) -> ParseResult { let _timer = Profiler::global().start_event("AsyncGeneratorMethod", "Parsing"); @@ -850,7 +862,7 @@ where let params = UniqueFormalParameters::new(true, true).parse(cursor, interner)?; - // It is a Syntax Error if FormalParameters Contains YieldExpression is true. + // Early Error: It is a Syntax Error if UniqueFormalParameters Contains YieldExpression is true. if contains(¶ms, ContainsSymbol::YieldExpression) { return Err(Error::lex(LexError::Syntax( "yield expression not allowed in async generator method definition parameters" @@ -859,7 +871,7 @@ where ))); } - // It is a Syntax Error if FormalParameters Contains AwaitExpression is true. + // Early Error: It is a Syntax Error if UniqueFormalParameters Contains AwaitExpression is true. if contains(¶ms, ContainsSymbol::AwaitExpression) { return Err(Error::lex(LexError::Syntax( "await expression not allowed in async generator method definition parameters" @@ -892,8 +904,8 @@ where ))); } - // Early Error: It is a Syntax Error if any element of the BoundNames of UniqueFormalParameters also - // occurs in the LexicallyDeclaredNames of GeneratorBody. + // Early Error: It is a Syntax Error if any element of the BoundNames of UniqueFormalParameters + // also occurs in the LexicallyDeclaredNames of AsyncGeneratorBody. name_in_lexically_declared_names( &bound_names(¶ms), &lexically_declared_names(&body), @@ -901,17 +913,15 @@ where interner, )?; - let method = - MethodDefinition::AsyncGenerator(AsyncGenerator::new(None, params, body, false)); - - if contains(&method, ContainsSymbol::Super) { + // Early Error: It is a Syntax Error if HasDirectSuper of AsyncMethod is true. + if has_direct_super_new(¶ms, &body) { return Err(Error::lex(LexError::Syntax( - "invalid super usage".into(), + "invalid super call usage".into(), body_start, ))); } - Ok((name, method)) + Ok((name, params, body)) } } @@ -945,7 +955,7 @@ impl TokenParser for AsyncMethod where R: ReadChar, { - type Output = (property::ClassElementName, MethodDefinition); + type Output = (ClassElementNameNode, FormalParameterList, Script); fn parse(self, cursor: &mut Cursor, interner: &mut Interner) -> ParseResult { let _timer = Profiler::global().start_event("AsyncMethod", "Parsing"); @@ -972,8 +982,8 @@ where interner, )?; - // Early Error: It is a Syntax Error if FunctionBodyContainsUseStrict of FunctionBody is true - // and IsSimpleParameterList of UniqueFormalParameters is false. + // Early Error: It is a Syntax Error if FunctionBodyContainsUseStrict of AsyncFunctionBody + // is true and IsSimpleParameterList of UniqueFormalParameters is false. if body.strict() && !params.is_simple() { return Err(Error::lex(LexError::Syntax( "Illegal 'use strict' directive in function with non-simple parameter list".into(), @@ -981,8 +991,8 @@ where ))); } - // Early Error: It is a Syntax Error if any element of the BoundNames of UniqueFormalParameters also - // occurs in the LexicallyDeclaredNames of GeneratorBody. + // Early Error: It is a Syntax Error if any element of the BoundNames of UniqueFormalParameters + // also occurs in the LexicallyDeclaredNames of AsyncFunctionBody. name_in_lexically_declared_names( &bound_names(¶ms), &lexically_declared_names(&body), @@ -990,16 +1000,15 @@ where interner, )?; - let method = MethodDefinition::Async(AsyncFunction::new(None, params, body, false)); - - if contains(&method, ContainsSymbol::Super) { + // Early Error: It is a Syntax Error if HasDirectSuper of AsyncMethod is true. + if has_direct_super_new(¶ms, &body) { return Err(Error::lex(LexError::Syntax( - "invalid super usage".into(), + "invalid super call usage".into(), body_start, ))); } - Ok((class_element_name, method)) + Ok((class_element_name, params, body)) } } @@ -1033,7 +1042,7 @@ impl TokenParser for CoverInitializedName where R: ReadChar, { - type Output = property::PropertyDefinition; + type Output = PropertyDefinitionNode; fn parse(self, cursor: &mut Cursor, interner: &mut Interner) -> ParseResult { let _timer = Profiler::global().start_event("CoverInitializedName", "Parsing"); @@ -1043,11 +1052,9 @@ where cursor.expect(Punctuator::Assign, "CoverInitializedName", interner)?; - let expr = AssignmentExpression::new(ident, true, self.allow_yield, self.allow_await) + let expr = AssignmentExpression::new(true, self.allow_yield, self.allow_await) .parse(cursor, interner)?; - Ok(property::PropertyDefinition::CoverInitializedName( - ident, expr, - )) + Ok(PropertyDefinitionNode::CoverInitializedName(ident, expr)) } } diff --git a/core/parser/src/parser/expression/primary/object_initializer/tests.rs b/core/parser/src/parser/expression/primary/object_initializer/tests.rs index 0fcee57cc8..4606f18b2e 100644 --- a/core/parser/src/parser/expression/primary/object_initializer/tests.rs +++ b/core/parser/src/parser/expression/primary/object_initializer/tests.rs @@ -2,14 +2,11 @@ use crate::parser::tests::{check_invalid_script, check_script_parser}; use boa_ast::{ declaration::{LexicalDeclaration, Variable}, expression::{ - literal::{Literal, ObjectLiteral}, + literal::{Literal, ObjectLiteral, ObjectMethodDefinition, PropertyDefinition}, Identifier, }, - function::{ - AsyncFunction, AsyncGenerator, FormalParameter, FormalParameterList, - FormalParameterListFlags, Function, FunctionBody, - }, - property::{MethodDefinition, PropertyDefinition, PropertyName}, + function::{FormalParameter, FormalParameterList, FormalParameterListFlags, FunctionBody}, + property::{MethodDefinitionKind, PropertyName}, Declaration, }; use boa_interner::{Interner, Sym}; @@ -60,14 +57,12 @@ fn check_object_short_function() { interner.get_or_intern_static("a", utf16!("a")).into(), Literal::from(true).into(), ), - PropertyDefinition::MethodDefinition( + PropertyDefinition::MethodDefinition(ObjectMethodDefinition::new( interner.get_or_intern_static("b", utf16!("b")).into(), - MethodDefinition::Ordinary(Function::new( - None, - FormalParameterList::default(), - FunctionBody::default(), - )), - ), + FormalParameterList::default(), + FunctionBody::default(), + MethodDefinitionKind::Ordinary, + )), ]; check_script_parser( @@ -110,10 +105,12 @@ fn check_object_short_function_arguments() { interner.get_or_intern_static("a", utf16!("a")).into(), Literal::from(true).into(), ), - PropertyDefinition::MethodDefinition( + PropertyDefinition::MethodDefinition(ObjectMethodDefinition::new( interner.get_or_intern_static("b", utf16!("b")).into(), - MethodDefinition::Ordinary(Function::new(None, parameters, FunctionBody::default())), - ), + parameters, + FunctionBody::default(), + MethodDefinitionKind::Ordinary, + )), ]; check_script_parser( @@ -144,14 +141,12 @@ fn check_object_getter() { interner.get_or_intern_static("a", utf16!("a")).into(), Literal::from(true).into(), ), - PropertyDefinition::MethodDefinition( + PropertyDefinition::MethodDefinition(ObjectMethodDefinition::new( interner.get_or_intern_static("b", utf16!("b")).into(), - MethodDefinition::Get(Function::new( - None, - FormalParameterList::default(), - FunctionBody::default(), - )), - ), + FormalParameterList::default(), + FunctionBody::default(), + MethodDefinitionKind::Get, + )), ]; check_script_parser( @@ -193,10 +188,12 @@ fn check_object_setter() { interner.get_or_intern_static("a", utf16!("a")).into(), Literal::from(true).into(), ), - PropertyDefinition::MethodDefinition( + PropertyDefinition::MethodDefinition(ObjectMethodDefinition::new( interner.get_or_intern_static("b", utf16!("b")).into(), - MethodDefinition::Set(Function::new(None, params, FunctionBody::default())), - ), + params, + FunctionBody::default(), + MethodDefinitionKind::Set, + )), ]; check_script_parser( @@ -223,12 +220,12 @@ fn check_object_short_function_get() { let interner = &mut Interner::default(); let object_properties = vec![PropertyDefinition::MethodDefinition( - Sym::GET.into(), - MethodDefinition::Ordinary(Function::new( - None, + ObjectMethodDefinition::new( + Sym::GET.into(), FormalParameterList::default(), FunctionBody::default(), - )), + MethodDefinitionKind::Ordinary, + ), )]; check_script_parser( @@ -254,12 +251,12 @@ fn check_object_short_function_set() { let interner = &mut Interner::default(); let object_properties = vec![PropertyDefinition::MethodDefinition( - Sym::SET.into(), - MethodDefinition::Ordinary(Function::new( - None, + ObjectMethodDefinition::new( + Sym::SET.into(), FormalParameterList::default(), FunctionBody::default(), - )), + MethodDefinitionKind::Ordinary, + ), )]; check_script_parser( @@ -402,13 +399,12 @@ fn check_async_method() { let interner = &mut Interner::default(); let object_properties = vec![PropertyDefinition::MethodDefinition( - interner.get_or_intern_static("dive", utf16!("dive")).into(), - MethodDefinition::Async(AsyncFunction::new( - None, + ObjectMethodDefinition::new( + PropertyName::Literal(interner.get_or_intern_static("dive", utf16!("dive"))), FormalParameterList::default(), FunctionBody::default(), - false, - )), + MethodDefinitionKind::Async, + ), )]; check_script_parser( @@ -434,15 +430,12 @@ fn check_async_generator_method() { let interner = &mut Interner::default(); let object_properties = vec![PropertyDefinition::MethodDefinition( - interner - .get_or_intern_static("vroom", utf16!("vroom")) - .into(), - MethodDefinition::AsyncGenerator(AsyncGenerator::new( - None, + ObjectMethodDefinition::new( + PropertyName::Literal(interner.get_or_intern_static("vroom", utf16!("vroom"))), FormalParameterList::default(), FunctionBody::default(), - false, - )), + MethodDefinitionKind::AsyncGenerator, + ), )]; check_script_parser( @@ -490,12 +483,12 @@ fn check_async_ordinary_method() { let interner = &mut Interner::default(); let object_properties = vec![PropertyDefinition::MethodDefinition( - PropertyName::Literal(interner.get_or_intern_static("async", utf16!("async"))), - MethodDefinition::Ordinary(Function::new( - None, + ObjectMethodDefinition::new( + PropertyName::Literal(interner.get_or_intern_static("async", utf16!("async"))), FormalParameterList::default(), FunctionBody::default(), - )), + MethodDefinitionKind::Ordinary, + ), )]; check_script_parser( diff --git a/core/parser/src/parser/expression/primary/template/mod.rs b/core/parser/src/parser/expression/primary/template/mod.rs index 5a7b0671e8..10769febdd 100644 --- a/core/parser/src/parser/expression/primary/template/mod.rs +++ b/core/parser/src/parser/expression/primary/template/mod.rs @@ -64,7 +64,7 @@ where let mut elements = vec![ TemplateElement::String(self.first), TemplateElement::Expr( - Expression::new(None, true, self.allow_yield, self.allow_await) + Expression::new(true, self.allow_yield, self.allow_await) .parse(cursor, interner)?, ), ]; @@ -85,7 +85,7 @@ where }; elements.push(TemplateElement::String(cooked)); elements.push(TemplateElement::Expr( - Expression::new(None, true, self.allow_yield, self.allow_await) + Expression::new(true, self.allow_yield, self.allow_await) .parse(cursor, interner)?, )); cursor.expect( diff --git a/core/parser/src/parser/expression/unary.rs b/core/parser/src/parser/expression/unary.rs index cab41e151f..2d81052982 100644 --- a/core/parser/src/parser/expression/unary.rs +++ b/core/parser/src/parser/expression/unary.rs @@ -20,7 +20,6 @@ use boa_ast::{ expression::{ access::PropertyAccess, operator::{unary::UnaryOp, Unary}, - Identifier, }, Expression, Keyword, Punctuator, }; @@ -37,21 +36,18 @@ use boa_profiler::Profiler; /// [spec]: https://tc39.es/ecma262/#prod-UnaryExpression #[derive(Debug, Clone, Copy)] pub(in crate::parser) struct UnaryExpression { - name: Option, allow_yield: AllowYield, allow_await: AllowAwait, } impl UnaryExpression { /// Creates a new `UnaryExpression` parser. - pub(in crate::parser) fn new(name: N, allow_yield: Y, allow_await: A) -> Self + pub(in crate::parser) fn new(allow_yield: Y, allow_await: A) -> Self where - N: Into>, Y: Into, A: Into, { Self { - name: name.into(), allow_yield: allow_yield.into(), allow_await: allow_await.into(), } @@ -129,8 +125,7 @@ where TokenKind::Keyword((Keyword::Await, false)) if self.allow_await.0 => { Ok((AwaitExpression::new(self.allow_yield).parse(cursor, interner)?).into()) } - _ => UpdateExpression::new(self.name, self.allow_yield, self.allow_await) - .parse(cursor, interner), + _ => UpdateExpression::new(self.allow_yield, self.allow_await).parse(cursor, interner), } } } diff --git a/core/parser/src/parser/expression/update.rs b/core/parser/src/parser/expression/update.rs index 413ac2bed9..bfc7b6777f 100644 --- a/core/parser/src/parser/expression/update.rs +++ b/core/parser/src/parser/expression/update.rs @@ -18,12 +18,9 @@ use crate::{ Error, }; use boa_ast::{ - expression::{ - operator::{ - update::{UpdateOp, UpdateTarget}, - Update, - }, - Identifier, + expression::operator::{ + update::{UpdateOp, UpdateTarget}, + Update, }, Expression, Position, Punctuator, }; @@ -38,21 +35,18 @@ use boa_profiler::Profiler; /// [spec]: https://tc39.es/ecma262/#prod-UpdateExpression #[derive(Debug, Clone, Copy)] pub(super) struct UpdateExpression { - name: Option, allow_yield: AllowYield, allow_await: AllowAwait, } impl UpdateExpression { /// Creates a new `UpdateExpression` parser. - pub(super) fn new(name: N, allow_yield: Y, allow_await: A) -> Self + pub(super) fn new(allow_yield: Y, allow_await: A) -> Self where - N: Into>, Y: Into, A: Into, { Self { - name: name.into(), allow_yield: allow_yield.into(), allow_await: allow_await.into(), } @@ -102,7 +96,7 @@ where .next(interner)? .expect("Punctuator::Inc token disappeared"); - let target = UnaryExpression::new(self.name, self.allow_yield, self.allow_await) + let target = UnaryExpression::new(self.allow_yield, self.allow_await) .parse(cursor, interner)?; // https://tc39.es/ecma262/#sec-update-expressions-static-semantics-early-errors @@ -121,7 +115,7 @@ where .next(interner)? .expect("Punctuator::Dec token disappeared"); - let target = UnaryExpression::new(self.name, self.allow_yield, self.allow_await) + let target = UnaryExpression::new(self.allow_yield, self.allow_await) .parse(cursor, interner)?; // https://tc39.es/ecma262/#sec-update-expressions-static-semantics-early-errors @@ -138,7 +132,7 @@ where _ => {} } - let lhs = LeftHandSideExpression::new(self.name, self.allow_yield, self.allow_await) + let lhs = LeftHandSideExpression::new(self.allow_yield, self.allow_await) .parse(cursor, interner)?; if cursor.peek_is_line_terminator(0, interner)?.unwrap_or(true) { diff --git a/core/parser/src/parser/function/mod.rs b/core/parser/src/parser/function/mod.rs index 3812964ee8..1f48e08612 100644 --- a/core/parser/src/parser/function/mod.rs +++ b/core/parser/src/parser/function/mod.rs @@ -267,7 +267,7 @@ where *t.kind() == TokenKind::Punctuator(Punctuator::Assign) }) .map(|_| { - Initializer::new(None, true, self.allow_yield, self.allow_await) + Initializer::new(true, self.allow_yield, self.allow_await) .parse(cursor, interner) }) .transpose()?; @@ -292,7 +292,7 @@ where *t.kind() == TokenKind::Punctuator(Punctuator::Assign) }) .map(|_| { - Initializer::new(None, true, self.allow_yield, self.allow_await) + Initializer::new(true, self.allow_yield, self.allow_await) .parse(cursor, interner) }) .transpose()?; @@ -356,7 +356,7 @@ where == TokenKind::Punctuator(Punctuator::Assign) { Some( - Initializer::new(None, true, self.allow_yield, self.allow_await) + Initializer::new(true, self.allow_yield, self.allow_await) .parse(cursor, interner)?, ) } else { @@ -372,7 +372,7 @@ where == TokenKind::Punctuator(Punctuator::Assign) { Some( - Initializer::new(None, true, self.allow_yield, self.allow_await) + Initializer::new(true, self.allow_yield, self.allow_await) .parse(cursor, interner)?, ) } else { @@ -388,7 +388,7 @@ where tok.kind() == &TokenKind::Punctuator(Punctuator::Assign) }) { Some( - Initializer::new(None, true, self.allow_yield, self.allow_await) + Initializer::new(true, self.allow_yield, self.allow_await) .parse(cursor, interner)?, ) } else { diff --git a/core/parser/src/parser/function/tests.rs b/core/parser/src/parser/function/tests.rs index 7d8857e285..f3b9c7050d 100644 --- a/core/parser/src/parser/function/tests.rs +++ b/core/parser/src/parser/function/tests.rs @@ -6,8 +6,8 @@ use boa_ast::{ Identifier, }, function::{ - ArrowFunction, FormalParameter, FormalParameterList, FormalParameterListFlags, Function, - FunctionBody, + ArrowFunction, FormalParameter, FormalParameterList, FormalParameterListFlags, + FunctionBody, FunctionDeclaration, }, statement::Return, Declaration, Expression, Statement, StatementListItem, @@ -28,8 +28,8 @@ fn check_basic() { check_script_parser( "function foo(a) { return a; }", - vec![Declaration::Function(Function::new_with_binding_identifier( - Some(interner.get_or_intern_static("foo", utf16!("foo")).into()), + vec![Declaration::FunctionDeclaration(FunctionDeclaration::new( + interner.get_or_intern_static("foo", utf16!("foo")).into(), params, FunctionBody::new( vec![StatementListItem::Statement(Statement::Return( @@ -39,7 +39,6 @@ fn check_basic() { ))] .into(), ), - true, )) .into()], interner, @@ -67,8 +66,8 @@ fn check_duplicates_strict_off() { assert_eq!(params.length(), 2); check_script_parser( "function foo(a, a) { return a; }", - vec![Declaration::Function(Function::new_with_binding_identifier( - Some(interner.get_or_intern_static("foo", utf16!("foo")).into()), + vec![Declaration::FunctionDeclaration(FunctionDeclaration::new( + interner.get_or_intern_static("foo", utf16!("foo")).into(), params, FunctionBody::new( vec![StatementListItem::Statement(Statement::Return( @@ -78,7 +77,6 @@ fn check_duplicates_strict_off() { ))] .into(), ), - true, )) .into()], interner, @@ -104,8 +102,8 @@ fn check_basic_semicolon_insertion() { check_script_parser( "function foo(a) { return a }", - vec![Declaration::Function(Function::new_with_binding_identifier( - Some(interner.get_or_intern_static("foo", utf16!("foo")).into()), + vec![Declaration::FunctionDeclaration(FunctionDeclaration::new( + interner.get_or_intern_static("foo", utf16!("foo")).into(), params, FunctionBody::new( vec![StatementListItem::Statement(Statement::Return( @@ -115,7 +113,6 @@ fn check_basic_semicolon_insertion() { ))] .into(), ), - true, )) .into()], interner, @@ -134,8 +131,8 @@ fn check_empty_return() { assert_eq!(params.length(), 1); check_script_parser( "function foo(a) { return; }", - vec![Declaration::Function(Function::new_with_binding_identifier( - Some(interner.get_or_intern_static("foo", utf16!("foo")).into()), + vec![Declaration::FunctionDeclaration(FunctionDeclaration::new( + interner.get_or_intern_static("foo", utf16!("foo")).into(), params, FunctionBody::new( vec![StatementListItem::Statement(Statement::Return( @@ -143,7 +140,6 @@ fn check_empty_return() { ))] .into(), ), - true, )) .into()], interner, @@ -162,8 +158,8 @@ fn check_empty_return_semicolon_insertion() { assert_eq!(params.length(), 1); check_script_parser( "function foo(a) { return }", - vec![Declaration::Function(Function::new_with_binding_identifier( - Some(interner.get_or_intern_static("foo", utf16!("foo")).into()), + vec![Declaration::FunctionDeclaration(FunctionDeclaration::new( + interner.get_or_intern_static("foo", utf16!("foo")).into(), params, FunctionBody::new( vec![StatementListItem::Statement(Statement::Return( @@ -171,7 +167,6 @@ fn check_empty_return_semicolon_insertion() { ))] .into(), ), - true, )) .into()], interner, @@ -199,11 +194,10 @@ fn check_rest_operator() { assert_eq!(params.length(), 1); check_script_parser( "function foo(a, ...b) {}", - vec![Declaration::Function(Function::new_with_binding_identifier( - Some(interner.get_or_intern_static("foo", utf16!("foo")).into()), + vec![Declaration::FunctionDeclaration(FunctionDeclaration::new( + interner.get_or_intern_static("foo", utf16!("foo")).into(), params, FunctionBody::default(), - true, )) .into()], interner, diff --git a/core/parser/src/parser/statement/block/tests.rs b/core/parser/src/parser/statement/block/tests.rs index b3897e447d..5270bd2d0b 100644 --- a/core/parser/src/parser/statement/block/tests.rs +++ b/core/parser/src/parser/statement/block/tests.rs @@ -12,7 +12,7 @@ use boa_ast::{ }, Call, Identifier, }, - function::{FormalParameterList, Function, FunctionBody}, + function::{FormalParameterList, FunctionBody, FunctionDeclaration}, statement::{Block, Return}, Declaration, Expression, Statement, StatementListItem, }; @@ -78,8 +78,8 @@ fn non_empty() { a++; }", vec![ - Declaration::Function(Function::new_with_binding_identifier( - Some(hello.into()), + Declaration::FunctionDeclaration(FunctionDeclaration::new( + hello.into(), FormalParameterList::default(), FunctionBody::new( vec![StatementListItem::Statement(Statement::Return( @@ -87,7 +87,6 @@ fn non_empty() { ))] .into(), ), - true, )) .into(), Statement::Var(VarDeclaration( @@ -136,8 +135,8 @@ fn hoisting() { UpdateTarget::Identifier(Identifier::new(a)), ))) .into(), - Declaration::Function(Function::new_with_binding_identifier( - Some(hello.into()), + Declaration::FunctionDeclaration(FunctionDeclaration::new( + hello.into(), FormalParameterList::default(), FunctionBody::new( vec![StatementListItem::Statement(Statement::Return( @@ -145,7 +144,6 @@ fn hoisting() { ))] .into(), ), - true, )) .into(), ], diff --git a/core/parser/src/parser/statement/declaration/export.rs b/core/parser/src/parser/statement/declaration/export.rs index a062465eb5..dcca0ec841 100644 --- a/core/parser/src/parser/statement/declaration/export.rs +++ b/core/parser/src/parser/statement/declaration/export.rs @@ -173,12 +173,12 @@ where TokenKind::Keyword((Keyword::Function, false)) => { let next_token = cursor.peek(1, interner).or_abrupt()?; if next_token.kind() == &TokenKind::Punctuator(Punctuator::Mul) { - AstExportDeclaration::DefaultGenerator( + AstExportDeclaration::DefaultGeneratorDeclaration( GeneratorDeclaration::new(false, true, true) .parse(cursor, interner)?, ) } else { - AstExportDeclaration::DefaultFunction( + AstExportDeclaration::DefaultFunctionDeclaration( FunctionDeclaration::new(false, true, true) .parse(cursor, interner)?, ) @@ -187,12 +187,12 @@ where TokenKind::Keyword((Keyword::Async, false)) => { let next_token = cursor.peek(2, interner).or_abrupt()?; if next_token.kind() == &TokenKind::Punctuator(Punctuator::Mul) { - AstExportDeclaration::DefaultAsyncGenerator( + AstExportDeclaration::DefaultAsyncGeneratorDeclaration( AsyncGeneratorDeclaration::new(false, true, true) .parse(cursor, interner)?, ) } else { - AstExportDeclaration::DefaultAsyncFunction( + AstExportDeclaration::DefaultAsyncFunctionDeclaration( AsyncFunctionDeclaration::new(false, true, true) .parse(cursor, interner)?, ) @@ -204,8 +204,8 @@ where ) } _ => { - let expr = AssignmentExpression::new(None, true, false, true) - .parse(cursor, interner)?; + let expr = + AssignmentExpression::new(true, false, true).parse(cursor, interner)?; cursor.expect_semicolon("default expression export", interner)?; diff --git a/core/parser/src/parser/statement/declaration/hoistable/async_function_decl/mod.rs b/core/parser/src/parser/statement/declaration/hoistable/async_function_decl/mod.rs index e0be6e13d8..97a01f5789 100644 --- a/core/parser/src/parser/statement/declaration/hoistable/async_function_decl/mod.rs +++ b/core/parser/src/parser/statement/declaration/hoistable/async_function_decl/mod.rs @@ -8,7 +8,7 @@ use crate::{ }, source::ReadChar, }; -use boa_ast::{function::AsyncFunction, Keyword}; +use boa_ast::{function::AsyncFunctionDeclaration as AsyncFunctionDeclarationNode, Keyword}; use boa_interner::Interner; /// Async Function declaration parsing. @@ -27,7 +27,7 @@ pub(in crate::parser) struct AsyncFunctionDeclaration { } impl AsyncFunctionDeclaration { - /// Creates a new `FunctionDeclaration` parser. + /// Creates a new `AsyncFunctionDeclaration` parser. pub(in crate::parser) fn new(allow_yield: Y, allow_await: A, is_default: D) -> Self where Y: Into, @@ -76,7 +76,7 @@ impl TokenParser for AsyncFunctionDeclaration where R: ReadChar, { - type Output = AsyncFunction; + type Output = AsyncFunctionDeclarationNode; fn parse(self, cursor: &mut Cursor, interner: &mut Interner) -> ParseResult { cursor.expect( @@ -93,6 +93,8 @@ where let result = parse_callable_declaration(&self, cursor, interner)?; - Ok(AsyncFunction::new(Some(result.0), result.1, result.2, true)) + Ok(AsyncFunctionDeclarationNode::new( + result.0, result.1, result.2, + )) } } diff --git a/core/parser/src/parser/statement/declaration/hoistable/async_function_decl/tests.rs b/core/parser/src/parser/statement/declaration/hoistable/async_function_decl/tests.rs index dc24d56106..e42798f412 100644 --- a/core/parser/src/parser/statement/declaration/hoistable/async_function_decl/tests.rs +++ b/core/parser/src/parser/statement/declaration/hoistable/async_function_decl/tests.rs @@ -1,6 +1,6 @@ use crate::parser::tests::check_script_parser; use boa_ast::{ - function::{AsyncFunction, FormalParameterList, FunctionBody}, + function::{AsyncFunctionDeclaration, FormalParameterList, FunctionBody}, Declaration, }; use boa_interner::{Interner, Sym}; @@ -12,17 +12,16 @@ fn async_function_declaration() { let interner = &mut Interner::default(); check_script_parser( "async function hello() {}", - vec![Declaration::AsyncFunction(AsyncFunction::new( - Some( + vec![ + Declaration::AsyncFunctionDeclaration(AsyncFunctionDeclaration::new( interner .get_or_intern_static("hello", utf16!("hello")) .into(), - ), - FormalParameterList::default(), - FunctionBody::default(), - true, - )) - .into()], + FormalParameterList::default(), + FunctionBody::default(), + )) + .into(), + ], interner, ); } @@ -33,26 +32,28 @@ fn async_function_declaration_keywords() { let interner = &mut Interner::default(); check_script_parser( "async function yield() {}", - vec![Declaration::AsyncFunction(AsyncFunction::new( - Some(Sym::YIELD.into()), - FormalParameterList::default(), - FunctionBody::default(), - true, - )) - .into()], + vec![ + Declaration::AsyncFunctionDeclaration(AsyncFunctionDeclaration::new( + Sym::YIELD.into(), + FormalParameterList::default(), + FunctionBody::default(), + )) + .into(), + ], interner, ); let interner = &mut Interner::default(); check_script_parser( "async function await() {}", - vec![Declaration::AsyncFunction(AsyncFunction::new( - Some(Sym::AWAIT.into()), - FormalParameterList::default(), - FunctionBody::default(), - true, - )) - .into()], + vec![ + Declaration::AsyncFunctionDeclaration(AsyncFunctionDeclaration::new( + Sym::AWAIT.into(), + FormalParameterList::default(), + FunctionBody::default(), + )) + .into(), + ], interner, ); } diff --git a/core/parser/src/parser/statement/declaration/hoistable/async_generator_decl/mod.rs b/core/parser/src/parser/statement/declaration/hoistable/async_generator_decl/mod.rs index 628e878be4..4438041f09 100644 --- a/core/parser/src/parser/statement/declaration/hoistable/async_generator_decl/mod.rs +++ b/core/parser/src/parser/statement/declaration/hoistable/async_generator_decl/mod.rs @@ -13,7 +13,9 @@ use crate::{ }, source::ReadChar, }; -use boa_ast::{function::AsyncGenerator, Keyword, Punctuator}; +use boa_ast::{ + function::AsyncGeneratorDeclaration as AsyncGeneratorDeclarationNode, Keyword, Punctuator, +}; use boa_interner::Interner; /// Async Generator Declaration Parser @@ -89,7 +91,7 @@ impl TokenParser for AsyncGeneratorDeclaration where R: ReadChar, { - type Output = AsyncGenerator; + type Output = AsyncGeneratorDeclarationNode; fn parse(self, cursor: &mut Cursor, interner: &mut Interner) -> ParseResult { cursor.expect( @@ -107,11 +109,8 @@ where let result = parse_callable_declaration(&self, cursor, interner)?; - Ok(AsyncGenerator::new( - Some(result.0), - result.1, - result.2, - true, + Ok(AsyncGeneratorDeclarationNode::new( + result.0, result.1, result.2, )) } } diff --git a/core/parser/src/parser/statement/declaration/hoistable/async_generator_decl/tests.rs b/core/parser/src/parser/statement/declaration/hoistable/async_generator_decl/tests.rs index a08f7313f0..2f19eb339a 100644 --- a/core/parser/src/parser/statement/declaration/hoistable/async_generator_decl/tests.rs +++ b/core/parser/src/parser/statement/declaration/hoistable/async_generator_decl/tests.rs @@ -1,6 +1,6 @@ use crate::parser::tests::check_script_parser; use boa_ast::{ - function::{AsyncGenerator, FormalParameterList, FunctionBody}, + function::{AsyncGeneratorDeclaration, FormalParameterList, FunctionBody}, Declaration, }; use boa_interner::Interner; @@ -11,13 +11,14 @@ fn async_generator_function_declaration() { let interner = &mut Interner::default(); check_script_parser( "async function* gen() {}", - vec![Declaration::AsyncGenerator(AsyncGenerator::new( - Some(interner.get_or_intern_static("gen", utf16!("gen")).into()), - FormalParameterList::default(), - FunctionBody::default(), - true, - )) - .into()], + vec![ + Declaration::AsyncGeneratorDeclaration(AsyncGeneratorDeclaration::new( + interner.get_or_intern_static("gen", utf16!("gen")).into(), + FormalParameterList::default(), + FunctionBody::default(), + )) + .into(), + ], interner, ); } diff --git a/core/parser/src/parser/statement/declaration/hoistable/class_decl/mod.rs b/core/parser/src/parser/statement/declaration/hoistable/class_decl/mod.rs index afb9a42e93..de2d0e2f84 100644 --- a/core/parser/src/parser/statement/declaration/hoistable/class_decl/mod.rs +++ b/core/parser/src/parser/statement/declaration/hoistable/class_decl/mod.rs @@ -20,13 +20,16 @@ use ast::{ operations::{ check_labels, contains_invalid_object_literal, lexically_declared_names, var_declared_names, }, + property::MethodDefinitionKind, }; use boa_ast::{ self as ast, expression::Identifier, - function::{self, Class, FormalParameterList, Function}, - operations::{contains, contains_arguments, has_direct_super, ContainsSymbol}, - property::{ClassElementName, MethodDefinition}, + function::{ + self, ClassDeclaration as ClassDeclarationNode, ClassElementName, ClassMethodDefinition, + FormalParameterList, FunctionExpression, + }, + operations::{contains, contains_arguments, ContainsSymbol}, Expression, Keyword, Punctuator, }; use boa_interner::{Interner, Sym}; @@ -68,19 +71,17 @@ impl TokenParser for ClassDeclaration where R: ReadChar, { - type Output = Class; + type Output = ClassDeclarationNode; fn parse(self, cursor: &mut Cursor, interner: &mut Interner) -> ParseResult { cursor.expect((Keyword::Class, false), "class declaration", interner)?; let strict = cursor.strict(); cursor.set_strict(true); - let mut has_binding_identifier = false; let token = cursor.peek(0, interner).or_abrupt()?; let name = match token.kind() { TokenKind::IdentifierName(_) | TokenKind::Keyword((Keyword::Yield | Keyword::Await, _)) => { - has_binding_identifier = true; BindingIdentifier::new(self.allow_yield, self.allow_await) .parse(cursor, interner)? } @@ -95,13 +96,15 @@ where }; cursor.set_strict(strict); - ClassTail::new( + let (super_ref, constructor, elements) = + ClassTail::new(name, self.allow_yield, self.allow_await).parse(cursor, interner)?; + + Ok(ClassDeclarationNode::new( name, - has_binding_identifier, - self.allow_yield, - self.allow_await, - ) - .parse(cursor, interner) + super_ref, + constructor, + elements.into_boxed_slice(), + )) } } @@ -114,19 +117,13 @@ where #[derive(Debug, Clone, Copy)] pub(in crate::parser) struct ClassTail { name: Option, - has_binding_identifier: bool, allow_yield: AllowYield, allow_await: AllowAwait, } impl ClassTail { /// Creates a new `ClassTail` parser. - pub(in crate::parser) fn new( - name: N, - has_binding_identifier: bool, - allow_yield: Y, - allow_await: A, - ) -> Self + pub(in crate::parser) fn new(name: N, allow_yield: Y, allow_await: A) -> Self where N: Into>, Y: Into, @@ -134,7 +131,6 @@ impl ClassTail { { Self { name: name.into(), - has_binding_identifier, allow_yield: allow_yield.into(), allow_await: allow_await.into(), } @@ -145,7 +141,11 @@ impl TokenParser for ClassTail where R: ReadChar, { - type Output = Class; + type Output = ( + Option, + Option, + Vec, + ); fn parse(self, cursor: &mut Cursor, interner: &mut Interner) -> ParseResult { let token = cursor.peek(0, interner).or_abrupt()?; @@ -173,13 +173,7 @@ where if is_close_block { cursor.advance(interner); - Ok(Class::new( - self.name, - super_ref, - None, - Box::default(), - self.has_binding_identifier, - )) + Ok((super_ref, None, Vec::new())) } else { let body_start = cursor.peek(0, interner).or_abrupt()?.span().start(); let (constructor, elements) = @@ -198,13 +192,7 @@ where } } - Ok(Class::new( - self.name, - super_ref, - constructor, - elements.into(), - self.has_binding_identifier, - )) + Ok((super_ref, constructor, elements)) } } } @@ -250,7 +238,7 @@ where let strict = cursor.strict(); cursor.set_strict(true); - let lhs = LeftHandSideExpression::new(None, self.allow_yield, self.allow_await) + let lhs = LeftHandSideExpression::new(self.allow_yield, self.allow_await) .parse(cursor, interner)?; cursor.set_strict(strict); @@ -291,7 +279,7 @@ impl TokenParser for ClassBody where R: ReadChar, { - type Output = (Option, Vec); + type Output = (Option, Vec); fn parse(self, cursor: &mut Cursor, interner: &mut Interner) -> ParseResult { let mut constructor = None; @@ -305,184 +293,116 @@ where loop { let token = cursor.peek(0, interner).or_abrupt()?; let position = token.span().start(); - match token.kind() { + let (parsed_constructor, element) = match token.kind() { TokenKind::Punctuator(Punctuator::CloseBlock) => break, - _ => match ClassElement::new(self.name, self.allow_yield, self.allow_await) - .parse(cursor, interner)? - { - (Some(_), None) if constructor.is_some() => { - return Err(Error::general( - "a class may only have one constructor", - position, - )); + _ => ClassElement::new(self.name, self.allow_yield, self.allow_await) + .parse(cursor, interner)?, + }; + if let Some(c) = parsed_constructor { + if constructor.is_some() { + return Err(Error::general( + "a class may only have one constructor", + position, + )); + } + constructor = Some(c); + } + let Some(element) = element else { + continue; + }; + + match &element { + function::ClassElement::MethodDefinition(m) => { + // It is a Syntax Error if PropName of MethodDefinition is not "constructor" and HasDirectSuper of MethodDefinition is true. + if let ClassElementName::PropertyName(name) = m.name() { + if contains(name, ContainsSymbol::SuperCall) { + return Err(Error::lex(LexError::Syntax( + "invalid super call usage".into(), + position, + ))); + } } - (Some(c), None) => { - constructor = Some(c); + if contains(m.parameters(), ContainsSymbol::SuperCall) + || contains(m.body(), ContainsSymbol::SuperCall) + { + return Err(Error::lex(LexError::Syntax( + "invalid super call usage".into(), + position, + ))); } - (None, Some(element)) => { - match &element { - function::ClassElement::PrivateMethodDefinition(name, method) => { - // It is a Syntax Error if PropName of MethodDefinition is not "constructor" and HasDirectSuper of MethodDefinition is true. - if has_direct_super(method) { - return Err(Error::lex(LexError::Syntax( - "invalid super usage".into(), - position, - ))); - } - match method { - MethodDefinition::Get(_) => { - match private_elements_names.get(&name.description()) { - Some(PrivateElement::Setter) => { - private_elements_names.insert( - name.description(), - PrivateElement::Value, - ); - } - Some(_) => { - return Err(Error::general( - "private identifier has already been declared", - position, - )); - } - None => { - private_elements_names.insert( - name.description(), - PrivateElement::Getter, - ); - } - } + + if let ClassElementName::PrivateName(name) = m.name() { + match m.kind() { + MethodDefinitionKind::Get => { + match private_elements_names.get(&name.description()) { + Some(PrivateElement::StaticSetter) if m.is_static() => { + private_elements_names.insert( + name.description(), + PrivateElement::StaticValue, + ); + } + Some(PrivateElement::Setter) if !m.is_static() => { + private_elements_names + .insert(name.description(), PrivateElement::Value); } - MethodDefinition::Set(_) => { - match private_elements_names.get(&name.description()) { - Some(PrivateElement::Getter) => { - private_elements_names.insert( - name.description(), - PrivateElement::Value, - ); - } - Some(_) => { - return Err(Error::general( - "private identifier has already been declared", - position, - )); - } - None => { - private_elements_names.insert( - name.description(), - PrivateElement::Setter, - ); - } - } + Some(_) => { + return Err(Error::general( + "private identifier has already been declared", + position, + )); } - _ => { - if private_elements_names - .insert(name.description(), PrivateElement::Value) - .is_some() - { - return Err(Error::general( - "private identifier has already been declared", - position, - )); - } + None => { + private_elements_names.insert( + name.description(), + if m.is_static() { + PrivateElement::StaticGetter + } else { + PrivateElement::Getter + }, + ); } } } - function::ClassElement::PrivateStaticMethodDefinition(name, method) => { - // It is a Syntax Error if HasDirectSuper of MethodDefinition is true. - if has_direct_super(method) { - return Err(Error::lex(LexError::Syntax( - "invalid super usage".into(), - position, - ))); - } - match method { - MethodDefinition::Get(_) => { - match private_elements_names.get(&name.description()) { - Some(PrivateElement::StaticSetter) => { - private_elements_names.insert( - name.description(), - PrivateElement::StaticValue, - ); - } - Some(_) => { - return Err(Error::general( - "private identifier has already been declared", - position, - )); - } - None => { - private_elements_names.insert( - name.description(), - PrivateElement::StaticGetter, - ); - } - } - } - MethodDefinition::Set(_) => { - match private_elements_names.get(&name.description()) { - Some(PrivateElement::StaticGetter) => { - private_elements_names.insert( - name.description(), - PrivateElement::StaticValue, - ); - } - Some(_) => { - return Err(Error::general( - "private identifier has already been declared", - position, - )); - } - None => { - private_elements_names.insert( - name.description(), - PrivateElement::StaticSetter, - ); - } - } + MethodDefinitionKind::Set => { + match private_elements_names.get(&name.description()) { + Some(PrivateElement::StaticGetter) if m.is_static() => { + private_elements_names.insert( + name.description(), + PrivateElement::StaticValue, + ); } - _ => { - if private_elements_names - .insert(name.description(), PrivateElement::StaticValue) - .is_some() - { - return Err(Error::general( - "private identifier has already been declared", - position, - )); - } + Some(PrivateElement::Getter) if !m.is_static() => { + private_elements_names + .insert(name.description(), PrivateElement::Value); } - } - } - function::ClassElement::PrivateFieldDefinition(name, init) => { - if let Some(node) = init { - if contains(node, ContainsSymbol::SuperCall) { - return Err(Error::lex(LexError::Syntax( - "invalid super usage".into(), + Some(_) => { + return Err(Error::general( + "private identifier has already been declared", position, - ))); + )); } - } - if private_elements_names - .insert(name.description(), PrivateElement::Value) - .is_some() - { - return Err(Error::general( - "private identifier has already been declared", - position, - )); - } - } - function::ClassElement::PrivateStaticFieldDefinition(name, init) => { - if let Some(node) = init { - if contains(node, ContainsSymbol::SuperCall) { - return Err(Error::lex(LexError::Syntax( - "invalid super usage".into(), - position, - ))); + None => { + private_elements_names.insert( + name.description(), + if m.is_static() { + PrivateElement::StaticSetter + } else { + PrivateElement::Setter + }, + ); } } + } + _ => { if private_elements_names - .insert(name.description(), PrivateElement::StaticValue) + .insert( + name.description(), + if m.is_static() { + PrivateElement::StaticValue + } else { + PrivateElement::Value + }, + ) .is_some() { return Err(Error::general( @@ -491,35 +411,59 @@ where )); } } - function::ClassElement::MethodDefinition(_, method) - | function::ClassElement::StaticMethodDefinition(_, method) => { - // ClassElement : MethodDefinition: - // It is a Syntax Error if PropName of MethodDefinition is not "constructor" and HasDirectSuper of MethodDefinition is true. - // ClassElement : static MethodDefinition: - // It is a Syntax Error if HasDirectSuper of MethodDefinition is true. - if has_direct_super(method) { - return Err(Error::lex(LexError::Syntax( - "invalid super usage".into(), - position, - ))); - } - } - function::ClassElement::FieldDefinition(_, Some(node)) - | function::ClassElement::StaticFieldDefinition(_, Some(node)) => { - if contains(node, ContainsSymbol::SuperCall) { - return Err(Error::lex(LexError::Syntax( - "invalid super usage".into(), - position, - ))); - } - } - _ => {} } - elements.push(element); } - _ => {} - }, + } + function::ClassElement::PrivateFieldDefinition(name, init) => { + if let Some(node) = init { + if contains(node, ContainsSymbol::SuperCall) { + return Err(Error::lex(LexError::Syntax( + "invalid super usage".into(), + position, + ))); + } + } + if private_elements_names + .insert(name.description(), PrivateElement::Value) + .is_some() + { + return Err(Error::general( + "private identifier has already been declared", + position, + )); + } + } + function::ClassElement::PrivateStaticFieldDefinition(name, init) => { + if let Some(node) = init { + if contains(node, ContainsSymbol::SuperCall) { + return Err(Error::lex(LexError::Syntax( + "invalid super usage".into(), + position, + ))); + } + } + if private_elements_names + .insert(name.description(), PrivateElement::StaticValue) + .is_some() + { + return Err(Error::general( + "private identifier has already been declared", + position, + )); + } + } + function::ClassElement::FieldDefinition(_, Some(node)) + | function::ClassElement::StaticFieldDefinition(_, Some(node)) => { + if contains(node, ContainsSymbol::SuperCall) { + return Err(Error::lex(LexError::Syntax( + "invalid super usage".into(), + position, + ))); + } + } + _ => {} } + elements.push(element); } cursor.set_strict(strict); @@ -572,7 +516,7 @@ impl TokenParser for ClassElement where R: ReadChar, { - type Output = (Option, Option); + type Output = (Option, Option); fn parse(self, cursor: &mut Cursor, interner: &mut Interner) -> ParseResult { let token = cursor.peek(0, interner).or_abrupt()?; @@ -643,7 +587,10 @@ where )?; cursor.set_strict(strict); - return Ok((Some(Function::new(self.name, parameters, body)), None)); + return Ok(( + Some(FunctionExpression::new(self.name, parameters, body, false)), + None, + )); } TokenKind::Punctuator(Punctuator::OpenBlock) if r#static => { cursor.advance(interner); @@ -743,39 +690,38 @@ where } let strict = cursor.strict(); cursor.set_strict(true); - let (class_element_name, method) = + let (class_element_name, params, body) = GeneratorMethod::new(self.allow_yield, self.allow_await) .parse(cursor, interner)?; cursor.set_strict(strict); - match class_element_name { - ClassElementName::PropertyName(property_name) if r#static => { - if property_name.literal() == Some(Sym::PROTOTYPE) { + let name = match class_element_name { + ClassElementName::PropertyName(name) => { + if r#static && name.literal() == Some(Sym::PROTOTYPE) { return Err(Error::general( "class may not have static method definitions named 'prototype'", name_position, )); } - function::ClassElement::StaticMethodDefinition(property_name, method) - } - ClassElementName::PropertyName(property_name) => { - function::ClassElement::MethodDefinition(property_name, method) + ClassElementName::PropertyName(name) } - ClassElementName::PrivateIdentifier(name) - if name.description() == Sym::CONSTRUCTOR => - { - return Err(Error::general( - "class constructor may not be a private method", - name_position, - )) - } - ClassElementName::PrivateIdentifier(private_ident) if r#static => { - function::ClassElement::PrivateStaticMethodDefinition(private_ident, method) - } - ClassElementName::PrivateIdentifier(private_ident) => { - function::ClassElement::PrivateMethodDefinition(private_ident, method) + ClassElementName::PrivateName(name) => { + if name.description() == Sym::CONSTRUCTOR { + return Err(Error::general( + "class constructor may not be a private method", + name_position, + )); + } + ClassElementName::PrivateName(name) } - } + }; + function::ClassElement::MethodDefinition(ClassMethodDefinition::new( + name, + params, + body, + MethodDefinitionKind::Generator, + r#static, + )) } TokenKind::Keyword((Keyword::Async, true)) if is_keyword => { return Err(Error::general( @@ -808,39 +754,33 @@ where } let strict = cursor.strict(); cursor.set_strict(true); - let (class_element_name, method) = + let (class_element_name, params, body) = AsyncGeneratorMethod::new(self.allow_yield, self.allow_await) .parse(cursor, interner)?; cursor.set_strict(strict); - match class_element_name { - ClassElementName::PropertyName(property_name) if r#static => { - if property_name.literal() == Some(Sym::PROTOTYPE) { + + let name = match class_element_name { + ClassElementName::PropertyName(name) => { + if r#static && name.literal() == Some(Sym::PROTOTYPE) { return Err(Error::general( "class may not have static method definitions named 'prototype'", name_position, )); } - function::ClassElement::StaticMethodDefinition( - property_name, - method, - ) - } - ClassElementName::PropertyName(property_name) => { - function::ClassElement::MethodDefinition(property_name, method) + ClassElementName::PropertyName(name) } - ClassElementName::PrivateIdentifier(private_ident) if r#static => { - function::ClassElement::PrivateStaticMethodDefinition( - private_ident, - method, - ) + ClassElementName::PrivateName(name) => { + ClassElementName::PrivateName(name) } - ClassElementName::PrivateIdentifier(private_ident) => { - function::ClassElement::PrivateMethodDefinition( - private_ident, - method, - ) - } - } + }; + + function::ClassElement::MethodDefinition(ClassMethodDefinition::new( + name, + params, + body, + MethodDefinitionKind::AsyncGenerator, + r#static, + )) } TokenKind::IdentifierName((Sym::CONSTRUCTOR, _)) if !r#static => { return Err(Error::general( @@ -852,44 +792,38 @@ where let name_position = token.span().start(); let strict = cursor.strict(); cursor.set_strict(true); - let (class_element_name, method) = + let (class_element_name, params, body) = AsyncMethod::new(self.allow_yield, self.allow_await) .parse(cursor, interner)?; cursor.set_strict(strict); - match class_element_name { - ClassElementName::PropertyName(property_name) if r#static => { - if property_name.literal() == Some(Sym::PROTOTYPE) { + let name = match class_element_name { + ClassElementName::PropertyName(name) => { + if r#static && name.literal() == Some(Sym::PROTOTYPE) { return Err(Error::general( "class may not have static method definitions named 'prototype'", name_position, )); } - function::ClassElement::StaticMethodDefinition( - property_name, - method, - ) - } - ClassElementName::PropertyName(property_name) => { - function::ClassElement::MethodDefinition(property_name, method) + ClassElementName::PropertyName(name) } - ClassElementName::PrivateIdentifier(name) - if name.description() == Sym::CONSTRUCTOR && r#static => - { - return Err(Error::general( - "class constructor may not be a private method", - name_position, - )) - } - ClassElementName::PrivateIdentifier(identifier) if r#static => { - function::ClassElement::PrivateStaticMethodDefinition( - identifier, method, - ) - } - ClassElementName::PrivateIdentifier(identifier) => { - function::ClassElement::PrivateMethodDefinition(identifier, method) + ClassElementName::PrivateName(name) => { + if r#static && name.description() == Sym::CONSTRUCTOR { + return Err(Error::general( + "class constructor may not be a private method", + name_position, + )); + } + ClassElementName::PrivateName(name) } - } + }; + function::ClassElement::MethodDefinition(ClassMethodDefinition::new( + name, + params, + body, + MethodDefinitionKind::Async, + r#static, + )) } } } @@ -940,18 +874,13 @@ where ))); } cursor.set_strict(strict); - let method = MethodDefinition::Get(Function::new(None, params, body)); - if r#static { - function::ClassElement::PrivateStaticMethodDefinition( - PrivateName::new(name), - method, - ) - } else { - function::ClassElement::PrivateMethodDefinition( - PrivateName::new(name), - method, - ) - } + function::ClassElement::MethodDefinition(ClassMethodDefinition::new( + ClassElementName::PrivateName(PrivateName::new(name)), + params, + body, + MethodDefinitionKind::Get, + r#static, + )) } TokenKind::IdentifierName((Sym::CONSTRUCTOR, _)) if !r#static => { return Err(Error::general( @@ -992,23 +921,19 @@ where "class getter", interner, )?; - - let method = MethodDefinition::Get(Function::new( - None, + if r#static && name.literal() == Some(Sym::PROTOTYPE) { + return Err(Error::general( + "class may not have static method definitions named 'prototype'", + name_position, + )); + } + function::ClassElement::MethodDefinition(ClassMethodDefinition::new( + ClassElementName::PropertyName(name), FormalParameterList::default(), body, - )); - if r#static { - if name.literal() == Some(Sym::PROTOTYPE) { - return Err(Error::general( - "class may not have static method definitions named 'prototype'", - name_position, - )); - } - function::ClassElement::StaticMethodDefinition(name, method) - } else { - function::ClassElement::MethodDefinition(name, method) - } + MethodDefinitionKind::Get, + r#static, + )) } _ => { cursor.expect_semicolon("expected semicolon", interner)?; @@ -1065,18 +990,13 @@ where ))); } cursor.set_strict(strict); - let method = MethodDefinition::Set(Function::new(None, params, body)); - if r#static { - function::ClassElement::PrivateStaticMethodDefinition( - PrivateName::new(name), - method, - ) - } else { - function::ClassElement::PrivateMethodDefinition( - PrivateName::new(name), - method, - ) - } + function::ClassElement::MethodDefinition(ClassMethodDefinition::new( + ClassElementName::PrivateName(PrivateName::new(name)), + params, + body, + MethodDefinitionKind::Set, + r#static, + )) } TokenKind::IdentifierName((Sym::CONSTRUCTOR, _)) if !r#static => { return Err(Error::general( @@ -1119,18 +1039,19 @@ where ))); } cursor.set_strict(strict); - let method = MethodDefinition::Set(Function::new(None, params, body)); - if r#static { - if name.literal() == Some(Sym::PROTOTYPE) { - return Err(Error::general( - "class may not have static method definitions named 'prototype'", - name_position, - )); - } - function::ClassElement::StaticMethodDefinition(name, method) - } else { - function::ClassElement::MethodDefinition(name, method) + if r#static && name.literal() == Some(Sym::PROTOTYPE) { + return Err(Error::general( + "class may not have static method definitions named 'prototype'", + name_position, + )); } + function::ClassElement::MethodDefinition(ClassMethodDefinition::new( + ClassElementName::PropertyName(name), + params, + body, + MethodDefinitionKind::Set, + r#static, + )) } _ => { cursor.expect_semicolon("expected semicolon", interner)?; @@ -1156,11 +1077,6 @@ where } TokenKind::PrivateIdentifier(name) => { let name = *name; - let name_private = interner.get_or_intern( - [utf16!("#"), interner.resolve_expect(name).utf16()] - .concat() - .as_slice(), - ); cursor.advance(interner); let token = cursor.peek(0, interner).or_abrupt()?; match token.kind() { @@ -1168,15 +1084,17 @@ where cursor.advance(interner); let strict = cursor.strict(); cursor.set_strict(true); - let rhs = AssignmentExpression::new( - Some(name_private.into()), - true, - self.allow_yield, - self.allow_await, - ) - .parse(cursor, interner)?; + let mut rhs = + AssignmentExpression::new(true, self.allow_yield, self.allow_await) + .parse(cursor, interner)?; cursor.expect_semicolon("expected semicolon", interner)?; cursor.set_strict(strict); + let function_name = interner.get_or_intern( + [utf16!("#"), interner.resolve_expect(name).utf16()] + .concat() + .as_slice(), + ); + rhs.set_anonymous_function_definition_name(&Identifier::new(function_name)); if r#static { function::ClassElement::PrivateStaticFieldDefinition( PrivateName::new(name), @@ -1210,24 +1128,18 @@ where // and IsSimpleParameterList of UniqueFormalParameters is false. if body.strict() && !params.is_simple() { return Err(Error::lex(LexError::Syntax( - "Illegal 'use strict' directive in function with non-simple parameter list" - .into(), + "Illegal 'use strict' directive in function with non-simple parameter list".into(), token.span().start(), - ))); + ))); } - let method = MethodDefinition::Ordinary(Function::new(None, params, body)); cursor.set_strict(strict); - if r#static { - function::ClassElement::PrivateStaticMethodDefinition( - PrivateName::new(name), - method, - ) - } else { - function::ClassElement::PrivateMethodDefinition( - PrivateName::new(name), - method, - ) - } + function::ClassElement::MethodDefinition(ClassMethodDefinition::new( + ClassElementName::PrivateName(PrivateName::new(name)), + params, + body, + MethodDefinitionKind::Ordinary, + r#static, + )) } _ => { cursor.expect_semicolon("expected semicolon", interner)?; @@ -1275,15 +1187,14 @@ where cursor.advance(interner); let strict = cursor.strict(); cursor.set_strict(true); - let rhs = AssignmentExpression::new( - name.literal().map(Into::into), - true, - self.allow_yield, - self.allow_await, - ) - .parse(cursor, interner)?; + let mut rhs = + AssignmentExpression::new(true, self.allow_yield, self.allow_await) + .parse(cursor, interner)?; cursor.expect_semicolon("expected semicolon", interner)?; cursor.set_strict(strict); + if let Some(name) = name.literal() { + rhs.set_anonymous_function_definition_name(&Identifier::new(name)); + } if r#static { function::ClassElement::StaticFieldDefinition(name, Some(rhs)) } else { @@ -1322,13 +1233,14 @@ where token.span().start(), ))); } - let method = MethodDefinition::Ordinary(Function::new(None, params, body)); cursor.set_strict(strict); - if r#static { - function::ClassElement::StaticMethodDefinition(name, method) - } else { - function::ClassElement::MethodDefinition(name, method) - } + function::ClassElement::MethodDefinition(ClassMethodDefinition::new( + ClassElementName::PropertyName(name), + params, + body, + MethodDefinitionKind::Ordinary, + r#static, + )) } _ => { if let Some(name) = name.literal() { diff --git a/core/parser/src/parser/statement/declaration/hoistable/class_decl/tests.rs b/core/parser/src/parser/statement/declaration/hoistable/class_decl/tests.rs index e5f3424650..cce7f5b748 100644 --- a/core/parser/src/parser/statement/declaration/hoistable/class_decl/tests.rs +++ b/core/parser/src/parser/statement/declaration/hoistable/class_decl/tests.rs @@ -6,8 +6,11 @@ use boa_ast::{ literal::Literal, Call, Identifier, }, - function::{Class, ClassElement, FormalParameterList, Function, FunctionBody}, - property::{MethodDefinition, PropertyName}, + function::{ + ClassDeclaration, ClassElement, ClassMethodDefinition, FormalParameterList, FunctionBody, + FunctionExpression, + }, + property::{MethodDefinitionKind, PropertyName}, Declaration, Expression, Statement, StatementList, StatementListItem, }; use boa_interner::Interner; @@ -17,26 +20,26 @@ use boa_macros::utf16; fn check_async_ordinary_method() { let interner = &mut Interner::default(); - let elements = vec![ClassElement::MethodDefinition( - PropertyName::Literal(interner.get_or_intern_static("async", utf16!("async"))), - MethodDefinition::Ordinary(Function::new( - None, - FormalParameterList::default(), - FunctionBody::default(), + let elements = vec![ClassElement::MethodDefinition(ClassMethodDefinition::new( + boa_ast::function::ClassElementName::PropertyName(PropertyName::Literal( + interner.get_or_intern_static("async", utf16!("async")), )), - )]; + FormalParameterList::default(), + FunctionBody::default(), + MethodDefinitionKind::Ordinary, + false, + ))]; check_script_parser( "class A { async() { } } ", - [Declaration::Class(Class::new( - Some(interner.get_or_intern_static("A", utf16!("A")).into()), + [Declaration::ClassDeclaration(ClassDeclaration::new( + interner.get_or_intern_static("A", utf16!("A")).into(), None, None, elements.into(), - true, )) .into()], interner, @@ -58,12 +61,11 @@ fn check_async_field_initialization() { = 1 } ", - [Declaration::Class(Class::new( - Some(interner.get_or_intern_static("A", utf16!("A")).into()), + [Declaration::ClassDeclaration(ClassDeclaration::new( + interner.get_or_intern_static("A", utf16!("A")).into(), None, None, elements.into(), - true, )) .into()], interner, @@ -84,12 +86,11 @@ fn check_async_field() { async } ", - [Declaration::Class(Class::new( - Some(interner.get_or_intern_static("A", utf16!("A")).into()), + [Declaration::ClassDeclaration(ClassDeclaration::new( + interner.get_or_intern_static("A", utf16!("A")).into(), None, None, elements.into(), - true, )) .into()], interner, @@ -117,21 +118,21 @@ fn check_new_target_with_property_access() { [new_target].into(), )); - let constructor = Function::new( + let constructor = FunctionExpression::new( Some(interner.get_or_intern_static("A", utf16!("A")).into()), FormalParameterList::default(), FunctionBody::new(StatementList::new( [Statement::Expression(console).into()], false, )), + false, ); - let class = Class::new( - Some(interner.get("A").unwrap().into()), + let class = ClassDeclaration::new( + interner.get("A").unwrap().into(), None, Some(constructor), Box::default(), - true, ); let instantiation = Expression::New( diff --git a/core/parser/src/parser/statement/declaration/hoistable/function_decl/mod.rs b/core/parser/src/parser/statement/declaration/hoistable/function_decl/mod.rs index adaf266689..da764fdd9f 100644 --- a/core/parser/src/parser/statement/declaration/hoistable/function_decl/mod.rs +++ b/core/parser/src/parser/statement/declaration/hoistable/function_decl/mod.rs @@ -8,7 +8,7 @@ use crate::{ }, source::ReadChar, }; -use boa_ast::{function::Function, Keyword}; +use boa_ast::{function::FunctionDeclaration as FunctionDeclarationNode, Keyword}; use boa_interner::Interner; /// Function declaration parsing. @@ -74,18 +74,13 @@ impl TokenParser for FunctionDeclaration where R: ReadChar, { - type Output = Function; + type Output = FunctionDeclarationNode; fn parse(self, cursor: &mut Cursor, interner: &mut Interner) -> ParseResult { cursor.expect((Keyword::Function, false), "function declaration", interner)?; let result = parse_callable_declaration(&self, cursor, interner)?; - Ok(Function::new_with_binding_identifier( - Some(result.0), - result.1, - result.2, - true, - )) + Ok(FunctionDeclarationNode::new(result.0, result.1, result.2)) } } diff --git a/core/parser/src/parser/statement/declaration/hoistable/function_decl/tests.rs b/core/parser/src/parser/statement/declaration/hoistable/function_decl/tests.rs index 271b6410a5..274c97b2f5 100644 --- a/core/parser/src/parser/statement/declaration/hoistable/function_decl/tests.rs +++ b/core/parser/src/parser/statement/declaration/hoistable/function_decl/tests.rs @@ -1,6 +1,6 @@ use crate::parser::tests::check_script_parser; use boa_ast::{ - function::{FormalParameterList, Function, FunctionBody}, + function::{FormalParameterList, FunctionBody, FunctionDeclaration}, Declaration, }; use boa_interner::Interner; @@ -12,15 +12,12 @@ fn function_declaration() { let interner = &mut Interner::default(); check_script_parser( "function hello() {}", - vec![Declaration::Function(Function::new_with_binding_identifier( - Some( - interner - .get_or_intern_static("hello", utf16!("hello")) - .into(), - ), + vec![Declaration::FunctionDeclaration(FunctionDeclaration::new( + interner + .get_or_intern_static("hello", utf16!("hello")) + .into(), FormalParameterList::default(), FunctionBody::default(), - true, )) .into()], interner, @@ -32,15 +29,12 @@ fn function_declaration() { fn function_declaration_keywords() { macro_rules! genast { ($keyword:literal, $interner:expr) => { - vec![Declaration::Function(Function::new_with_binding_identifier( - Some( - $interner - .get_or_intern_static($keyword, utf16!($keyword)) - .into(), - ), + vec![Declaration::FunctionDeclaration(FunctionDeclaration::new( + $interner + .get_or_intern_static($keyword, utf16!($keyword)) + .into(), FormalParameterList::default(), FunctionBody::default(), - true, )) .into()] }; diff --git a/core/parser/src/parser/statement/declaration/hoistable/generator_decl/mod.rs b/core/parser/src/parser/statement/declaration/hoistable/generator_decl/mod.rs index 911c25529e..30681a0382 100644 --- a/core/parser/src/parser/statement/declaration/hoistable/generator_decl/mod.rs +++ b/core/parser/src/parser/statement/declaration/hoistable/generator_decl/mod.rs @@ -8,7 +8,7 @@ use crate::{ }, source::ReadChar, }; -use boa_ast::{function::Generator, Keyword, Punctuator}; +use boa_ast::{function::GeneratorDeclaration as GeneratorDeclarationNode, Keyword, Punctuator}; use boa_interner::Interner; /// Generator declaration parsing. @@ -76,7 +76,7 @@ impl TokenParser for GeneratorDeclaration where R: ReadChar, { - type Output = Generator; + type Output = GeneratorDeclarationNode; fn parse(self, cursor: &mut Cursor, interner: &mut Interner) -> ParseResult { cursor.expect( @@ -88,6 +88,6 @@ where let result = parse_callable_declaration(&self, cursor, interner)?; - Ok(Generator::new(Some(result.0), result.1, result.2, true)) + Ok(GeneratorDeclarationNode::new(result.0, result.1, result.2)) } } diff --git a/core/parser/src/parser/statement/declaration/hoistable/generator_decl/tests.rs b/core/parser/src/parser/statement/declaration/hoistable/generator_decl/tests.rs index 69a47ed86b..b8e0134161 100644 --- a/core/parser/src/parser/statement/declaration/hoistable/generator_decl/tests.rs +++ b/core/parser/src/parser/statement/declaration/hoistable/generator_decl/tests.rs @@ -1,6 +1,6 @@ use crate::parser::tests::check_script_parser; use boa_ast::{ - function::{FormalParameterList, FunctionBody, Generator}, + function::{FormalParameterList, FunctionBody, GeneratorDeclaration}, Declaration, }; use boa_interner::Interner; @@ -11,11 +11,10 @@ fn generator_function_declaration() { let interner = &mut Interner::default(); check_script_parser( "function* gen() {}", - vec![Declaration::Generator(Generator::new( - Some(interner.get_or_intern_static("gen", utf16!("gen")).into()), + vec![Declaration::GeneratorDeclaration(GeneratorDeclaration::new( + interner.get_or_intern_static("gen", utf16!("gen")).into(), FormalParameterList::default(), FunctionBody::default(), - true, )) .into()], interner, diff --git a/core/parser/src/parser/statement/declaration/lexical.rs b/core/parser/src/parser/statement/declaration/lexical.rs index 279c5e2738..1e999b29f0 100644 --- a/core/parser/src/parser/statement/declaration/lexical.rs +++ b/core/parser/src/parser/statement/declaration/lexical.rs @@ -312,7 +312,7 @@ where .is_some() { Some( - Initializer::new(None, self.allow_in, self.allow_yield, self.allow_await) + Initializer::new(self.allow_in, self.allow_yield, self.allow_await) .parse(cursor, interner)?, ) } else { @@ -340,7 +340,7 @@ where .is_some() { Some( - Initializer::new(None, self.allow_in, self.allow_yield, self.allow_await) + Initializer::new(self.allow_in, self.allow_yield, self.allow_await) .parse(cursor, interner)?, ) } else { @@ -374,15 +374,11 @@ where .filter(|t| *t.kind() == TokenKind::Punctuator(Punctuator::Assign)) .is_some() { - Some( - Initializer::new( - Some(ident), - self.allow_in, - self.allow_yield, - self.allow_await, - ) - .parse(cursor, interner)?, - ) + let mut init = + Initializer::new(self.allow_in, self.allow_yield, self.allow_await) + .parse(cursor, interner)?; + init.set_anonymous_function_definition_name(&ident); + Some(init) } else { None }; diff --git a/core/parser/src/parser/statement/expression/mod.rs b/core/parser/src/parser/statement/expression/mod.rs index c932c4910d..bb6d345f89 100644 --- a/core/parser/src/parser/statement/expression/mod.rs +++ b/core/parser/src/parser/statement/expression/mod.rs @@ -100,8 +100,8 @@ where _ => {} } - let expr = Expression::new(None, true, self.allow_yield, self.allow_await) - .parse(cursor, interner)?; + let expr = + Expression::new(true, self.allow_yield, self.allow_await).parse(cursor, interner)?; cursor.expect_semicolon("expression statement", interner)?; diff --git a/core/parser/src/parser/statement/if_stm/mod.rs b/core/parser/src/parser/statement/if_stm/mod.rs index 0b94972937..ec083afd51 100644 --- a/core/parser/src/parser/statement/if_stm/mod.rs +++ b/core/parser/src/parser/statement/if_stm/mod.rs @@ -63,8 +63,8 @@ where cursor.expect((Keyword::If, false), "if statement", interner)?; cursor.expect(Punctuator::OpenParen, "if statement", interner)?; - let condition = Expression::new(None, true, self.allow_yield, self.allow_await) - .parse(cursor, interner)?; + let condition = + Expression::new(true, self.allow_yield, self.allow_await).parse(cursor, interner)?; let position = cursor .expect(Punctuator::CloseParen, "if statement", interner)? @@ -83,10 +83,12 @@ where // Source text matched by 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 text. - Block::from(vec![StatementListItem::Declaration(Declaration::Function( - FunctionDeclaration::new(self.allow_yield, self.allow_await, false) - .parse(cursor, interner)?, - ))]) + Block::from(vec![StatementListItem::Declaration( + Declaration::FunctionDeclaration( + FunctionDeclaration::new(self.allow_yield, self.allow_await, false) + .parse(cursor, interner)?, + ), + )]) .into() } _ => Statement::new(self.allow_yield, self.allow_await, self.allow_return) @@ -126,7 +128,7 @@ where // occurrence of FunctionDeclaration[?Yield, ?Await, ~Default] was the sole // StatementListItem of a BlockStatement occupying that position in the source text. Block::from(vec![StatementListItem::Declaration( - Declaration::Function( + Declaration::FunctionDeclaration( FunctionDeclaration::new( self.allow_yield, self.allow_await, diff --git a/core/parser/src/parser/statement/iteration/do_while_statement.rs b/core/parser/src/parser/statement/iteration/do_while_statement.rs index d48805ec6b..09a78d1c02 100644 --- a/core/parser/src/parser/statement/iteration/do_while_statement.rs +++ b/core/parser/src/parser/statement/iteration/do_while_statement.rs @@ -99,8 +99,8 @@ where cursor.expect(Punctuator::OpenParen, "do while statement", interner)?; - let cond = Expression::new(None, true, self.allow_yield, self.allow_await) - .parse(cursor, interner)?; + let cond = + Expression::new(true, self.allow_yield, self.allow_await).parse(cursor, interner)?; cursor.expect(Punctuator::CloseParen, "do while statement", interner)?; diff --git a/core/parser/src/parser/statement/iteration/for_statement.rs b/core/parser/src/parser/statement/iteration/for_statement.rs index 908434f0ea..5c0363b4e8 100644 --- a/core/parser/src/parser/statement/iteration/for_statement.rs +++ b/core/parser/src/parser/statement/iteration/for_statement.rs @@ -144,14 +144,14 @@ where } Some( - Expression::new(None, false, self.allow_yield, self.allow_await) + Expression::new(false, self.allow_yield, self.allow_await) .parse(cursor, interner)? .into(), ) } TokenKind::Punctuator(Punctuator::Semicolon) => None, _ => Some( - Expression::new(None, false, self.allow_yield, self.allow_await) + Expression::new(false, self.allow_yield, self.allow_await) .parse(cursor, interner)? .into(), ), @@ -203,10 +203,10 @@ where cursor.advance(interner); let expr = if in_loop { - Expression::new(None, true, self.allow_yield, self.allow_await) + Expression::new(true, self.allow_yield, self.allow_await) .parse(cursor, interner)? } else { - AssignmentExpression::new(None, true, self.allow_yield, self.allow_await) + AssignmentExpression::new(true, self.allow_yield, self.allow_await) .parse(cursor, interner)? }; @@ -281,7 +281,7 @@ where let cond = if cursor.next_if(Punctuator::Semicolon, interner)?.is_some() { None } else { - let step = Expression::new(None, true, self.allow_yield, self.allow_await) + let step = Expression::new(true, self.allow_yield, self.allow_await) .parse(cursor, interner)?; cursor.expect(Punctuator::Semicolon, "for statement", interner)?; Some(step) @@ -290,7 +290,7 @@ where let step = if cursor.next_if(Punctuator::CloseParen, interner)?.is_some() { None } else { - let step = Expression::new(None, true, self.allow_yield, self.allow_await) + let step = Expression::new(true, self.allow_yield, self.allow_await) .parse(cursor, interner)?; cursor.expect( TokenKind::Punctuator(Punctuator::CloseParen), diff --git a/core/parser/src/parser/statement/iteration/while_statement.rs b/core/parser/src/parser/statement/iteration/while_statement.rs index e6188462e4..cc6bb2302f 100644 --- a/core/parser/src/parser/statement/iteration/while_statement.rs +++ b/core/parser/src/parser/statement/iteration/while_statement.rs @@ -57,8 +57,8 @@ where cursor.expect(Punctuator::OpenParen, "while statement", interner)?; - let cond = Expression::new(None, true, self.allow_yield, self.allow_await) - .parse(cursor, interner)?; + let cond = + Expression::new(true, self.allow_yield, self.allow_await).parse(cursor, interner)?; cursor.expect(Punctuator::CloseParen, "while statement", interner)?; diff --git a/core/parser/src/parser/statement/mod.rs b/core/parser/src/parser/statement/mod.rs index e130486b43..c19e9ec0df 100644 --- a/core/parser/src/parser/statement/mod.rs +++ b/core/parser/src/parser/statement/mod.rs @@ -559,7 +559,6 @@ where match peek_token.kind() { TokenKind::Punctuator(Punctuator::Assign) => { let init = Initializer::new( - None, true, self.allow_yield, self.allow_await, @@ -592,7 +591,6 @@ where match peek_token.kind() { TokenKind::Punctuator(Punctuator::Assign) => { let init = Initializer::new( - None, true, self.allow_yield, self.allow_await, @@ -626,13 +624,13 @@ where if let Some(peek_token) = cursor.peek(0, interner)? { match peek_token.kind() { TokenKind::Punctuator(Punctuator::Assign) => { - let init = Initializer::new( - None, + let mut init = Initializer::new( true, self.allow_yield, self.allow_await, ) .parse(cursor, interner)?; + init.set_anonymous_function_definition_name(&ident); patterns.push(ObjectPatternElement::SingleName { ident, name: property_name, @@ -656,13 +654,10 @@ where .parse(cursor, interner)?; match cursor.peek(0, interner)?.map(Token::kind) { Some(TokenKind::Punctuator(Punctuator::Assign)) => { - let init = Initializer::new( - Some(name), - true, - self.allow_yield, - self.allow_await, - ) - .parse(cursor, interner)?; + let mut init = + Initializer::new(true, self.allow_yield, self.allow_await) + .parse(cursor, interner)?; + init.set_anonymous_function_definition_name(&name); patterns.push(ObjectPatternElement::SingleName { ident: name, name: name.sym().into(), @@ -811,7 +806,7 @@ where match cursor.peek(0, interner).or_abrupt()?.kind() { TokenKind::Punctuator(Punctuator::Assign) => { let default_init = - Initializer::new(None, true, self.allow_yield, self.allow_await) + Initializer::new(true, self.allow_yield, self.allow_await) .parse(cursor, interner)?; patterns.push(ArrayPatternElement::Pattern { pattern: bindings.into(), @@ -835,7 +830,7 @@ where match cursor.peek(0, interner).or_abrupt()?.kind() { TokenKind::Punctuator(Punctuator::Assign) => { let default_init = - Initializer::new(None, true, self.allow_yield, self.allow_await) + Initializer::new(true, self.allow_yield, self.allow_await) .parse(cursor, interner)?; patterns.push(ArrayPatternElement::Pattern { pattern: bindings.into(), @@ -857,16 +852,13 @@ where .parse(cursor, interner)?; match cursor.peek(0, interner).or_abrupt()?.kind() { TokenKind::Punctuator(Punctuator::Assign) => { - let default_init = Initializer::new( - Some(ident), - true, - self.allow_yield, - self.allow_await, - ) - .parse(cursor, interner)?; + let mut init = + Initializer::new(true, self.allow_yield, self.allow_await) + .parse(cursor, interner)?; + init.set_anonymous_function_definition_name(&ident); patterns.push(ArrayPatternElement::SingleName { ident, - default_init: Some(default_init), + default_init: Some(init), }); } _ => { diff --git a/core/parser/src/parser/statement/return_stm/mod.rs b/core/parser/src/parser/statement/return_stm/mod.rs index 83b971d24e..6e8fa00bda 100644 --- a/core/parser/src/parser/statement/return_stm/mod.rs +++ b/core/parser/src/parser/statement/return_stm/mod.rs @@ -57,8 +57,8 @@ where return Ok(Return::new(None)); } - let expr = Expression::new(None, true, self.allow_yield, self.allow_await) - .parse(cursor, interner)?; + let expr = + Expression::new(true, self.allow_yield, self.allow_await).parse(cursor, interner)?; cursor.expect_semicolon("return statement", interner)?; diff --git a/core/parser/src/parser/statement/switch/mod.rs b/core/parser/src/parser/statement/switch/mod.rs index de16fee08b..482be5bbca 100644 --- a/core/parser/src/parser/statement/switch/mod.rs +++ b/core/parser/src/parser/statement/switch/mod.rs @@ -65,8 +65,8 @@ where cursor.expect((Keyword::Switch, false), "switch statement", interner)?; cursor.expect(Punctuator::OpenParen, "switch statement", interner)?; - let condition = Expression::new(None, true, self.allow_yield, self.allow_await) - .parse(cursor, interner)?; + let condition = + Expression::new(true, self.allow_yield, self.allow_await).parse(cursor, interner)?; cursor.expect(Punctuator::CloseParen, "switch statement", interner)?; @@ -162,7 +162,7 @@ where } TokenKind::Keyword((Keyword::Case, false)) => { // Case statement. - let cond = Expression::new(None, true, self.allow_yield, self.allow_await) + let cond = Expression::new(true, self.allow_yield, self.allow_await) .parse(cursor, interner)?; cursor.expect(Punctuator::Colon, "switch case block", interner)?; diff --git a/core/parser/src/parser/statement/throw/mod.rs b/core/parser/src/parser/statement/throw/mod.rs index d39276bc4a..afb67f9db1 100644 --- a/core/parser/src/parser/statement/throw/mod.rs +++ b/core/parser/src/parser/statement/throw/mod.rs @@ -49,8 +49,8 @@ where cursor.peek_expect_no_lineterminator(0, "throw statement", interner)?; - let expr = Expression::new(None, true, self.allow_yield, self.allow_await) - .parse(cursor, interner)?; + let expr = + Expression::new(true, self.allow_yield, self.allow_await).parse(cursor, interner)?; cursor.expect_semicolon("throw statement", interner)?; diff --git a/core/parser/src/parser/statement/variable/mod.rs b/core/parser/src/parser/statement/variable/mod.rs index e1499ff77a..44338b536d 100644 --- a/core/parser/src/parser/statement/variable/mod.rs +++ b/core/parser/src/parser/statement/variable/mod.rs @@ -177,7 +177,7 @@ where .is_some() { Some( - Initializer::new(None, self.allow_in, self.allow_yield, self.allow_await) + Initializer::new(self.allow_in, self.allow_yield, self.allow_await) .parse(cursor, interner)?, ) } else { @@ -196,7 +196,7 @@ where .is_some() { Some( - Initializer::new(None, self.allow_in, self.allow_yield, self.allow_await) + Initializer::new(self.allow_in, self.allow_yield, self.allow_await) .parse(cursor, interner)?, ) } else { @@ -214,15 +214,11 @@ where .filter(|t| *t.kind() == TokenKind::Punctuator(Punctuator::Assign)) .is_some() { - Some( - Initializer::new( - Some(ident), - self.allow_in, - self.allow_yield, - self.allow_await, - ) - .parse(cursor, interner)?, - ) + let mut init = + Initializer::new(self.allow_in, self.allow_yield, self.allow_await) + .parse(cursor, interner)?; + init.set_anonymous_function_definition_name(&ident); + Some(init) } else { None }; diff --git a/core/parser/src/parser/statement/with/mod.rs b/core/parser/src/parser/statement/with/mod.rs index ef6fccdae9..0544557e1a 100644 --- a/core/parser/src/parser/statement/with/mod.rs +++ b/core/parser/src/parser/statement/with/mod.rs @@ -70,8 +70,8 @@ where } cursor.expect(Punctuator::OpenParen, "with statement", interner)?; - let expression = Expression::new(None, true, self.allow_yield, self.allow_await) - .parse(cursor, interner)?; + let expression = + Expression::new(true, self.allow_yield, self.allow_await).parse(cursor, interner)?; let position = cursor .expect(Punctuator::CloseParen, "with statement", interner)? .span() diff --git a/core/parser/src/parser/tests/mod.rs b/core/parser/src/parser/tests/mod.rs index 56ff4bef7e..f248cbf310 100644 --- a/core/parser/src/parser/tests/mod.rs +++ b/core/parser/src/parser/tests/mod.rs @@ -9,7 +9,7 @@ use boa_ast::{ declaration::{Declaration, LexicalDeclaration, VarDeclaration, Variable}, expression::{ access::SimplePropertyAccess, - literal::{Literal, ObjectLiteral}, + literal::{Literal, ObjectLiteral, PropertyDefinition}, operator::{ assign::AssignOp, binary::{ArithmeticOp, BinaryOp, LogicalOp, RelationalOp}, @@ -19,10 +19,9 @@ use boa_ast::{ Call, Identifier, New, Parenthesized, }, function::{ - ArrowFunction, FormalParameter, FormalParameterList, FormalParameterListFlags, Function, - FunctionBody, + ArrowFunction, FormalParameter, FormalParameterList, FormalParameterListFlags, + FunctionBody, FunctionDeclaration, }, - property::PropertyDefinition, statement::{If, Return}, Expression, Script, Statement, StatementList, StatementListItem, }; @@ -123,14 +122,13 @@ fn hoisting() { UpdateTarget::Identifier(Identifier::new(a)), ))) .into(), - Declaration::Function(Function::new_with_binding_identifier( - Some(hello.into()), + Declaration::FunctionDeclaration(FunctionDeclaration::new( + hello.into(), FormalParameterList::default(), FunctionBody::new( vec![Statement::Return(Return::new(Some(Literal::from(10).into()))).into()] .into(), ), - true, )) .into(), ],