summaryrefslogtreecommitdiff
path: root/Libraries
diff options
context:
space:
mode:
authorAndreas Kling <kling@serenityos.org>2020-03-29 14:34:25 +0200
committerAndreas Kling <kling@serenityos.org>2020-03-29 15:03:58 +0200
commit2285f8459695c7522aa7ff8b3dd9074fc2ffdd4b (patch)
tree8ad4bb5bd19c57e6b3ca21558229765f6533dc0b /Libraries
parent1923051c5bb2add119e2c90a7a52e44c240813c6 (diff)
downloadserenity-2285f8459695c7522aa7ff8b3dd9074fc2ffdd4b.zip
LibJS: Implement basic execution of "switch" statements
The "break" keyword now unwinds to the nearest ScopeType::Breakable. There's no support for break labels yet, but we'll get there too.
Diffstat (limited to 'Libraries')
-rw-r--r--Libraries/LibJS/AST.cpp28
-rw-r--r--Libraries/LibJS/AST.h3
-rw-r--r--Libraries/LibJS/Interpreter.h2
-rw-r--r--Libraries/LibJS/Tests/switch-basic-2.js10
-rw-r--r--Libraries/LibJS/Tests/switch-basic-3.js6
-rw-r--r--Libraries/LibJS/Tests/switch-basic.js10
6 files changed, 57 insertions, 2 deletions
diff --git a/Libraries/LibJS/AST.cpp b/Libraries/LibJS/AST.cpp
index 81b224ccf2..b3daa4eb3b 100644
--- a/Libraries/LibJS/AST.cpp
+++ b/Libraries/LibJS/AST.cpp
@@ -873,7 +873,31 @@ Value ThrowStatement::execute(Interpreter& interpreter) const
Value SwitchStatement::execute(Interpreter& interpreter) const
{
- (void)interpreter;
+ auto discriminant_result = m_discriminant->execute(interpreter);
+ if (interpreter.exception())
+ return {};
+
+ bool falling_through = false;
+
+ for (auto& switch_case : m_cases) {
+ if (!falling_through && switch_case.test()) {
+ auto test_result = switch_case.test()->execute(interpreter);
+ if (interpreter.exception())
+ return {};
+ if (!eq(discriminant_result, test_result).to_boolean())
+ continue;
+ }
+ falling_through = true;
+
+ for (auto& statement : switch_case.consequent()) {
+ statement.execute(interpreter);
+ if (interpreter.exception())
+ return {};
+ if (interpreter.should_unwind())
+ return {};
+ }
+ }
+
return {};
}
@@ -885,7 +909,7 @@ Value SwitchCase::execute(Interpreter& interpreter) const
Value BreakStatement::execute(Interpreter& interpreter) const
{
- (void)interpreter;
+ interpreter.unwind(ScopeType::Breakable);
return {};
}
diff --git a/Libraries/LibJS/AST.h b/Libraries/LibJS/AST.h
index 4372fbe185..80138b2af5 100644
--- a/Libraries/LibJS/AST.h
+++ b/Libraries/LibJS/AST.h
@@ -715,6 +715,9 @@ public:
{
}
+ const Expression* test() const { return m_test; }
+ const NonnullRefPtrVector<Statement>& consequent() const { return m_consequent; }
+
virtual void dump(int indent) const override;
virtual Value execute(Interpreter&) const override;
diff --git a/Libraries/LibJS/Interpreter.h b/Libraries/LibJS/Interpreter.h
index 2485a83ea2..70e6af0d80 100644
--- a/Libraries/LibJS/Interpreter.h
+++ b/Libraries/LibJS/Interpreter.h
@@ -42,6 +42,7 @@ enum class ScopeType {
Function,
Block,
Try,
+ Breakable,
};
struct Variable {
@@ -78,6 +79,7 @@ public:
Heap& heap() { return m_heap; }
void unwind(ScopeType type) { m_unwind_until = type; }
+ bool should_unwind() const { return m_unwind_until != ScopeType::None; }
Optional<Value> get_variable(const FlyString& name);
void set_variable(const FlyString& name, Value, bool first_assignment = false);
diff --git a/Libraries/LibJS/Tests/switch-basic-2.js b/Libraries/LibJS/Tests/switch-basic-2.js
new file mode 100644
index 0000000000..1dbf35471d
--- /dev/null
+++ b/Libraries/LibJS/Tests/switch-basic-2.js
@@ -0,0 +1,10 @@
+var a = "foo";
+
+switch (a + "bar") {
+case 1:
+ break;
+case "foobar":
+case 2:
+ console.log("PASS");
+ break;
+}
diff --git a/Libraries/LibJS/Tests/switch-basic-3.js b/Libraries/LibJS/Tests/switch-basic-3.js
new file mode 100644
index 0000000000..e0d3de8e85
--- /dev/null
+++ b/Libraries/LibJS/Tests/switch-basic-3.js
@@ -0,0 +1,6 @@
+var a = "foo";
+
+switch (100) {
+default:
+ console.log("PASS");
+}
diff --git a/Libraries/LibJS/Tests/switch-basic.js b/Libraries/LibJS/Tests/switch-basic.js
new file mode 100644
index 0000000000..ea63230ab6
--- /dev/null
+++ b/Libraries/LibJS/Tests/switch-basic.js
@@ -0,0 +1,10 @@
+switch (1 + 2) {
+case 3:
+ console.log("PASS");
+ break;
+case 5:
+case 1:
+ break;
+default:
+ break;
+}