From e7fdb02188154f496485694e90aab0694aa0501b Mon Sep 17 00:00:00 2001 From: raskad <32105367+raskad@users.noreply.github.com> Date: Sat, 9 Apr 2022 02:45:52 +0200 Subject: [PATCH] Allow PropertyNames in descructive object bindings --- boa_engine/src/bytecompiler.rs | 26 ++++++++-- .../src/syntax/ast/node/declaration/mod.rs | 52 +++++++++++++------ .../syntax/ast/node/operator/assign/mod.rs | 4 +- boa_engine/src/syntax/parser/statement/mod.rs | 48 +++++++++++++---- .../syntax/parser/statement/try_stm/tests.rs | 7 ++- 5 files changed, 103 insertions(+), 34 deletions(-) diff --git a/boa_engine/src/bytecompiler.rs b/boa_engine/src/bytecompiler.rs index c3c5a41337e..b79ca8d0298 100644 --- a/boa_engine/src/bytecompiler.rs +++ b/boa_engine/src/bytecompiler.rs @@ -2076,8 +2076,17 @@ impl<'b> ByteCompiler<'b> { default_init, } => { self.emit_opcode(Opcode::Dup); - let index = self.get_or_insert_name(*property_name); - self.emit(Opcode::GetPropertyByName, &[index]); + match property_name { + PropertyName::Literal(name) => { + let index = self.get_or_insert_name(*name); + self.emit(Opcode::GetPropertyByName, &[index]); + } + PropertyName::Computed(node) => { + self.compile_expr(node, true)?; + self.emit_opcode(Opcode::Swap); + self.emit_opcode(Opcode::GetPropertyByValue); + } + } if let Some(init) = default_init { let skip = self.jump_with_custom_opcode(Opcode::JumpIfNotUndefined); @@ -2129,8 +2138,17 @@ impl<'b> ByteCompiler<'b> { default_init, } => { self.emit_opcode(Opcode::Dup); - let index = self.get_or_insert_name(*ident); - self.emit(Opcode::GetPropertyByName, &[index]); + match ident { + PropertyName::Literal(name) => { + let index = self.get_or_insert_name(*name); + self.emit(Opcode::GetPropertyByName, &[index]); + } + PropertyName::Computed(node) => { + self.compile_expr(node, true)?; + self.emit_opcode(Opcode::Swap); + self.emit_opcode(Opcode::GetPropertyByValue); + } + } if let Some(init) = default_init { let skip = self.jump_with_custom_opcode(Opcode::JumpIfNotUndefined); diff --git a/boa_engine/src/syntax/ast/node/declaration/mod.rs b/boa_engine/src/syntax/ast/node/declaration/mod.rs index 37c98eb03da..c668f7d00ea 100644 --- a/boa_engine/src/syntax/ast/node/declaration/mod.rs +++ b/boa_engine/src/syntax/ast/node/declaration/mod.rs @@ -2,6 +2,7 @@ use crate::syntax::ast::node::{ field::{GetConstField, GetField}, join_nodes, + object::PropertyName, statement_list::StatementList, Identifier, Node, }; @@ -497,7 +498,7 @@ pub enum BindingPatternTypeObject { /// [spec2]: https://tc39.es/ecma262/#prod-BindingProperty SingleName { ident: Sym, - property_name: Sym, + property_name: PropertyName, default_init: Option, }, @@ -536,7 +537,7 @@ pub enum BindingPatternTypeObject { /// /// [spec1]: https://tc39.es/ecma262/#prod-BindingProperty BindingPattern { - ident: Sym, + ident: PropertyName, pattern: DeclarationPattern, default_init: Option, }, @@ -551,14 +552,24 @@ impl ToInternedString for BindingPatternTypeObject { property_name, default_init, } => { - let mut buf = if ident == property_name { - format!(" {}", interner.resolve_expect(*ident)) - } else { - format!( - " {} : {}", - interner.resolve_expect(*property_name), - interner.resolve_expect(*ident) - ) + let mut buf = match property_name { + PropertyName::Literal(name) if *name == *ident => { + format!(" {}", interner.resolve_expect(*ident)) + } + PropertyName::Literal(name) => { + format!( + " {} : {}", + interner.resolve_expect(*name), + interner.resolve_expect(*ident) + ) + } + PropertyName::Computed(node) => { + format!( + " [{}] : {}", + node.to_interned_string(interner), + interner.resolve_expect(*ident) + ) + } }; if let Some(ref init) = default_init { buf.push_str(&format!(" = {}", init.to_interned_string(interner))); @@ -581,11 +592,22 @@ impl ToInternedString for BindingPatternTypeObject { pattern, default_init, } => { - let mut buf = format!( - " {} : {}", - interner.resolve_expect(*property_name), - pattern.to_interned_string(interner) - ); + let mut buf = match property_name { + PropertyName::Literal(name) => { + format!( + " {} : {}", + interner.resolve_expect(*name), + pattern.to_interned_string(interner), + ) + } + PropertyName::Computed(node) => { + format!( + " [{}] : {}", + node.to_interned_string(interner), + pattern.to_interned_string(interner), + ) + } + }; if let Some(ref init) = default_init { buf.push_str(&format!(" = {}", init.to_interned_string(interner))); } diff --git a/boa_engine/src/syntax/ast/node/operator/assign/mod.rs b/boa_engine/src/syntax/ast/node/operator/assign/mod.rs index bbe875968cc..59ca9ba33e3 100644 --- a/boa_engine/src/syntax/ast/node/operator/assign/mod.rs +++ b/boa_engine/src/syntax/ast/node/operator/assign/mod.rs @@ -149,7 +149,7 @@ pub(crate) fn object_decl_to_declaration_pattern(object: &Object) -> Option Option BindingIdentifier::new(self.allow_yield, self.allow_await) - .parse(cursor, interner)?, + _ => { + PropertyName::new(self.allow_yield, self.allow_await).parse(cursor, interner)? + } }; - property_names.push(property_name); + if let Some(name) = property_name.prop_name() { + property_names.push(name); + } if let Some(peek_token) = cursor.peek(0, interner)? { match peek_token.kind() { TokenKind::Punctuator(Punctuator::Assign) => { + let name = if let Some(name) = property_name.literal() { + name + } else { + return Err(ParseError::expected( + [":".to_owned()], + peek_token.to_string(interner), + peek_token.span(), + "binding property", + )); + }; + let init = Initializer::new( - Some(property_name), + property_name.prop_name(), self.allow_in, self.allow_yield, self.allow_await, ) .parse(cursor, interner)?; patterns.push(BindingPatternTypeObject::SingleName { - ident: property_name, + ident: name, property_name, default_init: Some(init), }); @@ -844,11 +861,20 @@ where } } _ => { - patterns.push(BindingPatternTypeObject::SingleName { - ident: property_name, - property_name, - default_init: None, - }); + if let Some(name) = property_name.literal() { + patterns.push(BindingPatternTypeObject::SingleName { + ident: name, + property_name, + default_init: None, + }); + } else { + return Err(ParseError::expected( + [":".to_owned()], + peek_token.to_string(interner), + peek_token.span(), + "binding property", + )); + } } } } diff --git a/boa_engine/src/syntax/parser/statement/try_stm/tests.rs b/boa_engine/src/syntax/parser/statement/try_stm/tests.rs index 657bdc8fe83..002660921d3 100644 --- a/boa_engine/src/syntax/parser/statement/try_stm/tests.rs +++ b/boa_engine/src/syntax/parser/statement/try_stm/tests.rs @@ -2,6 +2,7 @@ use crate::syntax::{ ast::{ node::{ declaration::{BindingPatternTypeArray, BindingPatternTypeObject}, + object::PropertyName, Block, Catch, Declaration, DeclarationList, Finally, Try, }, Const, @@ -173,12 +174,14 @@ fn check_inline_with_binding_pattern_object() { vec![ BindingPatternTypeObject::SingleName { ident: a, - property_name: a, + property_name: PropertyName::Literal(a), default_init: None, }, BindingPatternTypeObject::SingleName { ident: interner.get_or_intern_static("c"), - property_name: interner.get_or_intern_static("b"), + property_name: PropertyName::Literal( + interner.get_or_intern_static("b"), + ), default_init: None, }, ],