mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 05:32:44 +00:00 
			
		
		
		
	LibJS: Add the Set built-in object
This commit is contained in:
		
							parent
							
								
									b17a282b4b
								
							
						
					
					
						commit
						670be04c81
					
				
					 15 changed files with 359 additions and 30 deletions
				
			
		|  | @ -1,31 +1,31 @@ | |||
| set(SOURCES | ||||
|         AST.cpp | ||||
|         Bytecode/ASTCodegen.cpp | ||||
|         Bytecode/BasicBlock.cpp | ||||
|         Bytecode/Generator.cpp | ||||
|         Bytecode/Instruction.cpp | ||||
|         Bytecode/Interpreter.cpp | ||||
|         Bytecode/Op.cpp | ||||
|         Console.cpp | ||||
|         Heap/CellAllocator.cpp | ||||
|         Heap/BlockAllocator.cpp | ||||
|         Heap/Handle.cpp | ||||
|         Heap/HeapBlock.cpp | ||||
|         Heap/Heap.cpp | ||||
|         Interpreter.cpp | ||||
|         Lexer.cpp | ||||
|         MarkupGenerator.cpp | ||||
|         Parser.cpp | ||||
|         Runtime/Array.cpp | ||||
|         Runtime/ArrayBuffer.cpp | ||||
|         Runtime/ArrayBufferConstructor.cpp | ||||
|         Runtime/ArrayBufferPrototype.cpp | ||||
|         Runtime/ArrayConstructor.cpp | ||||
|         Runtime/ArrayIterator.cpp | ||||
|         Runtime/ArrayIteratorPrototype.cpp | ||||
|         Runtime/ArrayPrototype.cpp | ||||
|         Runtime/BigInt.cpp | ||||
|         Runtime/BigIntConstructor.cpp | ||||
|     AST.cpp | ||||
|     Bytecode/ASTCodegen.cpp | ||||
|     Bytecode/BasicBlock.cpp | ||||
|     Bytecode/Generator.cpp | ||||
|     Bytecode/Instruction.cpp | ||||
|     Bytecode/Interpreter.cpp | ||||
|     Bytecode/Op.cpp | ||||
|     Console.cpp | ||||
|     Heap/CellAllocator.cpp | ||||
|     Heap/BlockAllocator.cpp | ||||
|     Heap/Handle.cpp | ||||
|     Heap/HeapBlock.cpp | ||||
|     Heap/Heap.cpp | ||||
|     Interpreter.cpp | ||||
|     Lexer.cpp | ||||
|     MarkupGenerator.cpp | ||||
|     Parser.cpp | ||||
|     Runtime/Array.cpp | ||||
|     Runtime/ArrayBuffer.cpp | ||||
|     Runtime/ArrayBufferConstructor.cpp | ||||
|     Runtime/ArrayBufferPrototype.cpp | ||||
|     Runtime/ArrayConstructor.cpp | ||||
|     Runtime/ArrayIterator.cpp | ||||
|     Runtime/ArrayIteratorPrototype.cpp | ||||
|     Runtime/ArrayPrototype.cpp | ||||
|     Runtime/BigInt.cpp | ||||
|     Runtime/BigIntConstructor.cpp | ||||
|     Runtime/BigIntObject.cpp | ||||
|     Runtime/BigIntPrototype.cpp | ||||
|     Runtime/BooleanConstructor.cpp | ||||
|  | @ -76,6 +76,9 @@ set(SOURCES | |||
|     Runtime/RegExpPrototype.cpp | ||||
|     Runtime/ScopeObject.cpp | ||||
|     Runtime/ScriptFunction.cpp | ||||
|     Runtime/Set.cpp | ||||
|     Runtime/SetConstructor.cpp | ||||
|     Runtime/SetPrototype.cpp | ||||
|     Runtime/Shape.cpp | ||||
|     Runtime/StringConstructor.cpp | ||||
|     Runtime/StringIterator.cpp | ||||
|  |  | |||
|  | @ -37,6 +37,7 @@ | |||
|     __JS_ENUMERATE(Object, object, ObjectPrototype, ObjectConstructor, void)                      \ | ||||
|     __JS_ENUMERATE(Promise, promise, PromisePrototype, PromiseConstructor, void)                  \ | ||||
|     __JS_ENUMERATE(RegExpObject, regexp, RegExpPrototype, RegExpConstructor, void)                \ | ||||
|     __JS_ENUMERATE(Set, set, SetPrototype, SetConstructor, void)                                  \ | ||||
|     __JS_ENUMERATE(StringObject, string, StringPrototype, StringConstructor, void)                \ | ||||
|     __JS_ENUMERATE(SymbolObject, symbol, SymbolPrototype, SymbolConstructor, void) | ||||
| 
 | ||||
|  |  | |||
|  | @ -239,6 +239,7 @@ namespace JS { | |||
|     P(sign)                                  \ | ||||
|     P(sin)                                   \ | ||||
|     P(sinh)                                  \ | ||||
|     P(size)                                  \ | ||||
|     P(slice)                                 \ | ||||
|     P(small)                                 \ | ||||
|     P(some)                                  \ | ||||
|  |  | |||
|  | @ -47,6 +47,8 @@ | |||
| #include <LibJS/Runtime/ReflectObject.h> | ||||
| #include <LibJS/Runtime/RegExpConstructor.h> | ||||
| #include <LibJS/Runtime/RegExpPrototype.h> | ||||
| #include <LibJS/Runtime/SetConstructor.h> | ||||
| #include <LibJS/Runtime/SetPrototype.h> | ||||
| #include <LibJS/Runtime/Shape.h> | ||||
| #include <LibJS/Runtime/StringConstructor.h> | ||||
| #include <LibJS/Runtime/StringIteratorPrototype.h> | ||||
|  | @ -87,7 +89,7 @@ void GlobalObject::initialize_global_object() | |||
|     static_cast<FunctionPrototype*>(m_function_prototype)->initialize(*this); | ||||
|     static_cast<ObjectPrototype*>(m_object_prototype)->initialize(*this); | ||||
| 
 | ||||
|     set_prototype(m_object_prototype); | ||||
|     Object::set_prototype(m_object_prototype); | ||||
| 
 | ||||
| #define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName, ArrayType) \ | ||||
|     if (!m_##snake_name##_prototype)                                                     \ | ||||
|  | @ -137,6 +139,7 @@ void GlobalObject::initialize_global_object() | |||
|     add_constructor(vm.names.Promise, m_promise_constructor, m_promise_prototype); | ||||
|     add_constructor(vm.names.Proxy, m_proxy_constructor, nullptr); | ||||
|     add_constructor(vm.names.RegExp, m_regexp_constructor, m_regexp_prototype); | ||||
|     add_constructor(vm.names.Set, m_set_constructor, m_set_prototype); | ||||
|     add_constructor(vm.names.String, m_string_constructor, m_string_prototype); | ||||
|     add_constructor(vm.names.Symbol, m_symbol_constructor, m_symbol_prototype); | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										37
									
								
								Userland/Libraries/LibJS/Runtime/Set.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								Userland/Libraries/LibJS/Runtime/Set.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,37 @@ | |||
| /*
 | ||||
|  * Copyright (c) 2021, Idan Horowitz <idan.horowitz@serenityos.org> | ||||
|  * | ||||
|  * SPDX-License-Identifier: BSD-2-Clause | ||||
|  */ | ||||
| 
 | ||||
| #include <LibJS/Runtime/Set.h> | ||||
| 
 | ||||
| namespace JS { | ||||
| 
 | ||||
| Set* Set::create(GlobalObject& global_object) | ||||
| { | ||||
|     return global_object.heap().allocate<Set>(global_object, *global_object.set_prototype()); | ||||
| } | ||||
| 
 | ||||
| Set::Set(Object& prototype) | ||||
|     : Object(prototype) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| Set::~Set() | ||||
| { | ||||
| } | ||||
| 
 | ||||
| Set* Set::typed_this(VM& vm, GlobalObject& global_object) | ||||
| { | ||||
|     auto* this_object = vm.this_value(global_object).to_object(global_object); | ||||
|     if (!this_object) | ||||
|         return {}; | ||||
|     if (!is<Set>(this_object)) { | ||||
|         vm.throw_exception<TypeError>(global_object, ErrorType::NotA, "Set"); | ||||
|         return nullptr; | ||||
|     } | ||||
|     return static_cast<Set*>(this_object); | ||||
| } | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										53
									
								
								Userland/Libraries/LibJS/Runtime/Set.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								Userland/Libraries/LibJS/Runtime/Set.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,53 @@ | |||
| /*
 | ||||
|  * Copyright (c) 2021, Idan Horowitz <idan.horowitz@serenityos.org> | ||||
|  * | ||||
|  * SPDX-License-Identifier: BSD-2-Clause | ||||
|  */ | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <AK/HashTable.h> | ||||
| #include <LibJS/Runtime/BigInt.h> | ||||
| #include <LibJS/Runtime/GlobalObject.h> | ||||
| #include <LibJS/Runtime/Object.h> | ||||
| #include <LibJS/Runtime/Value.h> | ||||
| 
 | ||||
| namespace JS { | ||||
| 
 | ||||
| struct ValueTraits : public Traits<Value> { | ||||
|     static unsigned hash(Value value) | ||||
|     { | ||||
|         VERIFY(!value.is_empty()); | ||||
|         if (value.is_string()) | ||||
|             return value.as_string().string().hash(); | ||||
| 
 | ||||
|         if (value.is_bigint()) | ||||
|             return value.as_bigint().big_integer().hash(); | ||||
| 
 | ||||
|         return u64_hash(value.encoded()); // FIXME: Is this the best way to hash pointers, doubles & ints?
 | ||||
|     } | ||||
|     static bool equals(const Value a, const Value b) | ||||
|     { | ||||
|         return same_value_zero(a, b); | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| class Set : public Object { | ||||
|     JS_OBJECT(Set, Object); | ||||
| 
 | ||||
| public: | ||||
|     static Set* create(GlobalObject&); | ||||
| 
 | ||||
|     explicit Set(Object& prototype); | ||||
|     virtual ~Set() override; | ||||
| 
 | ||||
|     static Set* typed_this(VM&, GlobalObject&); | ||||
| 
 | ||||
|     HashTable<Value, ValueTraits> const& values() const { return m_values; }; | ||||
|     HashTable<Value, ValueTraits>& values() { return m_values; }; | ||||
| 
 | ||||
| private: | ||||
|     HashTable<Value, ValueTraits> m_values; // FIXME: Replace with a HashTable that maintains a linked list of insertion order for correct iteration order
 | ||||
| }; | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										71
									
								
								Userland/Libraries/LibJS/Runtime/SetConstructor.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								Userland/Libraries/LibJS/Runtime/SetConstructor.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,71 @@ | |||
| /*
 | ||||
|  * Copyright (c) 2021, Idan Horowitz <idan.horowitz@serenityos.org> | ||||
|  * | ||||
|  * SPDX-License-Identifier: BSD-2-Clause | ||||
|  */ | ||||
| 
 | ||||
| #include <LibJS/Runtime/Error.h> | ||||
| #include <LibJS/Runtime/GlobalObject.h> | ||||
| #include <LibJS/Runtime/IteratorOperations.h> | ||||
| #include <LibJS/Runtime/Set.h> | ||||
| #include <LibJS/Runtime/SetConstructor.h> | ||||
| 
 | ||||
| namespace JS { | ||||
| 
 | ||||
| SetConstructor::SetConstructor(GlobalObject& global_object) | ||||
|     : NativeFunction(vm().names.Set, *global_object.function_prototype()) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| void SetConstructor::initialize(GlobalObject& global_object) | ||||
| { | ||||
|     auto& vm = this->vm(); | ||||
|     NativeFunction::initialize(global_object); | ||||
|     define_property(vm.names.prototype, global_object.set_prototype(), 0); | ||||
|     define_property(vm.names.length, Value(0), Attribute::Configurable); | ||||
| 
 | ||||
|     define_native_property(vm.well_known_symbol_species(), symbol_species_getter, {}, Attribute::Configurable); | ||||
| } | ||||
| 
 | ||||
| SetConstructor::~SetConstructor() | ||||
| { | ||||
| } | ||||
| 
 | ||||
| Value SetConstructor::call() | ||||
| { | ||||
|     auto& vm = this->vm(); | ||||
|     vm.throw_exception<TypeError>(global_object(), ErrorType::ConstructorWithoutNew, vm.names.Set); | ||||
|     return {}; | ||||
| } | ||||
| 
 | ||||
| Value SetConstructor::construct(Function&) | ||||
| { | ||||
|     auto& vm = this->vm(); | ||||
|     if (vm.argument(0).is_nullish()) | ||||
|         return Set::create(global_object()); | ||||
| 
 | ||||
|     auto* set = Set::create(global_object()); | ||||
|     auto adder = set->get(vm.names.add); | ||||
|     if (vm.exception()) | ||||
|         return {}; | ||||
|     if (!adder.is_function()) { | ||||
|         vm.throw_exception<TypeError>(global_object(), ErrorType::NotAFunction, "'add' property of Set"); | ||||
|         return {}; | ||||
|     } | ||||
|     get_iterator_values(global_object(), vm.argument(0), [&](Value iterator_value) { | ||||
|         if (vm.exception()) | ||||
|             return IterationDecision::Break; | ||||
|         (void)vm.call(adder.as_function(), Value(set), iterator_value); | ||||
|         return vm.exception() ? IterationDecision::Break : IterationDecision::Continue; | ||||
|     }); | ||||
|     if (vm.exception()) | ||||
|         return {}; | ||||
|     return set; | ||||
| } | ||||
| 
 | ||||
| JS_DEFINE_NATIVE_GETTER(SetConstructor::symbol_species_getter) | ||||
| { | ||||
|     return vm.this_value(global_object); | ||||
| } | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										30
									
								
								Userland/Libraries/LibJS/Runtime/SetConstructor.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								Userland/Libraries/LibJS/Runtime/SetConstructor.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,30 @@ | |||
| /*
 | ||||
|  * Copyright (c) 2021, Idan Horowitz <idan.horowitz@serenityos.org> | ||||
|  * | ||||
|  * SPDX-License-Identifier: BSD-2-Clause | ||||
|  */ | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <LibJS/Runtime/NativeFunction.h> | ||||
| 
 | ||||
| namespace JS { | ||||
| 
 | ||||
| class SetConstructor final : public NativeFunction { | ||||
|     JS_OBJECT(SetConstructor, NativeFunction); | ||||
| 
 | ||||
| public: | ||||
|     explicit SetConstructor(GlobalObject&); | ||||
|     virtual void initialize(GlobalObject&) override; | ||||
|     virtual ~SetConstructor() override; | ||||
| 
 | ||||
|     virtual Value call() override; | ||||
|     virtual Value construct(Function&) override; | ||||
| 
 | ||||
| private: | ||||
|     virtual bool has_constructor() const override { return true; } | ||||
| 
 | ||||
|     JS_DECLARE_NATIVE_GETTER(symbol_species_getter); | ||||
| }; | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										40
									
								
								Userland/Libraries/LibJS/Runtime/SetPrototype.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								Userland/Libraries/LibJS/Runtime/SetPrototype.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,40 @@ | |||
| /*
 | ||||
|  * Copyright (c) 2021, Idan Horowitz <idan.horowitz@serenityos.org> | ||||
|  * | ||||
|  * SPDX-License-Identifier: BSD-2-Clause | ||||
|  */ | ||||
| 
 | ||||
| #include <AK/HashTable.h> | ||||
| #include <LibJS/Runtime/SetPrototype.h> | ||||
| 
 | ||||
| namespace JS { | ||||
| 
 | ||||
| SetPrototype::SetPrototype(GlobalObject& global_object) | ||||
|     : Set(*global_object.object_prototype()) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| void SetPrototype::initialize(GlobalObject& global_object) | ||||
| { | ||||
|     auto& vm = this->vm(); | ||||
|     Set::initialize(global_object); | ||||
|     u8 attr = Attribute::Writable | Attribute::Configurable; | ||||
| 
 | ||||
|     define_native_property(vm.names.size, size_getter, {}, attr); | ||||
| 
 | ||||
|     define_property(vm.well_known_symbol_to_string_tag(), js_string(global_object.heap(), vm.names.Set), Attribute::Configurable); | ||||
| } | ||||
| 
 | ||||
| SetPrototype::~SetPrototype() | ||||
| { | ||||
| } | ||||
| 
 | ||||
| JS_DEFINE_NATIVE_GETTER(SetPrototype::size_getter) | ||||
| { | ||||
|     auto* set = typed_this(vm, global_object); | ||||
|     if (!set) | ||||
|         return {}; | ||||
|     return Value(set->values().size()); | ||||
| } | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										25
									
								
								Userland/Libraries/LibJS/Runtime/SetPrototype.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								Userland/Libraries/LibJS/Runtime/SetPrototype.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,25 @@ | |||
| /*
 | ||||
|  * Copyright (c) 2021, Idan Horowitz <idan.horowitz@serenityos.org> | ||||
|  * | ||||
|  * SPDX-License-Identifier: BSD-2-Clause | ||||
|  */ | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <LibJS/Runtime/Set.h> | ||||
| 
 | ||||
| namespace JS { | ||||
| 
 | ||||
| class SetPrototype final : public Set { | ||||
|     JS_OBJECT(SetPrototype, Set); | ||||
| 
 | ||||
| public: | ||||
|     SetPrototype(GlobalObject&); | ||||
|     virtual void initialize(GlobalObject&) override; | ||||
|     virtual ~SetPrototype() override; | ||||
| 
 | ||||
| private: | ||||
|     JS_DECLARE_NATIVE_GETTER(size_getter); | ||||
| }; | ||||
| 
 | ||||
| } | ||||
|  | @ -253,6 +253,8 @@ public: | |||
|     i32 as_i32() const; | ||||
|     u32 as_u32() const; | ||||
| 
 | ||||
|     u64 encoded() const { return m_value.encoded; } | ||||
| 
 | ||||
|     String to_string(GlobalObject&, bool legacy_null_to_empty_string = false) const; | ||||
|     PrimitiveString* to_primitive_string(GlobalObject&); | ||||
|     Value to_primitive(GlobalObject&, PreferredType preferred_type = PreferredType::Default) const; | ||||
|  | @ -301,7 +303,9 @@ private: | |||
|         Accessor* as_accessor; | ||||
|         BigInt* as_bigint; | ||||
|         NativeProperty* as_native_property; | ||||
|     } m_value; | ||||
| 
 | ||||
|         u64 encoded; | ||||
|     } m_value { .encoded = 0 }; | ||||
| }; | ||||
| 
 | ||||
| inline Value js_undefined() | ||||
|  |  | |||
							
								
								
									
										31
									
								
								Userland/Libraries/LibJS/Tests/builtins/Set/Set.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								Userland/Libraries/LibJS/Tests/builtins/Set/Set.js
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,31 @@ | |||
| test("constructor properties", () => { | ||||
|     expect(Set).toHaveLength(0); | ||||
|     expect(Set.name).toBe("Set"); | ||||
| }); | ||||
| 
 | ||||
| describe("errors", () => { | ||||
|     test("invalid array iterators", () => { | ||||
|         [-100, Infinity, NaN, {}, 152n].forEach(value => { | ||||
|             expect(() => { | ||||
|                 new Set(value); | ||||
|             }).toThrowWithMessage(TypeError, "is not iterable"); | ||||
|         }); | ||||
|     }); | ||||
|     test("called without new", () => { | ||||
|         expect(() => { | ||||
|             Set(); | ||||
|         }).toThrowWithMessage(TypeError, "Set constructor must be called with 'new'"); | ||||
|     }); | ||||
| }); | ||||
| 
 | ||||
| describe("normal behavior", () => { | ||||
|     test("typeof", () => { | ||||
|         expect(typeof new Set()).toBe("object"); | ||||
|     }); | ||||
| 
 | ||||
|     test("constructor with single array argument", () => { | ||||
|         var a = new Set([0, 1, 2]); | ||||
|         expect(a instanceof Set).toBeTrue(); | ||||
|         expect(a).toHaveSize(3); | ||||
|     }); | ||||
| }); | ||||
|  | @ -97,6 +97,17 @@ class ExpectationError extends Error { | |||
|             }); | ||||
|         } | ||||
| 
 | ||||
|         toHaveSize(size) { | ||||
|             this.__expect( | ||||
|                 typeof this.target.size === "number", | ||||
|                 () => "toHaveSize: target.size not of type number" | ||||
|             ); | ||||
| 
 | ||||
|             this.__doMatcher(() => { | ||||
|                 this.__expect(Object.is(this.target.size, size)); | ||||
|             }); | ||||
|         } | ||||
| 
 | ||||
|         toHaveProperty(property, value) { | ||||
|             this.__doMatcher(() => { | ||||
|                 let object = this.target; | ||||
|  |  | |||
|  | @ -43,7 +43,7 @@ void WindowObject::initialize_global_object() | |||
| { | ||||
|     Base::initialize_global_object(); | ||||
| 
 | ||||
|     set_prototype(&ensure_web_prototype<EventTargetPrototype>("EventTarget")); | ||||
|     Object::set_prototype(&ensure_web_prototype<EventTargetPrototype>("EventTarget")); | ||||
| 
 | ||||
|     define_property("window", this, JS::Attribute::Enumerable); | ||||
|     define_property("frames", this, JS::Attribute::Enumerable); | ||||
|  |  | |||
|  | @ -35,6 +35,7 @@ | |||
| #include <LibJS/Runtime/ProxyObject.h> | ||||
| #include <LibJS/Runtime/RegExpObject.h> | ||||
| #include <LibJS/Runtime/ScriptFunction.h> | ||||
| #include <LibJS/Runtime/Set.h> | ||||
| #include <LibJS/Runtime/Shape.h> | ||||
| #include <LibJS/Runtime/StringObject.h> | ||||
| #include <LibJS/Runtime/TypedArray.h> | ||||
|  | @ -277,6 +278,22 @@ static void print_proxy_object(const JS::Object& object, HashTable<JS::Object*>& | |||
|     print_value(&proxy_object.handler(), seen_objects); | ||||
| } | ||||
| 
 | ||||
| static void print_set(const JS::Object& object, HashTable<JS::Object*>& seen_objects) | ||||
| { | ||||
|     auto& set = static_cast<const JS::Set&>(object); | ||||
|     auto& values = set.values(); | ||||
|     print_type("Set"); | ||||
|     out(" {{"); | ||||
|     bool first = true; | ||||
|     for (auto& value : values) { | ||||
|         print_separator(first); | ||||
|         print_value(value, seen_objects); | ||||
|     } | ||||
|     if (!first) | ||||
|         out(" "); | ||||
|     out("}}"); | ||||
| } | ||||
| 
 | ||||
| static void print_promise(const JS::Object& object, HashTable<JS::Object*>& seen_objects) | ||||
| { | ||||
|     auto& promise = static_cast<const JS::Promise&>(object); | ||||
|  | @ -398,6 +415,8 @@ static void print_value(JS::Value value, HashTable<JS::Object*>& seen_objects) | |||
|             return print_error(object, seen_objects); | ||||
|         if (is<JS::RegExpObject>(object)) | ||||
|             return print_regexp_object(object, seen_objects); | ||||
|         if (is<JS::Set>(object)) | ||||
|             return print_set(object, seen_objects); | ||||
|         if (is<JS::ProxyObject>(object)) | ||||
|             return print_proxy_object(object, seen_objects); | ||||
|         if (is<JS::Promise>(object)) | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Idan Horowitz
						Idan Horowitz