mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 23:17:45 +00:00
LibJS: Add symbol objects
This commit adds the following classes: SymbolObject, SymbolConstructor, SymbolPrototype, and Symbol. This commit does not introduce any new functionality to the Object class, so they cannot be used as property keys in objects.
This commit is contained in:
parent
b5b08fba92
commit
4ced126704
21 changed files with 819 additions and 3 deletions
|
@ -491,6 +491,8 @@ Value UnaryExpression::execute(Interpreter& interpreter) const
|
||||||
return js_string(interpreter, "object");
|
return js_string(interpreter, "object");
|
||||||
case Value::Type::Boolean:
|
case Value::Type::Boolean:
|
||||||
return js_string(interpreter, "boolean");
|
return js_string(interpreter, "boolean");
|
||||||
|
case Value::Type::Symbol:
|
||||||
|
return js_string(interpreter, "symbol");
|
||||||
default:
|
default:
|
||||||
ASSERT_NOT_REACHED();
|
ASSERT_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,6 +46,10 @@ set(SOURCES
|
||||||
Runtime/StringConstructor.cpp
|
Runtime/StringConstructor.cpp
|
||||||
Runtime/StringObject.cpp
|
Runtime/StringObject.cpp
|
||||||
Runtime/StringPrototype.cpp
|
Runtime/StringPrototype.cpp
|
||||||
|
Runtime/Symbol.cpp
|
||||||
|
Runtime/SymbolConstructor.cpp
|
||||||
|
Runtime/SymbolObject.cpp
|
||||||
|
Runtime/SymbolPrototype.cpp
|
||||||
Runtime/Uint8ClampedArray.cpp
|
Runtime/Uint8ClampedArray.cpp
|
||||||
Runtime/Value.cpp
|
Runtime/Value.cpp
|
||||||
Token.cpp
|
Token.cpp
|
||||||
|
|
|
@ -34,7 +34,8 @@
|
||||||
__JS_ENUMERATE(Function, function, FunctionPrototype, FunctionConstructor) \
|
__JS_ENUMERATE(Function, function, FunctionPrototype, FunctionConstructor) \
|
||||||
__JS_ENUMERATE(NumberObject, number, NumberPrototype, NumberConstructor) \
|
__JS_ENUMERATE(NumberObject, number, NumberPrototype, NumberConstructor) \
|
||||||
__JS_ENUMERATE(Object, object, ObjectPrototype, ObjectConstructor) \
|
__JS_ENUMERATE(Object, object, ObjectPrototype, ObjectConstructor) \
|
||||||
__JS_ENUMERATE(StringObject, string, StringPrototype, StringConstructor)
|
__JS_ENUMERATE(StringObject, string, StringPrototype, StringConstructor) \
|
||||||
|
__JS_ENUMERATE(SymbolObject, symbol, SymbolPrototype, SymbolConstructor)
|
||||||
|
|
||||||
#define JS_ENUMERATE_ERROR_SUBCLASSES \
|
#define JS_ENUMERATE_ERROR_SUBCLASSES \
|
||||||
__JS_ENUMERATE(EvalError, eval_error, EvalErrorPrototype, EvalErrorConstructor) \
|
__JS_ENUMERATE(EvalError, eval_error, EvalErrorPrototype, EvalErrorConstructor) \
|
||||||
|
@ -70,6 +71,7 @@ class Reference;
|
||||||
class ScopeNode;
|
class ScopeNode;
|
||||||
class Shape;
|
class Shape;
|
||||||
class Statement;
|
class Statement;
|
||||||
|
class Symbol;
|
||||||
class Uint8ClampedArray;
|
class Uint8ClampedArray;
|
||||||
class Value;
|
class Value;
|
||||||
enum class DeclarationKind;
|
enum class DeclarationKind;
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
#include <LibJS/Runtime/Object.h>
|
#include <LibJS/Runtime/Object.h>
|
||||||
#include <LibJS/Runtime/Reference.h>
|
#include <LibJS/Runtime/Reference.h>
|
||||||
#include <LibJS/Runtime/Shape.h>
|
#include <LibJS/Runtime/Shape.h>
|
||||||
|
#include <LibJS/Runtime/SymbolObject.h>
|
||||||
#include <LibJS/Runtime/Value.h>
|
#include <LibJS/Runtime/Value.h>
|
||||||
|
|
||||||
namespace JS {
|
namespace JS {
|
||||||
|
@ -195,6 +196,8 @@ void Interpreter::gather_roots(Badge<Heap>, HashTable<Cell*>& roots)
|
||||||
}
|
}
|
||||||
roots.set(call_frame.environment);
|
roots.set(call_frame.environment);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SymbolObject::gather_symbol_roots(roots);
|
||||||
}
|
}
|
||||||
|
|
||||||
Value Interpreter::call(Function& function, Value this_value, Optional<MarkedValueList> arguments)
|
Value Interpreter::call(Function& function, Value this_value, Optional<MarkedValueList> arguments)
|
||||||
|
|
|
@ -54,6 +54,8 @@
|
||||||
#include <LibJS/Runtime/Shape.h>
|
#include <LibJS/Runtime/Shape.h>
|
||||||
#include <LibJS/Runtime/StringConstructor.h>
|
#include <LibJS/Runtime/StringConstructor.h>
|
||||||
#include <LibJS/Runtime/StringPrototype.h>
|
#include <LibJS/Runtime/StringPrototype.h>
|
||||||
|
#include <LibJS/Runtime/SymbolConstructor.h>
|
||||||
|
#include <LibJS/Runtime/SymbolPrototype.h>
|
||||||
#include <LibJS/Runtime/Value.h>
|
#include <LibJS/Runtime/Value.h>
|
||||||
|
|
||||||
namespace JS {
|
namespace JS {
|
||||||
|
@ -102,6 +104,7 @@ void GlobalObject::initialize()
|
||||||
add_constructor("Number", m_number_constructor, *m_number_prototype);
|
add_constructor("Number", m_number_constructor, *m_number_prototype);
|
||||||
add_constructor("Object", m_object_constructor, *m_object_prototype);
|
add_constructor("Object", m_object_constructor, *m_object_prototype);
|
||||||
add_constructor("String", m_string_constructor, *m_string_prototype);
|
add_constructor("String", m_string_constructor, *m_string_prototype);
|
||||||
|
add_constructor("Symbol", m_symbol_constructor, *m_symbol_prototype);
|
||||||
|
|
||||||
#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName) \
|
#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName) \
|
||||||
add_constructor(#ClassName, m_##snake_name##_constructor, *m_##snake_name##_prototype);
|
add_constructor(#ClassName, m_##snake_name##_constructor, *m_##snake_name##_prototype);
|
||||||
|
|
|
@ -89,6 +89,7 @@ public:
|
||||||
virtual bool is_bound_function() const { return false; }
|
virtual bool is_bound_function() const { return false; }
|
||||||
virtual bool is_native_property() const { return false; }
|
virtual bool is_native_property() const { return false; }
|
||||||
virtual bool is_string_object() const { return false; }
|
virtual bool is_string_object() const { return false; }
|
||||||
|
virtual bool is_symbol_object() const { return false; }
|
||||||
|
|
||||||
virtual const char* class_name() const override { return "Object"; }
|
virtual const char* class_name() const override { return "Object"; }
|
||||||
virtual void visit_children(Cell::Visitor&) override;
|
virtual void visit_children(Cell::Visitor&) override;
|
||||||
|
|
53
Libraries/LibJS/Runtime/Symbol.cpp
Normal file
53
Libraries/LibJS/Runtime/Symbol.cpp
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020, Matthew Olsson <matthewcolsson@gmail.com>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <LibJS/Heap/Heap.h>
|
||||||
|
#include <LibJS/Interpreter.h>
|
||||||
|
#include <LibJS/Runtime/Symbol.h>
|
||||||
|
|
||||||
|
namespace JS {
|
||||||
|
|
||||||
|
Symbol::Symbol(String description, bool is_global)
|
||||||
|
: m_description(move(description))
|
||||||
|
, m_is_global(is_global)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Symbol::~Symbol()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Symbol* js_symbol(Heap& heap, String description, bool is_global)
|
||||||
|
{
|
||||||
|
return heap.allocate<Symbol>(move(description), is_global);
|
||||||
|
}
|
||||||
|
|
||||||
|
Symbol* js_symbol(Interpreter& interpreter, String description, bool is_global)
|
||||||
|
{
|
||||||
|
return js_symbol(interpreter.heap(), description, is_global);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
53
Libraries/LibJS/Runtime/Symbol.h
Normal file
53
Libraries/LibJS/Runtime/Symbol.h
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020, Matthew Olsson <matthewcolsson@gmail.com>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <AK/String.h>
|
||||||
|
#include <LibJS/Runtime/Cell.h>
|
||||||
|
|
||||||
|
namespace JS {
|
||||||
|
|
||||||
|
class Symbol final : public Cell {
|
||||||
|
public:
|
||||||
|
Symbol(String, bool);
|
||||||
|
virtual ~Symbol();
|
||||||
|
|
||||||
|
const String& description() const { return m_description; }
|
||||||
|
bool is_global() const { return m_is_global; }
|
||||||
|
const String to_string() const { return String::format("Symbol(%s)", description().characters()); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual const char* class_name() const override { return "Symbol"; }
|
||||||
|
|
||||||
|
const String m_description;
|
||||||
|
const bool m_is_global;
|
||||||
|
};
|
||||||
|
|
||||||
|
Symbol* js_symbol(Heap&, String description, bool is_global);
|
||||||
|
Symbol* js_symbol(Interpreter&, String description, bool is_global);
|
||||||
|
|
||||||
|
}
|
105
Libraries/LibJS/Runtime/SymbolConstructor.cpp
Normal file
105
Libraries/LibJS/Runtime/SymbolConstructor.cpp
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020, Matthew Olsson <matthewcolsson@gmail.com>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <LibJS/Interpreter.h>
|
||||||
|
#include <LibJS/Runtime/Error.h>
|
||||||
|
#include <LibJS/Runtime/GlobalObject.h>
|
||||||
|
#include <LibJS/Runtime/SymbolConstructor.h>
|
||||||
|
#include <LibJS/Runtime/SymbolObject.h>
|
||||||
|
|
||||||
|
namespace JS {
|
||||||
|
|
||||||
|
SymbolConstructor::SymbolConstructor()
|
||||||
|
: NativeFunction("Symbol", *interpreter().global_object().function_prototype())
|
||||||
|
{
|
||||||
|
put("prototype", interpreter().global_object().symbol_prototype(), 0);
|
||||||
|
put("length", Value(0), Attribute::Configurable);
|
||||||
|
|
||||||
|
put_native_function("for", for_, 1, Attribute::Writable | Attribute::Configurable);
|
||||||
|
put_native_function("keyFor", key_for, 1, Attribute::Writable | Attribute::Configurable);
|
||||||
|
|
||||||
|
SymbolObject::initialize_well_known_symbols(interpreter());
|
||||||
|
|
||||||
|
put("iterator", SymbolObject::well_known_iterator(), 0);
|
||||||
|
put("asyncIterator", SymbolObject::well_known_async_terator(), 0);
|
||||||
|
put("match", SymbolObject::well_known_match(), 0);
|
||||||
|
put("matchAll", SymbolObject::well_known_match_all(), 0);
|
||||||
|
put("replace", SymbolObject::well_known_replace(), 0);
|
||||||
|
put("search", SymbolObject::well_known_search(), 0);
|
||||||
|
put("split", SymbolObject::well_known_split(), 0);
|
||||||
|
put("hasInstance", SymbolObject::well_known_has_instance(), 0);
|
||||||
|
put("isConcatSpreadable", SymbolObject::well_known_is_concat_spreadable(), 0);
|
||||||
|
put("unscopables", SymbolObject::well_known_unscopables(), 0);
|
||||||
|
put("species", SymbolObject::well_known_species(), 0);
|
||||||
|
put("toPrimitive", SymbolObject::well_known_to_primtive(), 0);
|
||||||
|
put("toStringTag", SymbolObject::well_known_to_string_tag(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
SymbolConstructor::~SymbolConstructor()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Value SymbolConstructor::call(Interpreter& interpreter)
|
||||||
|
{
|
||||||
|
if (!interpreter.argument_count())
|
||||||
|
return js_symbol(interpreter, "", false);
|
||||||
|
return js_symbol(interpreter, interpreter.argument(0).to_string(interpreter), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
Value SymbolConstructor::construct(Interpreter& interpreter)
|
||||||
|
{
|
||||||
|
interpreter.throw_exception<TypeError>("Symbol is not a constructor");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
Value SymbolConstructor::for_(Interpreter& interpreter)
|
||||||
|
{
|
||||||
|
String description;
|
||||||
|
if (!interpreter.argument_count()) {
|
||||||
|
description = "undefined";
|
||||||
|
} else {
|
||||||
|
description = interpreter.argument(0).to_string(interpreter);
|
||||||
|
}
|
||||||
|
|
||||||
|
return SymbolObject::get_global(interpreter, description);
|
||||||
|
}
|
||||||
|
|
||||||
|
Value SymbolConstructor::key_for(Interpreter& interpreter)
|
||||||
|
{
|
||||||
|
auto argument = interpreter.argument(0);
|
||||||
|
if (!argument.is_symbol()) {
|
||||||
|
interpreter.throw_exception<TypeError>(String::format("%s is not a symbol", argument.to_string_without_side_effects().characters()));
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& symbol = argument.as_symbol();
|
||||||
|
if (symbol.is_global())
|
||||||
|
return js_string(interpreter, symbol.description());
|
||||||
|
|
||||||
|
return js_undefined();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
49
Libraries/LibJS/Runtime/SymbolConstructor.h
Normal file
49
Libraries/LibJS/Runtime/SymbolConstructor.h
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020, Matthew Olsson <matthewcolsson@gmail.com>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <LibJS/Runtime/NativeFunction.h>
|
||||||
|
|
||||||
|
namespace JS {
|
||||||
|
|
||||||
|
class SymbolConstructor final : public NativeFunction {
|
||||||
|
public:
|
||||||
|
SymbolConstructor();
|
||||||
|
virtual ~SymbolConstructor() override;
|
||||||
|
|
||||||
|
virtual Value call(Interpreter&) override;
|
||||||
|
virtual Value construct(Interpreter&) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual bool has_constructor() const override { return true; }
|
||||||
|
virtual const char* class_name() const override { return "SymbolConstructor"; }
|
||||||
|
|
||||||
|
static Value for_(Interpreter&);
|
||||||
|
static Value key_for(Interpreter&);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
122
Libraries/LibJS/Runtime/SymbolObject.cpp
Normal file
122
Libraries/LibJS/Runtime/SymbolObject.cpp
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020, Matthew Olsson <matthewcolsson@gmail.com>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <LibJS/Heap/Heap.h>
|
||||||
|
#include <LibJS/Interpreter.h>
|
||||||
|
#include <LibJS/Runtime/GlobalObject.h>
|
||||||
|
#include <LibJS/Runtime/Symbol.h>
|
||||||
|
#include <LibJS/Runtime/SymbolObject.h>
|
||||||
|
#include <LibJS/Runtime/SymbolPrototype.h>
|
||||||
|
#include <LibJS/Runtime/Value.h>
|
||||||
|
|
||||||
|
namespace JS {
|
||||||
|
|
||||||
|
HashMap<String, Value> SymbolObject::s_global_symbol_map;
|
||||||
|
|
||||||
|
Value SymbolObject::s_well_known_iterator;
|
||||||
|
Value SymbolObject::s_well_known_async_terator;
|
||||||
|
Value SymbolObject::s_well_known_match;
|
||||||
|
Value SymbolObject::s_well_known_match_all;
|
||||||
|
Value SymbolObject::s_well_known_replace;
|
||||||
|
Value SymbolObject::s_well_known_search;
|
||||||
|
Value SymbolObject::s_well_known_split;
|
||||||
|
Value SymbolObject::s_well_known_has_instance;
|
||||||
|
Value SymbolObject::s_well_known_is_concat_spreadable;
|
||||||
|
Value SymbolObject::s_well_known_unscopables;
|
||||||
|
Value SymbolObject::s_well_known_species;
|
||||||
|
Value SymbolObject::s_well_known_to_primtive;
|
||||||
|
Value SymbolObject::s_well_known_to_string_tag;
|
||||||
|
|
||||||
|
SymbolObject* SymbolObject::create(GlobalObject& global_object, Symbol& primitive_symbol)
|
||||||
|
{
|
||||||
|
return global_object.heap().allocate<SymbolObject>(primitive_symbol, *global_object.symbol_prototype());
|
||||||
|
}
|
||||||
|
|
||||||
|
SymbolObject::SymbolObject(Symbol& symbol, Object& prototype)
|
||||||
|
: Object(&prototype)
|
||||||
|
, m_symbol(symbol)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
SymbolObject::~SymbolObject()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Value SymbolObject::get_global(Interpreter& interpreter, String description)
|
||||||
|
{
|
||||||
|
auto global_symbol = s_global_symbol_map.get(description);
|
||||||
|
if (global_symbol.has_value())
|
||||||
|
return global_symbol.value();
|
||||||
|
|
||||||
|
auto symbol = js_symbol(interpreter, description, true);
|
||||||
|
s_global_symbol_map.set(description, symbol);
|
||||||
|
return Value(symbol);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SymbolObject::initialize_well_known_symbols(Interpreter& interpreter)
|
||||||
|
{
|
||||||
|
SymbolObject::s_well_known_iterator = Value(js_symbol(interpreter, "Symbol.iterator", false));
|
||||||
|
SymbolObject::s_well_known_async_terator = Value(js_symbol(interpreter, "Symbol.asyncIterator", false));
|
||||||
|
SymbolObject::s_well_known_match = Value(js_symbol(interpreter, "Symbol.match", false));
|
||||||
|
SymbolObject::s_well_known_match_all = Value(js_symbol(interpreter, "Symbol.matchAll", false));
|
||||||
|
SymbolObject::s_well_known_replace = Value(js_symbol(interpreter, "Symbol.replace", false));
|
||||||
|
SymbolObject::s_well_known_search = Value(js_symbol(interpreter, "Symbol.search", false));
|
||||||
|
SymbolObject::s_well_known_split = Value(js_symbol(interpreter, "Symbol.split", false));
|
||||||
|
SymbolObject::s_well_known_has_instance = Value(js_symbol(interpreter, "Symbol.hasInstance", false));
|
||||||
|
SymbolObject::s_well_known_is_concat_spreadable = Value(js_symbol(interpreter, "Symbol.isConcatSpreadable", false));
|
||||||
|
SymbolObject::s_well_known_unscopables = Value(js_symbol(interpreter, "Symbol.unscopables", false));
|
||||||
|
SymbolObject::s_well_known_species = Value(js_symbol(interpreter, "Symbol.species", false));
|
||||||
|
SymbolObject::s_well_known_to_primtive = Value(js_symbol(interpreter, "Symbol.toPrimitive", false));
|
||||||
|
SymbolObject::s_well_known_to_string_tag = Value(js_symbol(interpreter, "Symbol.toStringTag", false));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SymbolObject::gather_symbol_roots(HashTable<Cell*>& roots)
|
||||||
|
{
|
||||||
|
for (auto& global_symbol : s_global_symbol_map)
|
||||||
|
roots.set(&global_symbol.value.as_symbol());
|
||||||
|
|
||||||
|
roots.set(&s_well_known_iterator.as_symbol());
|
||||||
|
roots.set(&s_well_known_async_terator.as_symbol());
|
||||||
|
roots.set(&s_well_known_match.as_symbol());
|
||||||
|
roots.set(&s_well_known_match_all.as_symbol());
|
||||||
|
roots.set(&s_well_known_replace.as_symbol());
|
||||||
|
roots.set(&s_well_known_search.as_symbol());
|
||||||
|
roots.set(&s_well_known_split.as_symbol());
|
||||||
|
roots.set(&s_well_known_has_instance.as_symbol());
|
||||||
|
roots.set(&s_well_known_is_concat_spreadable.as_symbol());
|
||||||
|
roots.set(&s_well_known_unscopables.as_symbol());
|
||||||
|
roots.set(&s_well_known_species.as_symbol());
|
||||||
|
roots.set(&s_well_known_to_primtive.as_symbol());
|
||||||
|
roots.set(&s_well_known_to_string_tag.as_symbol());
|
||||||
|
}
|
||||||
|
|
||||||
|
void SymbolObject::visit_children(Cell::Visitor& visitor)
|
||||||
|
{
|
||||||
|
Object::visit_children(visitor);
|
||||||
|
visitor.visit(&m_symbol);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
95
Libraries/LibJS/Runtime/SymbolObject.h
Normal file
95
Libraries/LibJS/Runtime/SymbolObject.h
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020, Matthew Olsson <matthewcolsson@gmail.com>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <LibJS/Runtime/Object.h>
|
||||||
|
#include <LibJS/Runtime/Symbol.h>
|
||||||
|
|
||||||
|
namespace JS {
|
||||||
|
|
||||||
|
class SymbolObject : public Object {
|
||||||
|
public:
|
||||||
|
static SymbolObject* create(GlobalObject&, Symbol&);
|
||||||
|
|
||||||
|
SymbolObject(Symbol&, Object& prototype);
|
||||||
|
virtual ~SymbolObject() override;
|
||||||
|
|
||||||
|
Symbol& primitive_symbol() { return m_symbol; }
|
||||||
|
const Symbol& primitive_symbol() const { return m_symbol; }
|
||||||
|
|
||||||
|
const String& description() const { return m_symbol.description(); }
|
||||||
|
bool is_global() const { return m_symbol.is_global(); }
|
||||||
|
|
||||||
|
static Value get_global(Interpreter&, String description);
|
||||||
|
|
||||||
|
virtual Value value_of() const override
|
||||||
|
{
|
||||||
|
return Value(&m_symbol);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void initialize_well_known_symbols(Interpreter&);
|
||||||
|
static void gather_symbol_roots(HashTable<Cell*>& roots);
|
||||||
|
|
||||||
|
static Value well_known_iterator() { return s_well_known_iterator; };
|
||||||
|
static Value well_known_async_terator() { return s_well_known_async_terator; };
|
||||||
|
static Value well_known_match() { return s_well_known_match; };
|
||||||
|
static Value well_known_match_all() { return s_well_known_match_all; };
|
||||||
|
static Value well_known_replace() { return s_well_known_replace; };
|
||||||
|
static Value well_known_search() { return s_well_known_search; };
|
||||||
|
static Value well_known_split() { return s_well_known_split; };
|
||||||
|
static Value well_known_has_instance() { return s_well_known_has_instance; };
|
||||||
|
static Value well_known_is_concat_spreadable() { return s_well_known_is_concat_spreadable; };
|
||||||
|
static Value well_known_unscopables() { return s_well_known_unscopables; };
|
||||||
|
static Value well_known_species() { return s_well_known_species; };
|
||||||
|
static Value well_known_to_primtive() { return s_well_known_to_primtive; };
|
||||||
|
static Value well_known_to_string_tag() { return s_well_known_to_string_tag; };
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual void visit_children(Visitor&) override;
|
||||||
|
virtual const char* class_name() const override { return "SymbolObject"; }
|
||||||
|
virtual bool is_symbol_object() const override { return true; }
|
||||||
|
|
||||||
|
Symbol& m_symbol;
|
||||||
|
|
||||||
|
static HashMap<String, Value> s_global_symbol_map;
|
||||||
|
|
||||||
|
static Value s_well_known_iterator;
|
||||||
|
static Value s_well_known_async_terator;
|
||||||
|
static Value s_well_known_match;
|
||||||
|
static Value s_well_known_match_all;
|
||||||
|
static Value s_well_known_replace;
|
||||||
|
static Value s_well_known_search;
|
||||||
|
static Value s_well_known_split;
|
||||||
|
static Value s_well_known_has_instance;
|
||||||
|
static Value s_well_known_is_concat_spreadable;
|
||||||
|
static Value s_well_known_unscopables;
|
||||||
|
static Value s_well_known_species;
|
||||||
|
static Value s_well_known_to_primtive;
|
||||||
|
static Value s_well_known_to_string_tag;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
98
Libraries/LibJS/Runtime/SymbolPrototype.cpp
Normal file
98
Libraries/LibJS/Runtime/SymbolPrototype.cpp
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020, Matthew Olsson <matthewcolsson@gmail.com>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <AK/Function.h>
|
||||||
|
#include <AK/StringBuilder.h>
|
||||||
|
#include <LibJS/Heap/Heap.h>
|
||||||
|
#include <LibJS/Interpreter.h>
|
||||||
|
#include <LibJS/Runtime/Error.h>
|
||||||
|
#include <LibJS/Runtime/GlobalObject.h>
|
||||||
|
#include <LibJS/Runtime/Object.h>
|
||||||
|
#include <LibJS/Runtime/PrimitiveString.h>
|
||||||
|
#include <LibJS/Runtime/SymbolObject.h>
|
||||||
|
#include <LibJS/Runtime/SymbolPrototype.h>
|
||||||
|
#include <LibJS/Runtime/Value.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
namespace JS {
|
||||||
|
|
||||||
|
SymbolPrototype::SymbolPrototype()
|
||||||
|
: Object(interpreter().global_object().object_prototype())
|
||||||
|
{
|
||||||
|
// FIXME: description has no setter, eventually remove
|
||||||
|
put_native_property("description", description_getter, description_setter, Attribute::Configurable);
|
||||||
|
|
||||||
|
put_native_function("toString", to_string, 0, Attribute::Writable | Attribute::Configurable);
|
||||||
|
put_native_function("valueOf", value_of, 0, Attribute::Writable | Attribute::Configurable);
|
||||||
|
}
|
||||||
|
|
||||||
|
SymbolPrototype::~SymbolPrototype()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static SymbolObject* this_symbol_from_interpreter(Interpreter& interpreter)
|
||||||
|
{
|
||||||
|
auto* this_object = interpreter.this_value().to_object(interpreter.heap());
|
||||||
|
if (!this_object)
|
||||||
|
return nullptr;
|
||||||
|
if (!this_object->is_symbol_object()) {
|
||||||
|
interpreter.throw_exception<TypeError>("object must be of type Symbol");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return static_cast<SymbolObject*>(this_object);
|
||||||
|
}
|
||||||
|
|
||||||
|
Value SymbolPrototype::description_getter(Interpreter& interpreter)
|
||||||
|
{
|
||||||
|
auto* this_object = this_symbol_from_interpreter(interpreter);
|
||||||
|
if (!this_object)
|
||||||
|
return {};
|
||||||
|
return js_string(interpreter, this_object->description());
|
||||||
|
}
|
||||||
|
|
||||||
|
void SymbolPrototype::description_setter(Interpreter&, Value)
|
||||||
|
{
|
||||||
|
// No-op, remove eventually
|
||||||
|
}
|
||||||
|
|
||||||
|
Value SymbolPrototype::to_string(Interpreter& interpreter)
|
||||||
|
{
|
||||||
|
auto* this_object = this_symbol_from_interpreter(interpreter);
|
||||||
|
if (!this_object)
|
||||||
|
return {};
|
||||||
|
auto string = this_object->primitive_symbol().to_string();
|
||||||
|
return js_string(interpreter, move(string));
|
||||||
|
}
|
||||||
|
|
||||||
|
Value SymbolPrototype::value_of(Interpreter& interpreter)
|
||||||
|
{
|
||||||
|
auto* this_object = this_symbol_from_interpreter(interpreter);
|
||||||
|
if (!this_object)
|
||||||
|
return {};
|
||||||
|
return this_object->value_of();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
48
Libraries/LibJS/Runtime/SymbolPrototype.h
Normal file
48
Libraries/LibJS/Runtime/SymbolPrototype.h
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020, Matthew Olsson <matthewcolsson@gmail.com>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <LibJS/Runtime/Object.h>
|
||||||
|
|
||||||
|
namespace JS {
|
||||||
|
|
||||||
|
class SymbolPrototype final : public Object {
|
||||||
|
public:
|
||||||
|
SymbolPrototype();
|
||||||
|
virtual ~SymbolPrototype() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual const char* class_name() const override { return "SymbolPrototype"; }
|
||||||
|
|
||||||
|
static Value description_getter(Interpreter&);
|
||||||
|
static void description_setter(Interpreter&, Value);
|
||||||
|
|
||||||
|
static Value to_string(Interpreter&);
|
||||||
|
static Value value_of(Interpreter&);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -36,7 +36,9 @@
|
||||||
#include <LibJS/Runtime/NumberObject.h>
|
#include <LibJS/Runtime/NumberObject.h>
|
||||||
#include <LibJS/Runtime/Object.h>
|
#include <LibJS/Runtime/Object.h>
|
||||||
#include <LibJS/Runtime/PrimitiveString.h>
|
#include <LibJS/Runtime/PrimitiveString.h>
|
||||||
|
#include <LibJS/Runtime/Symbol.h>
|
||||||
#include <LibJS/Runtime/StringObject.h>
|
#include <LibJS/Runtime/StringObject.h>
|
||||||
|
#include <LibJS/Runtime/SymbolObject.h>
|
||||||
#include <LibJS/Runtime/Value.h>
|
#include <LibJS/Runtime/Value.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
|
@ -87,6 +89,9 @@ String Value::to_string_without_side_effects() const
|
||||||
if (is_string())
|
if (is_string())
|
||||||
return m_value.as_string->string();
|
return m_value.as_string->string();
|
||||||
|
|
||||||
|
if (is_symbol())
|
||||||
|
return as_symbol().to_string();
|
||||||
|
|
||||||
ASSERT(is_object());
|
ASSERT(is_object());
|
||||||
return String::format("[object %s]", as_object().class_name());
|
return String::format("[object %s]", as_object().class_name());
|
||||||
}
|
}
|
||||||
|
@ -124,6 +129,11 @@ String Value::to_string(Interpreter& interpreter) const
|
||||||
return String::format("%.4f", as_double());
|
return String::format("%.4f", as_double());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (is_symbol()) {
|
||||||
|
interpreter.throw_exception<TypeError>("Can't convert symbol to string");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
if (is_object()) {
|
if (is_object()) {
|
||||||
auto primitive_value = as_object().to_primitive(Object::PreferredType::String);
|
auto primitive_value = as_object().to_primitive(Object::PreferredType::String);
|
||||||
// FIXME: Maybe we should pass in the Interpreter& and call interpreter.exception() instead?
|
// FIXME: Maybe we should pass in the Interpreter& and call interpreter.exception() instead?
|
||||||
|
@ -152,6 +162,7 @@ bool Value::to_boolean() const
|
||||||
case Type::String:
|
case Type::String:
|
||||||
return !as_string().string().is_empty();
|
return !as_string().string().is_empty();
|
||||||
case Type::Object:
|
case Type::Object:
|
||||||
|
case Type::Symbol:
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
ASSERT_NOT_REACHED();
|
ASSERT_NOT_REACHED();
|
||||||
|
@ -173,6 +184,9 @@ Object* Value::to_object(Heap& heap) const
|
||||||
if (is_string())
|
if (is_string())
|
||||||
return StringObject::create(heap.interpreter().global_object(), *m_value.as_string);
|
return StringObject::create(heap.interpreter().global_object(), *m_value.as_string);
|
||||||
|
|
||||||
|
if (is_symbol())
|
||||||
|
return SymbolObject::create(heap.interpreter().global_object(), *m_value.as_symbol);
|
||||||
|
|
||||||
if (is_number())
|
if (is_number())
|
||||||
return NumberObject::create(heap.interpreter().global_object(), m_value.as_double);
|
return NumberObject::create(heap.interpreter().global_object(), m_value.as_double);
|
||||||
|
|
||||||
|
@ -216,6 +230,9 @@ Value Value::to_number() const
|
||||||
return js_nan();
|
return js_nan();
|
||||||
return Value(parsed_double);
|
return Value(parsed_double);
|
||||||
}
|
}
|
||||||
|
case Type::Symbol:
|
||||||
|
// FIXME: Get access to the interpreter and throw a TypeError
|
||||||
|
ASSERT_NOT_REACHED();
|
||||||
case Type::Object:
|
case Type::Object:
|
||||||
return m_value.as_object->to_primitive(Object::PreferredType::Number).to_number();
|
return m_value.as_object->to_primitive(Object::PreferredType::Number).to_number();
|
||||||
}
|
}
|
||||||
|
@ -473,6 +490,8 @@ bool same_value_non_numeric(Interpreter&, Value lhs, Value rhs)
|
||||||
return true;
|
return true;
|
||||||
case Value::Type::String:
|
case Value::Type::String:
|
||||||
return lhs.as_string().string() == rhs.as_string().string();
|
return lhs.as_string().string() == rhs.as_string().string();
|
||||||
|
case Value::Type::Symbol:
|
||||||
|
return &lhs.as_symbol() == &rhs.as_symbol();
|
||||||
case Value::Type::Boolean:
|
case Value::Type::Boolean:
|
||||||
return lhs.as_bool() == rhs.as_bool();
|
return lhs.as_bool() == rhs.as_bool();
|
||||||
case Value::Type::Object:
|
case Value::Type::Object:
|
||||||
|
@ -520,10 +539,10 @@ bool abstract_eq(Interpreter& interpreter, Value lhs, Value rhs)
|
||||||
if (rhs.is_boolean())
|
if (rhs.is_boolean())
|
||||||
return abstract_eq(interpreter, lhs, rhs.to_number());
|
return abstract_eq(interpreter, lhs, rhs.to_number());
|
||||||
|
|
||||||
if ((lhs.is_string() || lhs.is_number()) && rhs.is_object())
|
if ((lhs.is_string() || lhs.is_number() || lhs.is_symbol()) && rhs.is_object())
|
||||||
return abstract_eq(interpreter, lhs, rhs.to_primitive(interpreter));
|
return abstract_eq(interpreter, lhs, rhs.to_primitive(interpreter));
|
||||||
|
|
||||||
if (lhs.is_object() && (rhs.is_string() || rhs.is_number()))
|
if (lhs.is_object() && (rhs.is_string() || rhs.is_number() || rhs.is_symbol()))
|
||||||
return abstract_eq(interpreter, lhs.to_primitive(interpreter), rhs);
|
return abstract_eq(interpreter, lhs.to_primitive(interpreter), rhs);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
#include <AK/Forward.h>
|
#include <AK/Forward.h>
|
||||||
#include <AK/LogStream.h>
|
#include <AK/LogStream.h>
|
||||||
#include <LibJS/Forward.h>
|
#include <LibJS/Forward.h>
|
||||||
|
#include <LibJS/Runtime/Symbol.h>
|
||||||
|
|
||||||
namespace JS {
|
namespace JS {
|
||||||
|
|
||||||
|
@ -43,6 +44,7 @@ public:
|
||||||
String,
|
String,
|
||||||
Object,
|
Object,
|
||||||
Boolean,
|
Boolean,
|
||||||
|
Symbol,
|
||||||
};
|
};
|
||||||
|
|
||||||
bool is_empty() const { return m_type == Type::Empty; }
|
bool is_empty() const { return m_type == Type::Empty; }
|
||||||
|
@ -52,6 +54,7 @@ public:
|
||||||
bool is_string() const { return m_type == Type::String; }
|
bool is_string() const { return m_type == Type::String; }
|
||||||
bool is_object() const { return m_type == Type::Object; }
|
bool is_object() const { return m_type == Type::Object; }
|
||||||
bool is_boolean() const { return m_type == Type::Boolean; }
|
bool is_boolean() const { return m_type == Type::Boolean; }
|
||||||
|
bool is_symbol() const { return m_type == Type::Symbol; }
|
||||||
bool is_cell() const { return is_string() || is_object(); }
|
bool is_cell() const { return is_string() || is_object(); }
|
||||||
bool is_array() const;
|
bool is_array() const;
|
||||||
bool is_function() const;
|
bool is_function() const;
|
||||||
|
@ -110,6 +113,12 @@ public:
|
||||||
m_value.as_string = string;
|
m_value.as_string = string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Value(Symbol* symbol)
|
||||||
|
: m_type(Type::Symbol)
|
||||||
|
{
|
||||||
|
m_value.as_symbol = symbol;
|
||||||
|
}
|
||||||
|
|
||||||
explicit Value(Type type)
|
explicit Value(Type type)
|
||||||
: m_type(type)
|
: m_type(type)
|
||||||
{
|
{
|
||||||
|
@ -153,6 +162,18 @@ public:
|
||||||
return *m_value.as_string;
|
return *m_value.as_string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Symbol& as_symbol()
|
||||||
|
{
|
||||||
|
ASSERT(is_symbol());
|
||||||
|
return *m_value.as_symbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Symbol& as_symbol() const
|
||||||
|
{
|
||||||
|
ASSERT(is_symbol());
|
||||||
|
return *m_value.as_symbol;
|
||||||
|
}
|
||||||
|
|
||||||
Cell* as_cell()
|
Cell* as_cell()
|
||||||
{
|
{
|
||||||
ASSERT(is_cell());
|
ASSERT(is_cell());
|
||||||
|
@ -188,6 +209,7 @@ private:
|
||||||
bool as_bool;
|
bool as_bool;
|
||||||
double as_double;
|
double as_double;
|
||||||
PrimitiveString* as_string;
|
PrimitiveString* as_string;
|
||||||
|
Symbol* as_symbol;
|
||||||
Object* as_object;
|
Object* as_object;
|
||||||
Cell* as_cell;
|
Cell* as_cell;
|
||||||
} m_value;
|
} m_value;
|
||||||
|
|
30
Libraries/LibJS/Tests/Symbol.for.js
Normal file
30
Libraries/LibJS/Tests/Symbol.for.js
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
load("test-common.js")
|
||||||
|
|
||||||
|
try {
|
||||||
|
const localSym = Symbol("foo");
|
||||||
|
const globalSym = Symbol.for("foo");
|
||||||
|
|
||||||
|
assert(localSym !== globalSym);
|
||||||
|
assert(localSym !== Symbol("foo"));
|
||||||
|
assert(globalSym !== Symbol("foo"));
|
||||||
|
assert(globalSym === Symbol.for("foo"));
|
||||||
|
assert(localSym.toString() === "Symbol(foo)");
|
||||||
|
assert(globalSym.toString() === "Symbol(foo)");
|
||||||
|
|
||||||
|
assert(Symbol.for(1).description === "1");
|
||||||
|
assert(Symbol.for(true).description === "true");
|
||||||
|
assert(Symbol.for({}).description === "[object Object]");
|
||||||
|
assert(Symbol.for().description === "undefined");
|
||||||
|
assert(Symbol.for(null).description === "null");
|
||||||
|
|
||||||
|
assertThrowsError(() => {
|
||||||
|
Symbol.for(Symbol());
|
||||||
|
}, {
|
||||||
|
error: TypeError,
|
||||||
|
message: "Can't convert symbol to string",
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log("PASS");
|
||||||
|
} catch (e) {
|
||||||
|
console.log("FAIL: " + e);
|
||||||
|
}
|
26
Libraries/LibJS/Tests/Symbol.js
Normal file
26
Libraries/LibJS/Tests/Symbol.js
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
load("test-common.js")
|
||||||
|
|
||||||
|
try {
|
||||||
|
const s1 = Symbol("foo");
|
||||||
|
const s2 = Symbol("foo");
|
||||||
|
|
||||||
|
assert(s1 !== s2);
|
||||||
|
assert(s1.description === "foo");
|
||||||
|
assert(s2.description === "foo");
|
||||||
|
|
||||||
|
s1.description = "bar";
|
||||||
|
assert(s1.description === "foo");
|
||||||
|
|
||||||
|
assert(typeof s1 === "symbol");
|
||||||
|
|
||||||
|
assertThrowsError(() => {
|
||||||
|
Symbol(Symbol('foo'));
|
||||||
|
}, {
|
||||||
|
error: TypeError,
|
||||||
|
message: "Can't convert symbol to string"
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log("PASS");
|
||||||
|
} catch (e) {
|
||||||
|
console.log("FAIL: " + e);
|
||||||
|
}
|
31
Libraries/LibJS/Tests/Symbol.keyFor.js
Normal file
31
Libraries/LibJS/Tests/Symbol.keyFor.js
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
load("test-common.js")
|
||||||
|
|
||||||
|
try {
|
||||||
|
const localSym = Symbol("foo");
|
||||||
|
const globalSym = Symbol.for("foo");
|
||||||
|
|
||||||
|
assert(Symbol.keyFor(localSym) === undefined);
|
||||||
|
assert(Symbol.keyFor(globalSym) === "foo");
|
||||||
|
|
||||||
|
const testThrows = (value, str) => {
|
||||||
|
assertThrowsError(() => {
|
||||||
|
Symbol.keyFor(value);
|
||||||
|
}, {
|
||||||
|
error: TypeError,
|
||||||
|
message: str + " is not a symbol",
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
testThrows(1, "1");
|
||||||
|
testThrows(null, "null");
|
||||||
|
testThrows(undefined, "undefined");
|
||||||
|
testThrows([], "[object Array]");
|
||||||
|
testThrows({}, "[object Object]");
|
||||||
|
testThrows(true, "true");
|
||||||
|
testThrows("foobar", "foobar");
|
||||||
|
testThrows(function(){}, "[object ScriptFunction]"); // FIXME: Better function stringification
|
||||||
|
|
||||||
|
console.log("PASS");
|
||||||
|
} catch (e) {
|
||||||
|
console.log("FAIL: " + e);
|
||||||
|
}
|
28
Libraries/LibJS/Tests/Symbol.prototype.toString.js
Normal file
28
Libraries/LibJS/Tests/Symbol.prototype.toString.js
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
load("test-common.js")
|
||||||
|
|
||||||
|
try {
|
||||||
|
const s1 = Symbol("foo");
|
||||||
|
const s2 = Symbol.for("bar");
|
||||||
|
|
||||||
|
assert(s1.toString() === "Symbol(foo)");
|
||||||
|
assert(s2.toString() === "Symbol(bar)");
|
||||||
|
|
||||||
|
assertThrowsError(() => {
|
||||||
|
s1 + "";
|
||||||
|
}, {
|
||||||
|
error: TypeError,
|
||||||
|
message: "Can't convert symbol to string",
|
||||||
|
});
|
||||||
|
|
||||||
|
// FIXME: Uncomment when this doesn't assert
|
||||||
|
// assertThrowsError(() => {
|
||||||
|
// s1 + 1;
|
||||||
|
// }, {
|
||||||
|
// error: TypeError,
|
||||||
|
// message: "Can't convert symbol to number",
|
||||||
|
// });
|
||||||
|
|
||||||
|
console.log("PASS");
|
||||||
|
} catch (e) {
|
||||||
|
console.log("FAIL: " + e);
|
||||||
|
}
|
22
Libraries/LibJS/Tests/Symbol.prototype.valueOf.js
Normal file
22
Libraries/LibJS/Tests/Symbol.prototype.valueOf.js
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
load("test-common.js");
|
||||||
|
|
||||||
|
try {
|
||||||
|
let local = Symbol('foo');
|
||||||
|
let global = Symbol.for('foo');
|
||||||
|
assert(local.valueOf() === local);
|
||||||
|
assert(global.valueOf() === global);
|
||||||
|
|
||||||
|
assert(Symbol.prototype.valueOf.call(local) === local);
|
||||||
|
assert(Symbol.prototype.valueOf.call(global) === global);
|
||||||
|
|
||||||
|
assertThrowsError(() => {
|
||||||
|
Symbol.prototype.valueOf.call("foo");
|
||||||
|
}, {
|
||||||
|
error: TypeError,
|
||||||
|
message: "object must be of type Symbol"
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log("PASS");
|
||||||
|
} catch (err) {
|
||||||
|
console.log("FAIL: " + err);
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue