mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-26 01:20:25 +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
Notes:
sideshowbarker
2024-07-19 06:33:31 +09:00
Author: https://github.com/mattco98 Commit: https://github.com/SerenityOS/serenity/commit/4ced1267045 Pull-request: https://github.com/SerenityOS/serenity/pull/2034 Reviewed-by: https://github.com/awesomekling
21 changed files with 819 additions and 3 deletions
|
@ -491,6 +491,8 @@ Value UnaryExpression::execute(Interpreter& interpreter) const
|
|||
return js_string(interpreter, "object");
|
||||
case Value::Type::Boolean:
|
||||
return js_string(interpreter, "boolean");
|
||||
case Value::Type::Symbol:
|
||||
return js_string(interpreter, "symbol");
|
||||
default:
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
|
|
@ -46,6 +46,10 @@ set(SOURCES
|
|||
Runtime/StringConstructor.cpp
|
||||
Runtime/StringObject.cpp
|
||||
Runtime/StringPrototype.cpp
|
||||
Runtime/Symbol.cpp
|
||||
Runtime/SymbolConstructor.cpp
|
||||
Runtime/SymbolObject.cpp
|
||||
Runtime/SymbolPrototype.cpp
|
||||
Runtime/Uint8ClampedArray.cpp
|
||||
Runtime/Value.cpp
|
||||
Token.cpp
|
||||
|
|
|
@ -34,7 +34,8 @@
|
|||
__JS_ENUMERATE(Function, function, FunctionPrototype, FunctionConstructor) \
|
||||
__JS_ENUMERATE(NumberObject, number, NumberPrototype, NumberConstructor) \
|
||||
__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 \
|
||||
__JS_ENUMERATE(EvalError, eval_error, EvalErrorPrototype, EvalErrorConstructor) \
|
||||
|
@ -70,6 +71,7 @@ class Reference;
|
|||
class ScopeNode;
|
||||
class Shape;
|
||||
class Statement;
|
||||
class Symbol;
|
||||
class Uint8ClampedArray;
|
||||
class Value;
|
||||
enum class DeclarationKind;
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include <LibJS/Runtime/Object.h>
|
||||
#include <LibJS/Runtime/Reference.h>
|
||||
#include <LibJS/Runtime/Shape.h>
|
||||
#include <LibJS/Runtime/SymbolObject.h>
|
||||
#include <LibJS/Runtime/Value.h>
|
||||
|
||||
namespace JS {
|
||||
|
@ -195,6 +196,8 @@ void Interpreter::gather_roots(Badge<Heap>, HashTable<Cell*>& roots)
|
|||
}
|
||||
roots.set(call_frame.environment);
|
||||
}
|
||||
|
||||
SymbolObject::gather_symbol_roots(roots);
|
||||
}
|
||||
|
||||
Value Interpreter::call(Function& function, Value this_value, Optional<MarkedValueList> arguments)
|
||||
|
|
|
@ -54,6 +54,8 @@
|
|||
#include <LibJS/Runtime/Shape.h>
|
||||
#include <LibJS/Runtime/StringConstructor.h>
|
||||
#include <LibJS/Runtime/StringPrototype.h>
|
||||
#include <LibJS/Runtime/SymbolConstructor.h>
|
||||
#include <LibJS/Runtime/SymbolPrototype.h>
|
||||
#include <LibJS/Runtime/Value.h>
|
||||
|
||||
namespace JS {
|
||||
|
@ -102,6 +104,7 @@ void GlobalObject::initialize()
|
|||
add_constructor("Number", m_number_constructor, *m_number_prototype);
|
||||
add_constructor("Object", m_object_constructor, *m_object_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) \
|
||||
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_native_property() 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 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/Object.h>
|
||||
#include <LibJS/Runtime/PrimitiveString.h>
|
||||
#include <LibJS/Runtime/Symbol.h>
|
||||
#include <LibJS/Runtime/StringObject.h>
|
||||
#include <LibJS/Runtime/SymbolObject.h>
|
||||
#include <LibJS/Runtime/Value.h>
|
||||
#include <math.h>
|
||||
|
||||
|
@ -87,6 +89,9 @@ String Value::to_string_without_side_effects() const
|
|||
if (is_string())
|
||||
return m_value.as_string->string();
|
||||
|
||||
if (is_symbol())
|
||||
return as_symbol().to_string();
|
||||
|
||||
ASSERT(is_object());
|
||||
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());
|
||||
}
|
||||
|
||||
if (is_symbol()) {
|
||||
interpreter.throw_exception<TypeError>("Can't convert symbol to string");
|
||||
return {};
|
||||
}
|
||||
|
||||
if (is_object()) {
|
||||
auto primitive_value = as_object().to_primitive(Object::PreferredType::String);
|
||||
// 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:
|
||||
return !as_string().string().is_empty();
|
||||
case Type::Object:
|
||||
case Type::Symbol:
|
||||
return true;
|
||||
default:
|
||||
ASSERT_NOT_REACHED();
|
||||
|
@ -173,6 +184,9 @@ Object* Value::to_object(Heap& heap) const
|
|||
if (is_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())
|
||||
return NumberObject::create(heap.interpreter().global_object(), m_value.as_double);
|
||||
|
||||
|
@ -216,6 +230,9 @@ Value Value::to_number() const
|
|||
return js_nan();
|
||||
return Value(parsed_double);
|
||||
}
|
||||
case Type::Symbol:
|
||||
// FIXME: Get access to the interpreter and throw a TypeError
|
||||
ASSERT_NOT_REACHED();
|
||||
case Type::Object:
|
||||
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;
|
||||
case Value::Type::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:
|
||||
return lhs.as_bool() == rhs.as_bool();
|
||||
case Value::Type::Object:
|
||||
|
@ -520,10 +539,10 @@ bool abstract_eq(Interpreter& interpreter, Value lhs, Value rhs)
|
|||
if (rhs.is_boolean())
|
||||
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));
|
||||
|
||||
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 false;
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include <AK/Forward.h>
|
||||
#include <AK/LogStream.h>
|
||||
#include <LibJS/Forward.h>
|
||||
#include <LibJS/Runtime/Symbol.h>
|
||||
|
||||
namespace JS {
|
||||
|
||||
|
@ -43,6 +44,7 @@ public:
|
|||
String,
|
||||
Object,
|
||||
Boolean,
|
||||
Symbol,
|
||||
};
|
||||
|
||||
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_object() const { return m_type == Type::Object; }
|
||||
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_array() const;
|
||||
bool is_function() const;
|
||||
|
@ -110,6 +113,12 @@ public:
|
|||
m_value.as_string = string;
|
||||
}
|
||||
|
||||
Value(Symbol* symbol)
|
||||
: m_type(Type::Symbol)
|
||||
{
|
||||
m_value.as_symbol = symbol;
|
||||
}
|
||||
|
||||
explicit Value(Type type)
|
||||
: m_type(type)
|
||||
{
|
||||
|
@ -153,6 +162,18 @@ public:
|
|||
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()
|
||||
{
|
||||
ASSERT(is_cell());
|
||||
|
@ -188,6 +209,7 @@ private:
|
|||
bool as_bool;
|
||||
double as_double;
|
||||
PrimitiveString* as_string;
|
||||
Symbol* as_symbol;
|
||||
Object* as_object;
|
||||
Cell* as_cell;
|
||||
} 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…
Reference in a new issue