diff options
Diffstat (limited to 'Libraries/LibJS/Runtime')
24 files changed, 1630 insertions, 0 deletions
diff --git a/Libraries/LibJS/Runtime/Cell.cpp b/Libraries/LibJS/Runtime/Cell.cpp new file mode 100644 index 0000000000..222dd85502 --- /dev/null +++ b/Libraries/LibJS/Runtime/Cell.cpp @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2020, Andreas Kling <kling@serenityos.org> + * 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/LogStream.h> +#include <LibJS/Heap/Heap.h> +#include <LibJS/Heap/HeapBlock.h> +#include <LibJS/Runtime/Cell.h> +#include <LibJS/Runtime/Object.h> +#include <LibJS/Runtime/PrimitiveString.h> +#include <LibJS/Runtime/Value.h> + +namespace JS { + +void Cell::Visitor::visit(Value value) +{ + if (value.is_cell()) + visit(value.as_cell()); +} + +Heap& Cell::heap() const +{ + return HeapBlock::from_cell(this)->heap(); +} + +Interpreter& Cell::interpreter() +{ + return heap().interpreter(); +} + +const LogStream& operator<<(const LogStream& stream, const Cell* cell) +{ + if (!cell) + return stream << "Cell{nullptr}"; + return stream << cell->class_name() << '{' << static_cast<const void*>(cell) << '}'; +} + +} diff --git a/Libraries/LibJS/Runtime/Cell.h b/Libraries/LibJS/Runtime/Cell.h new file mode 100644 index 0000000000..f58ab904f1 --- /dev/null +++ b/Libraries/LibJS/Runtime/Cell.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2020, Andreas Kling <kling@serenityos.org> + * 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/Forward.h> +#include <LibJS/Forward.h> + +namespace JS { + +class Cell { +public: + virtual ~Cell() {} + + bool is_marked() const { return m_mark; } + void set_marked(bool b) { m_mark = b; } + + bool is_live() const { return m_live; } + void set_live(bool b) { m_live = b; } + + virtual const char* class_name() const = 0; + + class Visitor { + public: + virtual void visit(Cell*) = 0; + void visit(Value); + }; + + virtual void visit_children(Visitor&) {} + + Heap& heap() const; + Interpreter& interpreter(); + +private: + bool m_mark { false }; + bool m_live { true }; +}; + +const LogStream& operator<<(const LogStream&, const Cell*); + +} diff --git a/Libraries/LibJS/Runtime/Function.cpp b/Libraries/LibJS/Runtime/Function.cpp new file mode 100644 index 0000000000..5f3d87a25a --- /dev/null +++ b/Libraries/LibJS/Runtime/Function.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2020, Andreas Kling <kling@serenityos.org> + * 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/Runtime/Function.h> +#include <LibJS/Runtime/Value.h> + +namespace JS { + +Function::Function() +{ +} + +Function::~Function() +{ +} + +} diff --git a/Libraries/LibJS/Runtime/Function.h b/Libraries/LibJS/Runtime/Function.h new file mode 100644 index 0000000000..15854d1f1c --- /dev/null +++ b/Libraries/LibJS/Runtime/Function.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2020, Andreas Kling <kling@serenityos.org> + * 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/Object.h> + +namespace JS { + +class Function : public Object { +public: + virtual ~Function(); + + virtual Value call(Interpreter&, Vector<Value>) = 0; + +protected: + Function(); + virtual const char* class_name() const override { return "Function"; } + +private: + virtual bool is_function() const final { return true; } +}; + +} diff --git a/Libraries/LibJS/Runtime/GlobalObject.cpp b/Libraries/LibJS/Runtime/GlobalObject.cpp new file mode 100644 index 0000000000..b87b2f431b --- /dev/null +++ b/Libraries/LibJS/Runtime/GlobalObject.cpp @@ -0,0 +1,31 @@ +#include <AK/LogStream.h> +#include <AK/String.h> +#include <LibJS/Heap/Heap.h> +#include <LibJS/Interpreter.h> +#include <LibJS/Runtime/ConsoleObject.h> +#include <LibJS/Runtime/GlobalObject.h> +#include <LibJS/Runtime/NativeFunction.h> +#include <LibJS/Runtime/Value.h> +#include <stdio.h> + +namespace JS { + +GlobalObject::GlobalObject() +{ + put_native_function("print", [](Object*, Vector<Value> arguments) -> Value { + for (auto& argument : arguments) + printf("%s ", argument.to_string().characters()); + return js_undefined(); + }); + put_native_function("gc", [](Object* this_object, Vector<Value>) -> Value { + dbg() << "Forced garbage collection requested!"; + this_object->heap().collect_garbage(); + return js_undefined(); + }); +} + +GlobalObject::~GlobalObject() +{ +} + +} diff --git a/Libraries/LibJS/Runtime/GlobalObject.h b/Libraries/LibJS/Runtime/GlobalObject.h new file mode 100644 index 0000000000..3aabb4d3e2 --- /dev/null +++ b/Libraries/LibJS/Runtime/GlobalObject.h @@ -0,0 +1,16 @@ +#pragma once + +#include <LibJS/Runtime/Object.h> + +namespace JS { + +class GlobalObject final : public Object { +public: + explicit GlobalObject(); + virtual ~GlobalObject() override; + +private: + virtual const char* class_name() const override { return "GlobalObject"; } +}; + +} diff --git a/Libraries/LibJS/Runtime/NativeFunction.cpp b/Libraries/LibJS/Runtime/NativeFunction.cpp new file mode 100644 index 0000000000..ba26635fda --- /dev/null +++ b/Libraries/LibJS/Runtime/NativeFunction.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2020, Andreas Kling <kling@serenityos.org> + * 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/NativeFunction.h> +#include <LibJS/Runtime/Value.h> + +namespace JS { + +NativeFunction::NativeFunction(AK::Function<Value(Object*, Vector<Value>)> native_function) + : m_native_function(move(native_function)) +{ +} + +NativeFunction::~NativeFunction() +{ +} + +Value NativeFunction::call(Interpreter& interpreter, Vector<Value> arguments) +{ + auto this_value = interpreter.this_value(); + ASSERT(this_value.is_object()); + return m_native_function(this_value.as_object(), move(arguments)); +} + +} diff --git a/Libraries/LibJS/Runtime/NativeFunction.h b/Libraries/LibJS/Runtime/NativeFunction.h new file mode 100644 index 0000000000..5c2a54d8f8 --- /dev/null +++ b/Libraries/LibJS/Runtime/NativeFunction.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2020, Andreas Kling <kling@serenityos.org> + * 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/Function.h> +#include <LibJS/Runtime/Function.h> + +namespace JS { + +class NativeFunction final : public Function { +public: + explicit NativeFunction(AK::Function<Value(Object*, Vector<Value>)>); + virtual ~NativeFunction() override; + + virtual Value call(Interpreter&, Vector<Value>) override; + +private: + virtual bool is_native_function() const override { return true; } + virtual const char* class_name() const override { return "NativeFunction"; } + + AK::Function<Value(Object*, Vector<Value>)> m_native_function; +}; + +} diff --git a/Libraries/LibJS/Runtime/NativeProperty.cpp b/Libraries/LibJS/Runtime/NativeProperty.cpp new file mode 100644 index 0000000000..58ea73b9b3 --- /dev/null +++ b/Libraries/LibJS/Runtime/NativeProperty.cpp @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2020, Andreas Kling <kling@serenityos.org> + * 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/Runtime/NativeProperty.h> +#include <LibJS/Runtime/Value.h> + +namespace JS { + +NativeProperty::NativeProperty(AK::Function<Value(Object*)> getter, AK::Function<void(Object*, Value)> setter) + : m_getter(move(getter)) + , m_setter(move(setter)) +{ +} + +NativeProperty::~NativeProperty() +{ +} + +Value NativeProperty::get(Object* object) const +{ + if (!m_getter) + return js_undefined(); + return m_getter(object); +} + +void NativeProperty::set(Object* object, Value value) +{ + if (!m_setter) + return; + m_setter(object, move(value)); +} + +} diff --git a/Libraries/LibJS/Runtime/NativeProperty.h b/Libraries/LibJS/Runtime/NativeProperty.h new file mode 100644 index 0000000000..0044ac5a0f --- /dev/null +++ b/Libraries/LibJS/Runtime/NativeProperty.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2020, Andreas Kling <kling@serenityos.org> + * 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/Function.h> +#include <LibJS/Runtime/Object.h> + +namespace JS { + +class NativeProperty final : public Object { +public: + NativeProperty(AK::Function<Value(Object*)> getter, AK::Function<void(Object*, Value)> setter); + virtual ~NativeProperty() override; + + Value get(Object*) const; + void set(Object*, Value); + +private: + virtual bool is_native_property() const override { return true; } + virtual const char* class_name() const override { return "NativeProperty"; } + + AK::Function<Value(Object*)> m_getter; + AK::Function<void(Object*, Value)> m_setter; +}; + +} diff --git a/Libraries/LibJS/Runtime/Object.cpp b/Libraries/LibJS/Runtime/Object.cpp new file mode 100644 index 0000000000..2ddc4dfe17 --- /dev/null +++ b/Libraries/LibJS/Runtime/Object.cpp @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2020, Andreas Kling <kling@serenityos.org> + * 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/String.h> +#include <LibJS/Heap/Heap.h> +#include <LibJS/Interpreter.h> +#include <LibJS/Runtime/NativeFunction.h> +#include <LibJS/Runtime/NativeProperty.h> +#include <LibJS/Runtime/Object.h> +#include <LibJS/Runtime/Value.h> + +namespace JS { + +Object::Object() +{ + set_prototype(interpreter().object_prototype()); +} + +Object::~Object() +{ +} + +Value Object::get(String property_name) const +{ + const Object* object = this; + while (object) { + auto value = object->m_properties.get(property_name); + if (value.has_value()) { + if (value.value().is_object() && value.value().as_object()->is_native_property()) + return static_cast<const NativeProperty*>(value.value().as_object())->get(const_cast<Object*>(this)); + return value.value(); + } + object = object->prototype(); + } + return js_undefined(); +} + +void Object::put(String property_name, Value value) +{ + m_properties.set(property_name, move(value)); +} + +void Object::put_native_function(String property_name, AK::Function<Value(Object*, Vector<Value>)> native_function) +{ + put(property_name, heap().allocate<NativeFunction>(move(native_function))); +} + +void Object::put_native_property(String property_name, AK::Function<Value(Object*)> getter, AK::Function<void(Object*, Value)> setter) +{ + put(property_name, heap().allocate<NativeProperty>(move(getter), move(setter))); +} + +void Object::visit_children(Cell::Visitor& visitor) +{ + Cell::visit_children(visitor); + if (m_prototype) + visitor.visit(m_prototype); + for (auto& it : m_properties) + visitor.visit(it.value); +} + +bool Object::has_own_property(const String& property_name) const +{ + return m_properties.get(property_name).has_value(); +} + +Value Object::to_primitive(PreferredType preferred_type) const +{ + Value result = js_undefined(); + + switch (preferred_type) { + case PreferredType::Default: + case PreferredType::Number: { + result = value_of(); + if (result.is_object()) { + result = to_string(); + } + break; + } + case PreferredType::String: { + result = to_string(); + if (result.is_object()) + result = value_of(); + break; + } + } + + ASSERT(!result.is_object()); + return result; +} + +Value Object::to_string() const +{ + return js_string(heap(), String::format("[object %s]", class_name())); +} + +} diff --git a/Libraries/LibJS/Runtime/Object.h b/Libraries/LibJS/Runtime/Object.h new file mode 100644 index 0000000000..cca3c587d6 --- /dev/null +++ b/Libraries/LibJS/Runtime/Object.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2020, Andreas Kling <kling@serenityos.org> + * 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/HashMap.h> +#include <AK/String.h> +#include <LibJS/Forward.h> +#include <LibJS/Runtime/Cell.h> +#include <LibJS/Runtime/PrimitiveString.h> +#include <LibJS/Runtime/Value.h> + +namespace JS { + +class Object : public Cell { +public: + Object(); + virtual ~Object(); + + Value get(String property_name) const; + void put(String property_name, Value); + + void put_native_function(String property_name, AK::Function<Value(Object*, Vector<Value>)>); + void put_native_property(String property_name, AK::Function<Value(Object*)> getter, AK::Function<void(Object*, Value)> setter); + + virtual bool is_function() const { return false; } + virtual bool is_native_function() const { return false; } + virtual bool is_string_object() const { return false; } + virtual bool is_native_property() const { return false; } + + virtual const char* class_name() const override { return "Object"; } + virtual void visit_children(Cell::Visitor&) override; + + Object* prototype() { return m_prototype; } + const Object* prototype() const { return m_prototype; } + void set_prototype(Object* prototype) { m_prototype = prototype; } + + bool has_own_property(const String& property_name) const; + enum class PreferredType { + Default, + String, + Number, + }; + + virtual Value value_of() const { return Value(const_cast<Object*>(this)); } + virtual Value to_primitive(PreferredType preferred_type = PreferredType::Default) const; + virtual Value to_string() const; + +private: + HashMap<String, Value> m_properties; + Object* m_prototype { nullptr }; +}; + +} diff --git a/Libraries/LibJS/Runtime/ObjectPrototype.cpp b/Libraries/LibJS/Runtime/ObjectPrototype.cpp new file mode 100644 index 0000000000..688a5025f5 --- /dev/null +++ b/Libraries/LibJS/Runtime/ObjectPrototype.cpp @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2020, Andreas Kling <kling@serenityos.org> + * 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/String.h> +#include <LibJS/Heap/Heap.h> +#include <LibJS/Interpreter.h> +#include <LibJS/Runtime/ObjectPrototype.h> +#include <LibJS/Runtime/Value.h> + +namespace JS { + +ObjectPrototype::ObjectPrototype() +{ + set_prototype(nullptr); + + put_native_function("hasOwnProperty", [](Object* this_object, Vector<Value> arguments) -> Value { + ASSERT(this_object); + if (arguments.is_empty()) + return js_undefined(); + return Value(this_object->has_own_property(arguments[0].to_string())); + }); + + put_native_function("toString", [](Object* this_object, Vector<Value>) -> Value { + ASSERT(this_object); + + return Value(this_object->to_string()); + }); + + put_native_function("valueOf", [](Object* this_object, Vector<Value>) -> Value { + ASSERT(this_object); + return this_object->value_of(); + }); +} + +ObjectPrototype::~ObjectPrototype() +{ +} + +} diff --git a/Libraries/LibJS/Runtime/ObjectPrototype.h b/Libraries/LibJS/Runtime/ObjectPrototype.h new file mode 100644 index 0000000000..704e0322e3 --- /dev/null +++ b/Libraries/LibJS/Runtime/ObjectPrototype.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2020, Andreas Kling <kling@serenityos.org> + * 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 ObjectPrototype final : public Object { +public: + ObjectPrototype(); + virtual ~ObjectPrototype() override; + +private: + virtual const char* class_name() const override { return "ObjectPrototype"; } +}; + +} diff --git a/Libraries/LibJS/Runtime/PrimitiveString.cpp b/Libraries/LibJS/Runtime/PrimitiveString.cpp new file mode 100644 index 0000000000..cfba8c8872 --- /dev/null +++ b/Libraries/LibJS/Runtime/PrimitiveString.cpp @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2020, Andreas Kling <kling@serenityos.org> + * 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/Runtime/PrimitiveString.h> + +namespace JS { + +PrimitiveString::PrimitiveString(String string) + : m_string(move(string)) +{ +} + +PrimitiveString::~PrimitiveString() +{ +} + +PrimitiveString* js_string(Heap& heap, String string) +{ + return heap.allocate<PrimitiveString>(move(string)); +} + +} diff --git a/Libraries/LibJS/Runtime/PrimitiveString.h b/Libraries/LibJS/Runtime/PrimitiveString.h new file mode 100644 index 0000000000..6e9f9539d3 --- /dev/null +++ b/Libraries/LibJS/Runtime/PrimitiveString.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2020, Andreas Kling <kling@serenityos.org> + * 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 PrimitiveString final : public Cell { +public: + explicit PrimitiveString(String); + virtual ~PrimitiveString(); + + const String& string() const { return m_string; } + +private: + virtual const char* class_name() const override { return "PrimitiveString"; } + + String m_string; +}; + +PrimitiveString* js_string(Heap&, String); + +} diff --git a/Libraries/LibJS/Runtime/ScriptFunction.cpp b/Libraries/LibJS/Runtime/ScriptFunction.cpp new file mode 100644 index 0000000000..f8833a4ec6 --- /dev/null +++ b/Libraries/LibJS/Runtime/ScriptFunction.cpp @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2020, Stephan Unverwerth <s.unverwerth@gmx.de> + * 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/ScriptFunction.h> +#include <LibJS/Runtime/Value.h> + +namespace JS { + +ScriptFunction::ScriptFunction(const ScopeNode& body, Vector<String> parameters) + : m_body(body) + , m_parameters(move(parameters)) +{ +} + +ScriptFunction::~ScriptFunction() +{ +} + +Value ScriptFunction::call(Interpreter& interpreter, Vector<Value> argument_values) +{ + Vector<Argument> arguments; + for (size_t i = 0; i < m_parameters.size(); ++i) { + auto name = parameters()[i]; + auto value = js_undefined(); + if (i < argument_values.size()) + value = argument_values[i]; + arguments.append({ move(name), move(value) }); + } + return interpreter.run(m_body, move(arguments), ScopeType::Function); +} + +} diff --git a/Libraries/LibJS/Runtime/ScriptFunction.h b/Libraries/LibJS/Runtime/ScriptFunction.h new file mode 100644 index 0000000000..76ac8e1b69 --- /dev/null +++ b/Libraries/LibJS/Runtime/ScriptFunction.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2020, Andreas Kling <kling@serenityos.org> + * 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/Function.h> + +namespace JS { + +class ScriptFunction final : public Function { +public: + ScriptFunction(const ScopeNode& body, Vector<String> parameters = {}); + virtual ~ScriptFunction(); + + const ScopeNode& body() const { return m_body; } + const Vector<String>& parameters() const { return m_parameters; }; + + virtual Value call(Interpreter&, Vector<Value>) override; + +private: + virtual bool is_script_function() const final { return true; } + virtual const char* class_name() const override { return "ScriptFunction"; } + + const ScopeNode& m_body; + const Vector<String> m_parameters; +}; + +} diff --git a/Libraries/LibJS/Runtime/StringObject.cpp b/Libraries/LibJS/Runtime/StringObject.cpp new file mode 100644 index 0000000000..2d6c76c580 --- /dev/null +++ b/Libraries/LibJS/Runtime/StringObject.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2020, Andreas Kling <kling@serenityos.org> + * 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/PrimitiveString.h> +#include <LibJS/Runtime/StringObject.h> +#include <LibJS/Runtime/StringPrototype.h> +#include <LibJS/Runtime/Value.h> + +namespace JS { + +StringObject::StringObject(PrimitiveString* string) + : m_string(string) +{ + set_prototype(interpreter().string_prototype()); +} + +StringObject::~StringObject() +{ +} + +void StringObject::visit_children(Cell::Visitor& visitor) +{ + Object::visit_children(visitor); + visitor.visit(m_string); +} + +} diff --git a/Libraries/LibJS/Runtime/StringObject.h b/Libraries/LibJS/Runtime/StringObject.h new file mode 100644 index 0000000000..76f05bbcce --- /dev/null +++ b/Libraries/LibJS/Runtime/StringObject.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2020, Andreas Kling <kling@serenityos.org> + * 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 StringObject final : public Object { +public: + explicit StringObject(PrimitiveString*); + virtual ~StringObject() override; + + virtual void visit_children(Visitor&) override; + const PrimitiveString* primitive_string() const { return m_string; } + virtual Value value_of() const override + { + return Value(m_string); + } + +private: + virtual const char* class_name() const override { return "StringObject"; } + virtual bool is_string_object() const override { return true; } + + PrimitiveString* m_string { nullptr }; +}; + +} diff --git a/Libraries/LibJS/Runtime/StringPrototype.cpp b/Libraries/LibJS/Runtime/StringPrototype.cpp new file mode 100644 index 0000000000..dabb8cccda --- /dev/null +++ b/Libraries/LibJS/Runtime/StringPrototype.cpp @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2020, Andreas Kling <kling@serenityos.org> + * 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/PrimitiveString.h> +#include <LibJS/Runtime/StringObject.h> +#include <LibJS/Runtime/StringPrototype.h> +#include <LibJS/Runtime/Value.h> + +namespace JS { + +StringPrototype::StringPrototype() +{ + put_native_property( + "length", [](Object* this_object) { + ASSERT(this_object); + ASSERT(this_object->is_string_object()); + return Value((i32) static_cast<const StringObject*>(this_object)->primitive_string()->string().length()); + }, + nullptr); + put_native_function("charAt", [](Object* this_object, Vector<Value> arguments) -> Value { + ASSERT(this_object); + i32 index = 0; + if (!arguments.is_empty()) + index = arguments[0].to_i32(); + ASSERT(this_object->is_string_object()); + auto underlying_string = static_cast<const StringObject*>(this_object)->primitive_string()->string(); + if (index < 0 || index >= static_cast<i32>(underlying_string.length())) + return js_string(this_object->heap(), String::empty()); + return js_string(this_object->heap(), underlying_string.substring(index, 1)); + }); + put_native_function("repeat", [](Object* this_object, Vector<Value> arguments) -> Value { + ASSERT(this_object->is_string_object()); + if (arguments.is_empty()) + return js_string(this_object->heap(), String::empty()); + i32 count = 0; + count = arguments[0].to_i32(); + if (count < 0) { + // FIXME: throw RangeError + return js_undefined(); + } + auto* string_object = static_cast<StringObject*>(this_object); + StringBuilder builder; + for (i32 i = 0; i < count; ++i) + builder.append(string_object->primitive_string()->string()); + return js_string(this_object->heap(), builder.to_string()); + }); +} + +StringPrototype::~StringPrototype() +{ +} + +} diff --git a/Libraries/LibJS/Runtime/StringPrototype.h b/Libraries/LibJS/Runtime/StringPrototype.h new file mode 100644 index 0000000000..51cdedd73b --- /dev/null +++ b/Libraries/LibJS/Runtime/StringPrototype.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2020, Andreas Kling <kling@serenityos.org> + * 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 StringPrototype final : public Object { +public: + StringPrototype(); + virtual ~StringPrototype() override; + +private: + virtual const char* class_name() const override { return "StringPrototype"; } +}; + +} diff --git a/Libraries/LibJS/Runtime/Value.cpp b/Libraries/LibJS/Runtime/Value.cpp new file mode 100644 index 0000000000..a865ba3048 --- /dev/null +++ b/Libraries/LibJS/Runtime/Value.cpp @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2020, Andreas Kling <kling@serenityos.org> + * 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/String.h> +#include <LibJS/Heap/Heap.h> +#include <LibJS/Runtime/Object.h> +#include <LibJS/Runtime/PrimitiveString.h> +#include <LibJS/Runtime/StringObject.h> +#include <LibJS/Runtime/Value.h> + +namespace JS { + +String Value::to_string() const +{ + if (is_boolean()) + return as_bool() ? "true" : "false"; + + if (is_null()) + return "null"; + + if (is_undefined()) + return "undefined"; + + if (is_number()) + // FIXME: This needs improvement. + return String::number((i32)as_double()); + + if (is_object()) + return as_object()->to_primitive(Object::PreferredType::String).to_string(); + + if (is_string()) + return m_value.as_string->string(); + + ASSERT_NOT_REACHED(); +} + +bool Value::to_boolean() const +{ + switch (m_type) { + case Type::Boolean: + return m_value.as_bool; + case Type::Number: + return !(m_value.as_double == 0 || m_value.as_double == -0); + case Type::Null: + case Type::Undefined: + return false; + case Type::String: + return !as_string()->string().is_empty(); + case Type::Object: + return true; + default: + ASSERT_NOT_REACHED(); + } +} + +Value Value::to_object(Heap& heap) const +{ + if (is_object()) + return const_cast<Object*>(as_object()); + + if (is_string()) + return heap.allocate<StringObject>(m_value.as_string); + + ASSERT_NOT_REACHED(); +} + +Value Value::to_number() const +{ + switch (m_type) { + case Type::Boolean: + return Value(m_value.as_bool ? 1 : 0); + case Type::Number: + return Value(m_value.as_double); + case Type::Null: + return Value(0); + case Type::String: { + bool ok; + //FIXME: Parse in a better way + auto parsed_int = as_string()->string().to_int(ok); + if (ok) + return Value(parsed_int); + + //FIXME: Implement 'NaN' + ASSERT_NOT_REACHED(); + + break; + } + case Type::Undefined: + //FIXME: Implement 'NaN' + ASSERT_NOT_REACHED(); + case Type::Object: + return m_value.as_object->to_primitive(Object::PreferredType::Number).to_number(); + } + + ASSERT_NOT_REACHED(); +} + +i32 Value::to_i32() const +{ + return static_cast<i32>(to_number().as_double()); +} + +Value greater_than(Value lhs, Value rhs) +{ + return Value(lhs.to_number().as_double() > rhs.to_number().as_double()); +} + +Value greater_than_equals(Value lhs, Value rhs) +{ + return Value(lhs.to_number().as_double() >= rhs.to_number().as_double()); +} + +Value less_than(Value lhs, Value rhs) +{ + return Value(lhs.to_number().as_double() < rhs.to_number().as_double()); +} + +Value less_than_equals(Value lhs, Value rhs) +{ + return Value(lhs.to_number().as_double() <= rhs.to_number().as_double()); +} + +Value bitwise_and(Value lhs, Value rhs) +{ + return Value((i32)lhs.to_number().as_double() & (i32)rhs.to_number().as_double()); +} + +Value bitwise_or(Value lhs, Value rhs) +{ + return Value((i32)lhs.to_number().as_double() | (i32)rhs.to_number().as_double()); +} + +Value bitwise_xor(Value lhs, Value rhs) +{ + return Value((i32)lhs.to_number().as_double() ^ (i32)rhs.to_number().as_double()); +} + +Value bitwise_not(Value lhs) +{ + return Value(~(i32)lhs.to_number().as_double()); +} + +Value left_shift(Value lhs, Value rhs) +{ + return Value((i32)lhs.to_number().as_double() << (i32)rhs.to_number().as_double()); +} + +Value right_shift(Value lhs, Value rhs) +{ + return Value((i32)lhs.to_number().as_double() >> (i32)rhs.to_number().as_double()); +} + +Value add(Value lhs, Value rhs) +{ + if (lhs.is_string() || rhs.is_string()) + return js_string((lhs.is_string() ? lhs : rhs).as_string()->heap(), String::format("%s%s", lhs.to_string().characters(), rhs.to_string().characters())); + + return Value(lhs.to_number().as_double() + rhs.to_number().as_double()); +} + +Value sub(Value lhs, Value rhs) +{ + return Value(lhs.to_number().as_double() - rhs.to_number().as_double()); +} + +Value mul(Value lhs, Value rhs) +{ + return Value(lhs.to_number().as_double() * rhs.to_number().as_double()); +} + +Value div(Value lhs, Value rhs) +{ + return Value(lhs.to_number().as_double() / rhs.to_number().as_double()); +} + +Value typed_eq(Value lhs, Value rhs) +{ + if (rhs.type() != lhs.type()) + return Value(false); + + switch (lhs.type()) { + case Value::Type::Undefined: + return Value(true); + case Value::Type::Null: + return Value(true); + case Value::Type::Number: + return Value(lhs.as_double() == rhs.as_double()); + case Value::Type::String: + return Value(lhs.as_string()->string() == rhs.as_string()->string()); + case Value::Type::Boolean: + return Value(lhs.as_bool() == rhs.as_bool()); + case Value::Type::Object: + return Value(lhs.as_object() == rhs.as_object()); + } + + ASSERT_NOT_REACHED(); +} + +Value eq(Value lhs, Value rhs) +{ + if (lhs.type() == rhs.type()) + return typed_eq(lhs, rhs); + + if ((lhs.is_undefined() || lhs.is_null()) && (rhs.is_undefined() || rhs.is_null())) + return Value(true); + + if (lhs.is_object() && rhs.is_boolean()) + return eq(lhs.as_object()->to_primitive(), rhs.to_number()); + + if (lhs.is_boolean() && rhs.is_object()) + return eq(lhs.to_number(), rhs.as_object()->to_primitive()); + + if (lhs.is_object()) + return eq(lhs.as_object()->to_primitive(), rhs); + + if (rhs.is_object()) + return eq(lhs, rhs.as_object()->to_primitive()); + + if (lhs.is_number() || rhs.is_number()) + return Value(lhs.to_number().as_double() == rhs.to_number().as_double()); + + if ((lhs.is_string() && rhs.is_boolean()) || (lhs.is_string() && rhs.is_boolean())) + return Value(lhs.to_number().as_double() == rhs.to_number().as_double()); + + return Value(false); +} + +const LogStream& operator<<(const LogStream& stream, const Value& value) +{ + return stream << value.to_string(); +} + +} diff --git a/Libraries/LibJS/Runtime/Value.h b/Libraries/LibJS/Runtime/Value.h new file mode 100644 index 0000000000..ada26761c6 --- /dev/null +++ b/Libraries/LibJS/Runtime/Value.h @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2020, Andreas Kling <kling@serenityos.org> + * 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/Assertions.h> +#include <AK/Forward.h> +#include <AK/LogStream.h> +#include <LibJS/Forward.h> + +namespace JS { + +class Value { +public: + enum class Type { + Undefined, + Null, + Number, + String, + Object, + Boolean, + }; + + bool is_undefined() const { return m_type == Type::Undefined; } + bool is_null() const { return m_type == Type::Null; } + bool is_number() const { return m_type == Type::Number; } + 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_cell() const { return is_string() || is_object(); } + + explicit Value(bool value) + : m_type(Type::Boolean) + { + m_value.as_bool = value; + } + + explicit Value(double value) + : m_type(Type::Number) + { + m_value.as_double = value; + } + + explicit Value(i32 value) + : m_type(Type::Number) + { + m_value.as_double = value; + } + + Value(Object* object) + : m_type(Type::Object) + { + m_value.as_object = object; + } + + Value(PrimitiveString* string) + : m_type(Type::String) + { + m_value.as_string = string; + } + + explicit Value(Type type) + : m_type(type) + { + } + + Type type() const { return m_type; } + + double as_double() const + { + ASSERT(type() == Type::Number); + return m_value.as_double; + } + + bool as_bool() const + { + ASSERT(type() == Type::Boolean); + return m_value.as_bool; + } + + Object* as_object() + { + ASSERT(type() == Type::Object); + return m_value.as_object; + } + + const Object* as_object() const + { + ASSERT(type() == Type::Object); + return m_value.as_object; + } + + PrimitiveString* as_string() + { + ASSERT(is_string()); + return m_value.as_string; + } + + const PrimitiveString* as_string() const + { + ASSERT(is_string()); + return m_value.as_string; + } + + Cell* as_cell() + { + ASSERT(is_cell()); + return m_value.as_cell; + } + + String to_string() const; + bool to_boolean() const; + Value to_number() const; + i32 to_i32() const; + + Value to_object(Heap&) const; + +private: + Type m_type { Type::Undefined }; + + union { + bool as_bool; + double as_double; + PrimitiveString* as_string; + Object* as_object; + Cell* as_cell; + } m_value; +}; + +inline Value js_undefined() +{ + return Value(Value::Type::Undefined); +} + +inline Value js_null() +{ + return Value(Value::Type::Null); +} + +Value greater_than(Value lhs, Value rhs); +Value greater_than_equals(Value lhs, Value rhs); +Value less_than(Value lhs, Value rhs); +Value less_than_equals(Value lhs, Value rhs); +Value bitwise_and(Value lhs, Value rhs); +Value bitwise_or(Value lhs, Value rhs); +Value bitwise_xor(Value lhs, Value rhs); +Value bitwise_not(Value); +Value left_shift(Value lhs, Value rhs); +Value right_shift(Value lhs, Value rhs); +Value add(Value lhs, Value rhs); +Value sub(Value lhs, Value rhs); +Value mul(Value lhs, Value rhs); +Value div(Value lhs, Value rhs); +Value eq(Value lhs, Value rhs); +Value typed_eq(Value lhs, Value rhs); + +const LogStream& operator<<(const LogStream&, const Value&); + +} |