summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Kling <kling@serenityos.org>2020-03-23 19:19:03 +0100
committerAndreas Kling <kling@serenityos.org>2020-03-23 19:22:24 +0100
commit494df529613e1b68619281c6b0cfa6729dac375f (patch)
treede485734e83fb4207fd7bfaaa15ffcf3f1634274
parentdf524203b2ebbe16356e594e9cd6ab845caa15dd (diff)
downloadserenity-494df529613e1b68619281c6b0cfa6729dac375f.zip
LibJS: Actually leave the current function scope on "return"
We now unwind until the nearest function-level scope on the scope stack when executing a return statement.
-rw-r--r--Libraries/LibJS/AST.cpp2
-rw-r--r--Libraries/LibJS/Interpreter.cpp12
-rw-r--r--Libraries/LibJS/Interpreter.h5
3 files changed, 13 insertions, 6 deletions
diff --git a/Libraries/LibJS/AST.cpp b/Libraries/LibJS/AST.cpp
index d3b34dc027..f89b3b0f5a 100644
--- a/Libraries/LibJS/AST.cpp
+++ b/Libraries/LibJS/AST.cpp
@@ -81,7 +81,7 @@ Value CallExpression::execute(Interpreter& interpreter) const
Value ReturnStatement::execute(Interpreter& interpreter) const
{
auto value = argument() ? argument()->execute(interpreter) : js_undefined();
- interpreter.do_return();
+ interpreter.unwind(ScopeType::Function);
return value;
}
diff --git a/Libraries/LibJS/Interpreter.cpp b/Libraries/LibJS/Interpreter.cpp
index ac80f688b0..f602336bc4 100644
--- a/Libraries/LibJS/Interpreter.cpp
+++ b/Libraries/LibJS/Interpreter.cpp
@@ -61,8 +61,13 @@ Value Interpreter::run(const Statement& statement, Vector<Argument> arguments, S
Value last_value = js_undefined();
for (auto& node : block.children()) {
last_value = node.execute(*this);
+ if (m_unwind_until != ScopeType::None)
+ break;
}
+ if (m_unwind_until == scope_type)
+ m_unwind_until = ScopeType::None;
+
exit_scope(block);
return last_value;
}
@@ -80,11 +85,10 @@ void Interpreter::exit_scope(const ScopeNode& scope_node)
{
while (m_scope_stack.last().scope_node.ptr() != &scope_node)
m_scope_stack.take_last();
-}
-void Interpreter::do_return()
-{
- dbg() << "FIXME: Implement Interpreter::do_return()";
+ // If we unwind all the way, just reset m_unwind_until so that future "return" doesn't break.
+ if (m_scope_stack.is_empty())
+ m_unwind_until = ScopeType::None;
}
void Interpreter::declare_variable(const FlyString& name, DeclarationType declaration_type)
diff --git a/Libraries/LibJS/Interpreter.h b/Libraries/LibJS/Interpreter.h
index 1aa7b87f05..fab56397d1 100644
--- a/Libraries/LibJS/Interpreter.h
+++ b/Libraries/LibJS/Interpreter.h
@@ -37,6 +37,7 @@
namespace JS {
enum class ScopeType {
+ None,
Function,
Block,
};
@@ -74,7 +75,7 @@ public:
Heap& heap() { return m_heap; }
- void do_return();
+ void unwind(ScopeType type) { m_unwind_until = type; }
Value get_variable(const FlyString& name);
void set_variable(const FlyString& name, Value, bool first_assignment = false);
@@ -114,6 +115,8 @@ private:
Object* m_string_prototype { nullptr };
Object* m_object_prototype { nullptr };
Object* m_array_prototype { nullptr };
+
+ ScopeType m_unwind_until { ScopeType::None };
};
}