diff options
Diffstat (limited to 'Libraries')
-rw-r--r-- | Libraries/LibJS/AST.cpp | 41 | ||||
-rw-r--r-- | Libraries/LibJS/Forward.h | 1 | ||||
-rw-r--r-- | Libraries/LibJS/Interpreter.cpp | 13 | ||||
-rw-r--r-- | Libraries/LibJS/Interpreter.h | 9 | ||||
-rw-r--r-- | Libraries/LibJS/Makefile | 2 | ||||
-rw-r--r-- | Libraries/LibJS/Runtime/Error.cpp | 43 | ||||
-rw-r--r-- | Libraries/LibJS/Runtime/Error.h | 48 | ||||
-rw-r--r-- | Libraries/LibJS/Runtime/ErrorPrototype.cpp | 61 | ||||
-rw-r--r-- | Libraries/LibJS/Runtime/ErrorPrototype.h | 42 | ||||
-rw-r--r-- | Libraries/LibJS/Runtime/Object.h | 1 |
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; } |