diff --git a/boa_engine/src/bytecompiler.rs b/boa_engine/src/bytecompiler.rs index 2aca2a1c292..a71c53dee3a 100644 --- a/boa_engine/src/bytecompiler.rs +++ b/boa_engine/src/bytecompiler.rs @@ -559,6 +559,7 @@ impl<'b> ByteCompiler<'b> { Const::Bool(false) => self.emit(Opcode::PushFalse, &[]), Const::Null => self.emit(Opcode::PushNull, &[]), Const::Undefined => self.emit(Opcode::PushUndefined, &[]), + Const::Hole => unreachable!(), } if !use_expr { @@ -921,6 +922,11 @@ impl<'b> ByteCompiler<'b> { self.emit_opcode(Opcode::PopOnReturnAdd); for element in array.as_ref() { + if let Node::Const(Const::Hole) = element { + self.emit_opcode(Opcode::PushHoleToArray); + continue; + } + self.compile_expr(element, true)?; if let Node::Spread(_) = element { self.emit_opcode(Opcode::InitIterator); diff --git a/boa_engine/src/syntax/ast/constant.rs b/boa_engine/src/syntax/ast/constant.rs index b1672492e7c..1504daf8a51 100644 --- a/boa_engine/src/syntax/ast/constant.rs +++ b/boa_engine/src/syntax/ast/constant.rs @@ -111,6 +111,8 @@ pub enum Const { /// [spec]: https://tc39.es/ecma262/#sec-undefined /// [mdn]: https://developer.mozilla.org/en-US/docs/Glossary/undefined Undefined, + + Hole, } impl From for Const { @@ -155,6 +157,7 @@ impl ToInternedString for Const { Self::Bool(v) => v.to_string(), Self::Null => "null".to_owned(), Self::Undefined => "undefined".to_owned(), + Self::Hole => "".to_owned() } } } diff --git a/boa_engine/src/syntax/parser/expression/primary/array_initializer/mod.rs b/boa_engine/src/syntax/parser/expression/primary/array_initializer/mod.rs index b017f779faa..90cffa0f3fa 100644 --- a/boa_engine/src/syntax/parser/expression/primary/array_initializer/mod.rs +++ b/boa_engine/src/syntax/parser/expression/primary/array_initializer/mod.rs @@ -68,7 +68,7 @@ where loop { // TODO: Support all features. while cursor.next_if(Punctuator::Comma, interner)?.is_some() { - elements.push(Node::Const(Const::Undefined)); + elements.push(Node::Const(Const::Hole)); } if cursor diff --git a/boa_engine/src/value/display.rs b/boa_engine/src/value/display.rs index 97f2754bbc9..400cfbdf840 100644 --- a/boa_engine/src/value/display.rs +++ b/boa_engine/src/value/display.rs @@ -134,16 +134,17 @@ pub(crate) fn log_string_from(x: &JsValue, print_internals: bool, print_children .map(|i| { // Introduce recursive call to stringify any objects // which are part of the Array - log_string_from( - v.borrow() - .properties() - .get(&i.into()) - // FIXME: handle accessor descriptors - .and_then(PropertyDescriptor::value) - .unwrap_or(&JsValue::Undefined), - print_internals, - false, - ) + + // FIXME: handle accessor descriptors + if let Some(value) = v.borrow().properties().get(&i.into()).and_then(PropertyDescriptor::value) { + log_string_from( + value, + print_internals, + false, + ) + } else { + String::from("") + } }) .collect::>() .join(", "); diff --git a/boa_engine/src/vm/code_block.rs b/boa_engine/src/vm/code_block.rs index cb45df1c3fd..0854a3dc595 100644 --- a/boa_engine/src/vm/code_block.rs +++ b/boa_engine/src/vm/code_block.rs @@ -317,6 +317,7 @@ impl CodeBlock { | Opcode::PushNewArray | Opcode::PopOnReturnAdd | Opcode::PopOnReturnSub + | Opcode::PushHoleToArray | Opcode::Nop => String::new(), } } diff --git a/boa_engine/src/vm/mod.rs b/boa_engine/src/vm/mod.rs index d8593bbe38d..60e5fd1a147 100644 --- a/boa_engine/src/vm/mod.rs +++ b/boa_engine/src/vm/mod.rs @@ -179,6 +179,18 @@ impl Context { let array = Array::add_to_array_object(&array, &[value], self)?; self.vm.push(array); } + Opcode::PushHoleToArray => { + let array = self.vm.pop(); + let o = array + .as_object() + .expect("should always be an object"); + + let len = o.length_of_array_like(self) + .expect("arrays should always have a 'length' property"); + + o.set("length", len + 1, true, self)?; + self.vm.push(array); + } Opcode::PushIteratorToArray => { let next_function = self.vm.pop(); let iterator = self.vm.pop(); diff --git a/boa_engine/src/vm/opcode.rs b/boa_engine/src/vm/opcode.rs index cd96a17aa1a..cc1c6b5d386 100644 --- a/boa_engine/src/vm/opcode.rs +++ b/boa_engine/src/vm/opcode.rs @@ -145,6 +145,13 @@ pub enum Opcode { /// Stack: array, value **=>** array PushValueToArray, + /// Push a hole to an array. + /// + /// Operands: + /// + /// Stack: array **=>** array + PushHoleToArray, + /// Push all iterator values to an array. /// /// Operands: @@ -909,6 +916,7 @@ impl Opcode { Opcode::PushEmptyObject => "PushEmptyObject", Opcode::PushNewArray => "PushNewArray", Opcode::PushValueToArray => "PushValueToArray", + Opcode::PushHoleToArray => "PushHoleToArray", Opcode::PushIteratorToArray => "PushIteratorToArray", Opcode::Add => "Add", Opcode::Sub => "Sub",