summaryrefslogtreecommitdiff
path: root/Libraries
diff options
context:
space:
mode:
Diffstat (limited to 'Libraries')
-rw-r--r--Libraries/LibJS/AST.cpp41
-rw-r--r--Libraries/LibJS/Forward.h1
-rw-r--r--Libraries/LibJS/Interpreter.cpp13
-rw-r--r--Libraries/LibJS/Interpreter.h9
-rw-r--r--Libraries/LibJS/Makefile2
-rw-r--r--Libraries/LibJS/Runtime/Error.cpp43
-rw-r--r--Libraries/LibJS/Runtime/Error.h48
-rw-r--r--Libraries/LibJS/Runtime/ErrorPrototype.cpp61
-rw-r--r--Libraries/LibJS/Runtime/ErrorPrototype.h42
-rw-r--r--Libraries/LibJS/Runtime/Object.h1
10 files changed, 256 insertions, 5 deletions
diff --git a/Libraries/LibJS/AST.cpp b/Libraries/LibJS/AST.cpp
index 936f48d18c..b6d48ad82f 100644
--- a/Libraries/LibJS/AST.cpp
+++ b/Libraries/LibJS/AST.cpp
@@ -30,6 +30,7 @@
#include <LibJS/AST.h>
#include <LibJS/Interpreter.h>
#include <LibJS/Runtime/Array.h>
+#include <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/PrimitiveString.h>
#include <LibJS/Runtime/ScriptFunction.h>
#include <LibJS/Runtime/Value.h>
@@ -62,16 +63,29 @@ Value ExpressionStatement::execute(Interpreter& interpreter) const
Value CallExpression::execute(Interpreter& interpreter) const
{
auto callee = m_callee->execute(interpreter);
+ if (interpreter.exception())
+ return {};
+
ASSERT(callee.is_object());
ASSERT(callee.as_object()->is_function());
auto* function = static_cast<Function*>(callee.as_object());
auto& call_frame = interpreter.push_call_frame();
- for (size_t i = 0; i < m_arguments.size(); ++i)
+ for (size_t i = 0; i < m_arguments.size(); ++i) {
call_frame.arguments.append(m_arguments[i].execute(interpreter));
+ if (interpreter.exception())
+ return {};
+ }
- if (m_callee->is_member_expression())
- call_frame.this_value = static_cast<const MemberExpression&>(*m_callee).object().execute(interpreter).to_object(interpreter.heap());
+ if (m_callee->is_member_expression()) {
+ auto object_value = static_cast<const MemberExpression&>(*m_callee).object().execute(interpreter);
+ if (interpreter.exception())
+ return {};
+ auto this_value = object_value.to_object(interpreter.heap());
+ if (interpreter.exception())
+ return {};
+ call_frame.this_value = this_value;
+ }
auto result = function->call(interpreter, call_frame.arguments);
interpreter.pop_call_frame();
@@ -464,7 +478,10 @@ void ForStatement::dump(int indent) const
Value Identifier::execute(Interpreter& interpreter) const
{
- return interpreter.get_variable(string());
+ auto value = interpreter.get_variable(string());
+ if (value.is_undefined())
+ return interpreter.throw_exception(interpreter.heap().allocate<Error>("ReferenceError", String::format("'%s' not known", string().characters())));
+ return value;
}
void Identifier::dump(int indent) const
@@ -745,13 +762,27 @@ void CatchClause::dump(int indent) const
body().dump(indent + 1);
}
-Value TryStatement::execute(Interpreter&) const
+Value TryStatement::execute(Interpreter& interpreter) const
{
+ interpreter.run(block(), {}, ScopeType::Try);
+ if (auto* exception = interpreter.exception()) {
+ if (m_handler) {
+ interpreter.clear_exception();
+ Vector<Argument> arguments { { m_handler->parameter(), Value(exception) } };
+ interpreter.run(m_handler->body(), move(arguments));
+ }
+ }
+
+ if (m_finalizer)
+ m_finalizer->execute(interpreter);
+
return {};
}
Value CatchClause::execute(Interpreter&) const
{
+ // NOTE: CatchClause execution is handled by TryStatement.
+ ASSERT_NOT_REACHED();
return {};
}
diff --git a/Libraries/LibJS/Forward.h b/Libraries/LibJS/Forward.h
index 359d6f6ab4..aa4079bc61 100644
--- a/Libraries/LibJS/Forward.h
+++ b/Libraries/LibJS/Forward.h
@@ -31,6 +31,7 @@ namespace JS {
class ASTNode;
class Argument;
class Cell;
+class Error;
class Expression;
class Function;
class HandleImpl;
diff --git a/Libraries/LibJS/Interpreter.cpp b/Libraries/LibJS/Interpreter.cpp
index f602336bc4..6a5bee1938 100644
--- a/Libraries/LibJS/Interpreter.cpp
+++ b/Libraries/LibJS/Interpreter.cpp
@@ -28,6 +28,8 @@
#include <LibJS/AST.h>
#include <LibJS/Interpreter.h>
#include <LibJS/Runtime/ArrayPrototype.h>
+#include <LibJS/Runtime/Error.h>
+#include <LibJS/Runtime/ErrorPrototype.h>
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/NativeFunction.h>
#include <LibJS/Runtime/Object.h>
@@ -44,6 +46,7 @@ Interpreter::Interpreter()
m_object_prototype = heap().allocate<ObjectPrototype>();
m_string_prototype = heap().allocate<StringPrototype>();
m_array_prototype = heap().allocate<ArrayPrototype>();
+ m_error_prototype = heap().allocate<ErrorPrototype>();
}
Interpreter::~Interpreter()
@@ -154,6 +157,9 @@ void Interpreter::gather_roots(Badge<Heap>, HashTable<Cell*>& roots)
roots.set(m_string_prototype);
roots.set(m_object_prototype);
roots.set(m_array_prototype);
+ roots.set(m_error_prototype);
+
+ roots.set(m_exception);
for (auto& scope : m_scope_stack) {
for (auto& it : scope.variables) {
@@ -182,4 +188,11 @@ Value Interpreter::call(Function* function, Value this_value, const Vector<Value
return result;
}
+Value Interpreter::throw_exception(Error* exception)
+{
+ m_exception = exception;
+ unwind(ScopeType::Try);
+ return {};
+}
+
}
diff --git a/Libraries/LibJS/Interpreter.h b/Libraries/LibJS/Interpreter.h
index fab56397d1..6c2beecd9e 100644
--- a/Libraries/LibJS/Interpreter.h
+++ b/Libraries/LibJS/Interpreter.h
@@ -40,6 +40,7 @@ enum class ScopeType {
None,
Function,
Block,
+ Try,
};
struct Variable {
@@ -104,6 +105,11 @@ public:
Object* string_prototype() { return m_string_prototype; }
Object* object_prototype() { return m_object_prototype; }
Object* array_prototype() { return m_array_prototype; }
+ Object* error_prototype() { return m_error_prototype; }
+
+ Error* exception() { return m_exception; }
+ void clear_exception() { m_exception = nullptr; }
+ Value throw_exception(Error*);
private:
Heap m_heap;
@@ -115,6 +121,9 @@ private:
Object* m_string_prototype { nullptr };
Object* m_object_prototype { nullptr };
Object* m_array_prototype { nullptr };
+ Object* m_error_prototype { nullptr };
+
+ Error* m_exception { nullptr };
ScopeType m_unwind_until { ScopeType::None };
};
diff --git a/Libraries/LibJS/Makefile b/Libraries/LibJS/Makefile
index e550349a57..fd0b255115 100644
--- a/Libraries/LibJS/Makefile
+++ b/Libraries/LibJS/Makefile
@@ -10,6 +10,8 @@ OBJS = \
Runtime/ArrayPrototype.o \
Runtime/Cell.o \
Runtime/ConsoleObject.o \
+ Runtime/Error.o \
+ Runtime/ErrorPrototype.o \
Runtime/Function.o \
Runtime/GlobalObject.o \
Runtime/MathObject.o \
diff --git a/Libraries/LibJS/Runtime/Error.cpp b/Libraries/LibJS/Runtime/Error.cpp
new file mode 100644
index 0000000000..029c25d197
--- /dev/null
+++ b/Libraries/LibJS/Runtime/Error.cpp
@@ -0,0 +1,43 @@
+/*
+ * 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/Error.h>
+
+namespace JS {
+
+Error::Error(const FlyString& name, const String& message)
+ : m_name(name)
+ , m_message(message)
+{
+ set_prototype(interpreter().error_prototype());
+}
+
+Error::~Error()
+{
+}
+
+}
diff --git a/Libraries/LibJS/Runtime/Error.h b/Libraries/LibJS/Runtime/Error.h
new file mode 100644
index 0000000000..411454217e
--- /dev/null
+++ b/Libraries/LibJS/Runtime/Error.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.
+ */
+
+#include <AK/FlyString.h>
+#include <LibJS/Runtime/Object.h>
+
+namespace JS {
+
+class Error : public Object {
+public:
+ Error(const FlyString& name, const String& message);
+ virtual ~Error() override;
+
+ const FlyString& name() const { return m_name; }
+ const String& message() const { return m_message; }
+
+private:
+ virtual bool is_error() const final { return true; }
+ virtual const char* class_name() const override { return "Error"; }
+
+ FlyString m_name;
+ String m_message;
+};
+
+}
diff --git a/Libraries/LibJS/Runtime/ErrorPrototype.cpp b/Libraries/LibJS/Runtime/ErrorPrototype.cpp
new file mode 100644
index 0000000000..27b396f211
--- /dev/null
+++ b/Libraries/LibJS/Runtime/ErrorPrototype.cpp
@@ -0,0 +1,61 @@
+/*
+ * 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 <LibJS/Heap/Heap.h>
+#include <LibJS/Interpreter.h>
+#include <LibJS/Runtime/Error.h>
+#include <LibJS/Runtime/ErrorPrototype.h>
+#include <LibJS/Runtime/PrimitiveString.h>
+#include <LibJS/Runtime/Value.h>
+
+namespace JS {
+
+ErrorPrototype::ErrorPrototype()
+{
+ put_native_property(
+ "name", [](Object* this_object) {
+ dbg() << "Error.prototype.name on " << this_object;
+ ASSERT(this_object);
+ ASSERT(this_object->is_error());
+ return js_string(this_object->heap(), static_cast<const Error*>(this_object)->name());
+ },
+ nullptr);
+
+ put_native_property(
+ "message", [](Object* this_object) {
+ ASSERT(this_object);
+ ASSERT(this_object->is_error());
+ return js_string(this_object->heap(), static_cast<const Error*>(this_object)->message());
+ },
+ nullptr);
+}
+
+ErrorPrototype::~ErrorPrototype()
+{
+}
+
+}
diff --git a/Libraries/LibJS/Runtime/ErrorPrototype.h b/Libraries/LibJS/Runtime/ErrorPrototype.h
new file mode 100644
index 0000000000..8775b6aa51
--- /dev/null
+++ b/Libraries/LibJS/Runtime/ErrorPrototype.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 ErrorPrototype final : public Object {
+public:
+ ErrorPrototype();
+ virtual ~ErrorPrototype() override;
+
+private:
+ virtual const char* class_name() const override { return "ErrorPrototype"; }
+};
+
+}
diff --git a/Libraries/LibJS/Runtime/Object.h b/Libraries/LibJS/Runtime/Object.h
index fd98b0e44f..af11e35af5 100644
--- a/Libraries/LibJS/Runtime/Object.h
+++ b/Libraries/LibJS/Runtime/Object.h
@@ -49,6 +49,7 @@ public:
void put_native_function(const FlyString& property_name, AK::Function<Value(Object*, Vector<Value>)>);
void put_native_property(const FlyString& property_name, AK::Function<Value(Object*)> getter, AK::Function<void(Object*, Value)> setter);
+ virtual bool is_error() const { return false; }
virtual bool is_array() const { return false; }
virtual bool is_function() const { return false; }
virtual bool is_native_function() const { return false; }