summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Base/home/anon/js/throw.js5
-rw-r--r--Libraries/LibJS/AST.cpp16
-rw-r--r--Libraries/LibJS/AST.h18
-rw-r--r--Libraries/LibJS/Forward.h1
-rw-r--r--Libraries/LibJS/Interpreter.cpp2
-rw-r--r--Libraries/LibJS/Interpreter.h20
-rw-r--r--Libraries/LibJS/Lexer.cpp1
-rw-r--r--Libraries/LibJS/Makefile1
-rw-r--r--Libraries/LibJS/Parser.cpp9
-rw-r--r--Libraries/LibJS/Parser.h1
-rw-r--r--Libraries/LibJS/Runtime/Exception.cpp46
-rw-r--r--Libraries/LibJS/Runtime/Exception.h46
-rw-r--r--Libraries/LibJS/Token.h1
13 files changed, 160 insertions, 7 deletions
diff --git a/Base/home/anon/js/throw.js b/Base/home/anon/js/throw.js
new file mode 100644
index 0000000000..67c891f571
--- /dev/null
+++ b/Base/home/anon/js/throw.js
@@ -0,0 +1,5 @@
+try {
+ throw 123;
+} catch (e) {
+ console.log(e);
+}
diff --git a/Libraries/LibJS/AST.cpp b/Libraries/LibJS/AST.cpp
index b6d48ad82f..4528d4a4bd 100644
--- a/Libraries/LibJS/AST.cpp
+++ b/Libraries/LibJS/AST.cpp
@@ -480,7 +480,7 @@ Value Identifier::execute(Interpreter& interpreter) const
{
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 interpreter.throw_exception<Error>("ReferenceError", String::format("'%s' not known", string().characters()));
return value;
}
@@ -762,13 +762,19 @@ void CatchClause::dump(int indent) const
body().dump(indent + 1);
}
+void ThrowStatement::dump(int indent) const
+{
+ ASTNode::dump(indent);
+ argument().dump(indent + 1);
+}
+
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) } };
+ Vector<Argument> arguments { { m_handler->parameter(), exception->value() } };
interpreter.run(m_handler->body(), move(arguments));
}
}
@@ -786,4 +792,10 @@ Value CatchClause::execute(Interpreter&) const
return {};
}
+Value ThrowStatement::execute(Interpreter& interrupt) const
+{
+ auto value = m_argument->execute(interrupt);
+ return interrupt.throw_exception(value);
+}
+
}
diff --git a/Libraries/LibJS/AST.h b/Libraries/LibJS/AST.h
index 6a8e3f9f9c..34a3fd6b4c 100644
--- a/Libraries/LibJS/AST.h
+++ b/Libraries/LibJS/AST.h
@@ -675,4 +675,22 @@ private:
RefPtr<BlockStatement> m_finalizer;
};
+class ThrowStatement final : public Statement {
+public:
+ explicit ThrowStatement(NonnullRefPtr<Expression> argument)
+ : m_argument(move(argument))
+ {
+ }
+
+ const Expression& argument() const { return m_argument; }
+
+ virtual void dump(int indent) const override;
+ virtual Value execute(Interpreter&) const override;
+
+private:
+ virtual const char* class_name() const override { return "ThrowStatement"; }
+
+ NonnullRefPtr<Expression> m_argument;
+};
+
}
diff --git a/Libraries/LibJS/Forward.h b/Libraries/LibJS/Forward.h
index aa4079bc61..47ee9a13f9 100644
--- a/Libraries/LibJS/Forward.h
+++ b/Libraries/LibJS/Forward.h
@@ -32,6 +32,7 @@ class ASTNode;
class Argument;
class Cell;
class Error;
+class Exception;
class Expression;
class Function;
class HandleImpl;
diff --git a/Libraries/LibJS/Interpreter.cpp b/Libraries/LibJS/Interpreter.cpp
index 6a5bee1938..1dd5cc46db 100644
--- a/Libraries/LibJS/Interpreter.cpp
+++ b/Libraries/LibJS/Interpreter.cpp
@@ -188,7 +188,7 @@ Value Interpreter::call(Function* function, Value this_value, const Vector<Value
return result;
}
-Value Interpreter::throw_exception(Error* exception)
+Value Interpreter::throw_exception(Exception* exception)
{
m_exception = exception;
unwind(ScopeType::Try);
diff --git a/Libraries/LibJS/Interpreter.h b/Libraries/LibJS/Interpreter.h
index 6c2beecd9e..fe806f9a4f 100644
--- a/Libraries/LibJS/Interpreter.h
+++ b/Libraries/LibJS/Interpreter.h
@@ -26,12 +26,13 @@
#pragma once
+#include <AK/FlyString.h>
#include <AK/HashMap.h>
#include <AK/String.h>
-#include <AK/FlyString.h>
#include <AK/Vector.h>
#include <LibJS/Forward.h>
#include <LibJS/Heap/Heap.h>
+#include <LibJS/Runtime/Exception.h>
#include <LibJS/Runtime/Value.h>
namespace JS {
@@ -107,9 +108,20 @@ public:
Object* array_prototype() { return m_array_prototype; }
Object* error_prototype() { return m_error_prototype; }
- Error* exception() { return m_exception; }
+ Exception* exception() { return m_exception; }
void clear_exception() { m_exception = nullptr; }
- Value throw_exception(Error*);
+
+ template<typename T, typename... Args>
+ Value throw_exception(Args&&... args)
+ {
+ return throw_exception(heap().allocate<T>(forward<Args>(args)...));
+ }
+
+ Value throw_exception(Exception*);
+ Value throw_exception(Value value)
+ {
+ return throw_exception(heap().allocate<Exception>(value));
+ }
private:
Heap m_heap;
@@ -123,7 +135,7 @@ private:
Object* m_array_prototype { nullptr };
Object* m_error_prototype { nullptr };
- Error* m_exception { nullptr };
+ Exception* m_exception { nullptr };
ScopeType m_unwind_until { ScopeType::None };
};
diff --git a/Libraries/LibJS/Lexer.cpp b/Libraries/LibJS/Lexer.cpp
index 15aa4c8026..97ee8ec901 100644
--- a/Libraries/LibJS/Lexer.cpp
+++ b/Libraries/LibJS/Lexer.cpp
@@ -62,6 +62,7 @@ Lexer::Lexer(StringView source)
s_keywords.set("null", TokenType::NullLiteral);
s_keywords.set("undefined", TokenType::UndefinedLiteral);
s_keywords.set("return", TokenType::Return);
+ s_keywords.set("throw", TokenType::Throw);
s_keywords.set("true", TokenType::BoolLiteral);
s_keywords.set("try", TokenType::Try);
s_keywords.set("typeof", TokenType::Typeof);
diff --git a/Libraries/LibJS/Makefile b/Libraries/LibJS/Makefile
index fd0b255115..97d35be52d 100644
--- a/Libraries/LibJS/Makefile
+++ b/Libraries/LibJS/Makefile
@@ -12,6 +12,7 @@ OBJS = \
Runtime/ConsoleObject.o \
Runtime/Error.o \
Runtime/ErrorPrototype.o \
+ Runtime/Exception.o \
Runtime/Function.o \
Runtime/GlobalObject.o \
Runtime/MathObject.o \
diff --git a/Libraries/LibJS/Parser.cpp b/Libraries/LibJS/Parser.cpp
index 77e892e553..7b1769ac4a 100644
--- a/Libraries/LibJS/Parser.cpp
+++ b/Libraries/LibJS/Parser.cpp
@@ -197,6 +197,8 @@ NonnullRefPtr<Statement> Parser::parse_statement()
return parse_for_statement();
case TokenType::If:
return parse_if_statement();
+ case TokenType::Throw:
+ return parse_throw_statement();
case TokenType::Try:
return parse_try_statement();
default:
@@ -520,6 +522,12 @@ NonnullRefPtr<VariableDeclaration> Parser::parse_variable_declaration()
return create_ast_node<VariableDeclaration>(create_ast_node<Identifier>(name), move(initializer), declaration_type);
}
+NonnullRefPtr<ThrowStatement> Parser::parse_throw_statement()
+{
+ consume(TokenType::Throw);
+ return create_ast_node<ThrowStatement>(parse_expression(0));
+}
+
NonnullRefPtr<TryStatement> Parser::parse_try_statement()
{
consume(TokenType::Try);
@@ -700,6 +708,7 @@ bool Parser::match_statement() const
|| type == TokenType::Delete
|| type == TokenType::Do
|| type == TokenType::If
+ || type == TokenType::Throw
|| type == TokenType::Try
|| type == TokenType::While
|| type == TokenType::For
diff --git a/Libraries/LibJS/Parser.h b/Libraries/LibJS/Parser.h
index 7d131347b7..7cbd614b32 100644
--- a/Libraries/LibJS/Parser.h
+++ b/Libraries/LibJS/Parser.h
@@ -52,6 +52,7 @@ public:
NonnullRefPtr<VariableDeclaration> parse_variable_declaration();
NonnullRefPtr<ForStatement> parse_for_statement();
NonnullRefPtr<IfStatement> parse_if_statement();
+ NonnullRefPtr<ThrowStatement> parse_throw_statement();
NonnullRefPtr<TryStatement> parse_try_statement();
NonnullRefPtr<CatchClause> parse_catch_clause();
diff --git a/Libraries/LibJS/Runtime/Exception.cpp b/Libraries/LibJS/Runtime/Exception.cpp
new file mode 100644
index 0000000000..a11116a602
--- /dev/null
+++ b/Libraries/LibJS/Runtime/Exception.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/Runtime/Exception.h>
+
+namespace JS {
+
+Exception::Exception(Value value)
+ : m_value(value)
+{
+}
+
+Exception::~Exception()
+{
+}
+
+void Exception::visit_children(Visitor& visitor)
+{
+ Cell::visit_children(visitor);
+ visitor.visit(m_value);
+}
+
+}
diff --git a/Libraries/LibJS/Runtime/Exception.h b/Libraries/LibJS/Runtime/Exception.h
new file mode 100644
index 0000000000..14082c310f
--- /dev/null
+++ b/Libraries/LibJS/Runtime/Exception.h
@@ -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/Runtime/Cell.h>
+#include <LibJS/Runtime/Value.h>
+
+namespace JS {
+
+class Exception : public Cell {
+public:
+ explicit Exception(Value);
+ virtual ~Exception() override;
+
+ Value value() const { return m_value; }
+
+private:
+ virtual const char* class_name() const override { return "Exception"; }
+ virtual void visit_children(Visitor&) override;
+
+ Value m_value;
+};
+
+}
diff --git a/Libraries/LibJS/Token.h b/Libraries/LibJS/Token.h
index d278a6f4e5..880834d301 100644
--- a/Libraries/LibJS/Token.h
+++ b/Libraries/LibJS/Token.h
@@ -105,6 +105,7 @@ enum class TokenType {
Slash,
SlashEquals,
StringLiteral,
+ Throw,
Tilde,
Try,
Typeof,