summaryrefslogtreecommitdiff
path: root/Libraries/LibJS/Runtime
diff options
context:
space:
mode:
Diffstat (limited to 'Libraries/LibJS/Runtime')
-rw-r--r--Libraries/LibJS/Runtime/Cell.cpp60
-rw-r--r--Libraries/LibJS/Runtime/Cell.h64
-rw-r--r--Libraries/LibJS/Runtime/Function.cpp40
-rw-r--r--Libraries/LibJS/Runtime/Function.h48
-rw-r--r--Libraries/LibJS/Runtime/GlobalObject.cpp31
-rw-r--r--Libraries/LibJS/Runtime/GlobalObject.h16
-rw-r--r--Libraries/LibJS/Runtime/NativeFunction.cpp49
-rw-r--r--Libraries/LibJS/Runtime/NativeFunction.h48
-rw-r--r--Libraries/LibJS/Runtime/NativeProperty.cpp56
-rw-r--r--Libraries/LibJS/Runtime/NativeProperty.h50
-rw-r--r--Libraries/LibJS/Runtime/Object.cpp120
-rw-r--r--Libraries/LibJS/Runtime/Object.h77
-rw-r--r--Libraries/LibJS/Runtime/ObjectPrototype.cpp63
-rw-r--r--Libraries/LibJS/Runtime/ObjectPrototype.h42
-rw-r--r--Libraries/LibJS/Runtime/PrimitiveString.cpp46
-rw-r--r--Libraries/LibJS/Runtime/PrimitiveString.h49
-rw-r--r--Libraries/LibJS/Runtime/ScriptFunction.cpp56
-rw-r--r--Libraries/LibJS/Runtime/ScriptFunction.h51
-rw-r--r--Libraries/LibJS/Runtime/StringObject.cpp52
-rw-r--r--Libraries/LibJS/Runtime/StringObject.h52
-rw-r--r--Libraries/LibJS/Runtime/StringPrototype.cpp80
-rw-r--r--Libraries/LibJS/Runtime/StringPrototype.h42
-rw-r--r--Libraries/LibJS/Runtime/Value.cpp256
-rw-r--r--Libraries/LibJS/Runtime/Value.h182
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&);
+
+}