diff options
author | Andreas Kling <kling@serenityos.org> | 2020-03-29 14:34:25 +0200 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2020-03-29 15:03:58 +0200 |
commit | 2285f8459695c7522aa7ff8b3dd9074fc2ffdd4b (patch) | |
tree | 8ad4bb5bd19c57e6b3ca21558229765f6533dc0b /Libraries | |
parent | 1923051c5bb2add119e2c90a7a52e44c240813c6 (diff) | |
download | serenity-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.cpp | 28 | ||||
-rw-r--r-- | Libraries/LibJS/AST.h | 3 | ||||
-rw-r--r-- | Libraries/LibJS/Interpreter.h | 2 | ||||
-rw-r--r-- | Libraries/LibJS/Tests/switch-basic-2.js | 10 | ||||
-rw-r--r-- | Libraries/LibJS/Tests/switch-basic-3.js | 6 | ||||
-rw-r--r-- | Libraries/LibJS/Tests/switch-basic.js | 10 |
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; +} |