diff --git a/boa/src/exec/mod.rs b/boa/src/exec/mod.rs index 5690de19938..45aa641fa1c 100644 --- a/boa/src/exec/mod.rs +++ b/boa/src/exec/mod.rs @@ -17,7 +17,7 @@ use crate::{ realm::Realm, syntax::ast::{ constant::Const, - node::Node, + node::{MethodDefinitionKind, Node, PropertyDefinition}, op::{AssignOp, BinOp, BitOp, CompOp, LogOp, NumOp, UnaryOp}, }, }; @@ -141,7 +141,7 @@ impl Executor for Interpreter { }; let mut v_args = Vec::with_capacity(args.len()); for arg in args.iter() { - if let Node::UnaryOp(UnaryOp::Spread, ref x) = arg.deref() { + if let Node::Spread(ref x) = arg.deref() { let val = self.run(x)?; let mut vals = self.extract_array_properties(&val).unwrap(); v_args.append(&mut vals); @@ -205,23 +205,39 @@ impl Executor for Interpreter { } Ok(result) } - Node::ObjectDecl(ref map) => { + Node::Object(ref properties) => { let global_val = &self .realm .environment .get_global_object() .expect("Could not get the global object"); let obj = ValueData::new_obj(Some(global_val)); - for (key, val) in map.iter() { - obj.borrow().set_field_slice(&key.clone(), self.run(val)?); + + // TODO: Implement the rest of the property types. + for property in properties { + match property { + PropertyDefinition::Property(key, value) => { + obj.borrow().set_field_slice(&key.clone(), self.run(value)?); + } + PropertyDefinition::MethodDefinition(kind, name, func) => { + if let MethodDefinitionKind::Ordinary = kind { + obj.borrow().set_field_slice(&name.clone(), self.run(func)?); + } else { + // TODO: Implement other types of MethodDefinitionKinds. + unimplemented!("other types of property method definitions."); + } + } + i => unimplemented!("{:?} type of property", i), + } } + Ok(obj) } Node::ArrayDecl(ref arr) => { let array = array::new_array(self)?; let mut elements: Vec = vec![]; for elem in arr.iter() { - if let Node::UnaryOp(UnaryOp::Spread, ref x) = elem.deref() { + if let Node::Spread(ref x) = elem.deref() { let val = self.run(x)?; let mut vals = self.extract_array_properties(&val).unwrap(); elements.append(&mut vals); @@ -286,7 +302,6 @@ impl Executor for Interpreter { !(num_v_a as i32) }) } - UnaryOp::Spread => Gc::new(v_a), // for now we can do nothing but return the value as-is _ => unreachable!(), }) } @@ -356,7 +371,12 @@ impl Executor for Interpreter { } _ => Ok(Gc::new(ValueData::Undefined)), }, - Node::Construct(ref callee, ref args) => { + Node::New(ref call) => { + let (callee, args) = match call.as_ref() { + Node::Call(callee, args) => (callee, args), + _ => unreachable!("Node::New(ref call): 'call' must only be Node::Call type."), + }; + let func_object = self.run(callee)?; let mut v_args = Vec::with_capacity(args.len()); for arg in args.iter() { @@ -538,7 +558,11 @@ impl Executor for Interpreter { Ok(obj) } - _ => unimplemented!(), + Node::Spread(ref node) => { + // TODO: for now we can do nothing but return the value as-is + Ok(Gc::new((*self.run(node)?).clone())) + } + ref i => unimplemented!("{}", i), } } } @@ -591,7 +615,7 @@ impl Interpreter { .environment .initialize_binding(name, expr.clone()); } - Node::UnaryOp(UnaryOp::Spread, ref expr) => { + Node::Spread(ref expr) => { if let Node::Local(ref name) = expr.deref() { let array = array::new_array(self)?; array::add_to_array_object(&array, &arguments_list[i..])?; diff --git a/boa/src/syntax/ast/node.rs b/boa/src/syntax/ast/node.rs index 21e7ec3426d..7d5813fa4b7 100644 --- a/boa/src/syntax/ast/node.rs +++ b/boa/src/syntax/ast/node.rs @@ -3,7 +3,7 @@ use crate::syntax::ast::{ op::{BinOp, Operator, UnaryOp}, }; use gc_derive::{Finalize, Trace}; -use std::{collections::btree_map::BTreeMap, fmt}; +use std::fmt; #[cfg(feature = "serde-ast")] use serde::{Deserialize, Serialize}; @@ -32,8 +32,6 @@ pub enum Node { Const(Const), /// Const declaration. ConstDecl(Vec<(String, Node)>), - /// Construct an object from the function and arguments. - Construct(Box, Vec), /// Continue with an optional label. Continue(Option), /// Create a function with the given name, arguments, and internal AST node. @@ -57,15 +55,13 @@ pub enum Node { Local(String), /// New New(Box), - /// Create an object out of the binary tree given - ObjectDecl(Box>), - /// Object Declaration (replaces ObjectDecl) + /// Object Declaration Object(Vec), /// Return the expression from a function Return(Option>), /// Run blocks whose cases match the expression Switch(Box, Vec<(Node, Vec)>, Option>), - /// Spread operator + /// `...a` - spread an iterable value Spread(Box), // Similar to Block but without the braces StatementList(Vec), @@ -99,18 +95,14 @@ pub enum Node { impl Operator for Node { fn get_assoc(&self) -> bool { match *self { - Node::Construct(_, _) - | Node::UnaryOp(_, _) - | Node::TypeOf(_) - | Node::If(_, _, _) - | Node::Assign(_, _) => false, + Node::UnaryOp(_, _) | Node::TypeOf(_) | Node::If(_, _, _) | Node::Assign(_, _) => false, _ => true, } } fn get_precedence(&self) -> u64 { match self { Node::GetField(_, _) | Node::GetConstField(_, _) => 1, - Node::Call(_, _) | Node::Construct(_, _) => 2, + Node::Call(_, _) => 2, Node::UnaryOp(UnaryOp::IncrementPost, _) | Node::UnaryOp(UnaryOp::IncrementPre, _) | Node::UnaryOp(UnaryOp::DecrementPost, _) @@ -148,12 +140,10 @@ impl Node { Self::ConditionalOp(_, _, _) => write!(f, "Conditional op"), // TODO Self::ForLoop(_, _, _, _) => write!(f, "for loop"), // TODO Self::This => write!(f, "this"), // TODO - Self::Object(_) => write!(f, "object"), // TODO - Self::Spread(_) => write!(f, "spread"), // TODO - Self::New(_) => write!(f, "new"), // TODO Self::Try(_, _, _, _) => write!(f, "try/catch/finally"), // TODO Self::Break(_) => write!(f, "break"), // TODO: add potential value Self::Continue(_) => write!(f, "continue"), // TODO: add potential value + Self::Spread(ref node) => write!(f, "...{}", node), Self::Block(ref block) => { writeln!(f, "{{")?; for node in block.iter() { @@ -197,7 +187,12 @@ impl Node { let arg_strs: Vec = args.iter().map(ToString::to_string).collect(); write!(f, "{})", arg_strs.join(", ")) } - Self::Construct(ref func, ref args) => { + Self::New(ref call) => { + let (func, args) = match call.as_ref() { + Node::Call(func, args) => (func, args), + _ => unreachable!("Node::New(ref call): 'call' must only be Node::Call type."), + }; + write!(f, "new {}", func)?; f.write_str("(")?; let mut first = true; @@ -242,10 +237,24 @@ impl Node { def.display(f, indentation + 1)?; write!(f, "{}}}", indent) } - Self::ObjectDecl(ref map) => { + Self::Object(ref properties) => { f.write_str("{\n")?; - for (key, value) in map.iter() { - write!(f, "{} {}: {},", indent, key, value)?; + for property in properties { + match property { + PropertyDefinition::IdentifierReference(key) => { + write!(f, "{} {},", indent, key)?; + } + PropertyDefinition::Property(key, value) => { + write!(f, "{} {}: {},", indent, key, value)?; + } + PropertyDefinition::SpreadObject(key) => { + write!(f, "{} ...{},", indent, key)?; + } + PropertyDefinition::MethodDefinition(_kind, _key, _node) => { + // TODO: Implement display for PropertyDefinition::MethodDefinition. + unimplemented!("Display for PropertyDefinition::MethodDefinition"); + } + } } f.write_str("}") } diff --git a/boa/src/syntax/ast/op.rs b/boa/src/syntax/ast/op.rs index 10de3f61f26..4c088b77607 100644 --- a/boa/src/syntax/ast/op.rs +++ b/boa/src/syntax/ast/op.rs @@ -75,8 +75,6 @@ pub enum UnaryOp { Tilde, /// `typeof` - Get the type of object TypeOf, - /// `...a` - spread an iterable value - Spread, /// The JavaScript `delete` operator removes a property from an object. /// /// Unlike what common belief suggests, the delete operator has nothing to do with @@ -117,7 +115,6 @@ impl Display for UnaryOp { UnaryOp::Minus => "-", UnaryOp::Not => "!", UnaryOp::Tilde => "~", - UnaryOp::Spread => "...", UnaryOp::Delete => "delete", UnaryOp::TypeOf => "typeof", UnaryOp::Void => "void", diff --git a/boa/src/syntax/parser/mod.rs b/boa/src/syntax/parser/mod.rs index 84527006029..bdb643c8e6f 100644 --- a/boa/src/syntax/parser/mod.rs +++ b/boa/src/syntax/parser/mod.rs @@ -1386,8 +1386,14 @@ impl Parser { return Err(ParseError::AbruptEnd); } } - - args.push(self.read_assignment_expression()?); + if self + .next_if(TokenKind::Punctuator(Punctuator::Spread)) + .is_some() + { + args.push(Node::Spread(Box::new(self.read_assignment_expression()?))); + } else { + args.push(self.read_assignment_expression()?); + } } Ok(args) @@ -1415,13 +1421,15 @@ impl Parser { TokenKind::Identifier(ident) => Ok(Node::Local(ident)), TokenKind::StringLiteral(s) => Ok(Node::Const(Const::String(s))), TokenKind::NumericLiteral(num) => Ok(Node::Const(Const::Num(num))), - TokenKind::RegularExpressionLiteral(body, flags) => Ok(Node::Construct( - Box::new(Node::Local("RegExp".to_string())), - vec![ - Node::Const(Const::String(body)), - Node::Const(Const::String(flags)), - ], - )), + TokenKind::RegularExpressionLiteral(body, flags) => { + Ok(Node::New(Box::new(Node::Call( + Box::new(Node::Local("RegExp".to_string())), + vec![ + Node::Const(Const::String(body)), + Node::Const(Const::String(flags)), + ], + )))) + } _ => Err(ParseError::Unexpected(tok, None)), } }