LibJS: Add support for "continue" inside "for" statements :^)

This commit is contained in:
Andreas Kling 2020-04-05 00:22:42 +02:00
parent e3b92caa6d
commit 9ebd066ac8
Notes: sideshowbarker 2024-07-19 07:55:21 +09:00
8 changed files with 65 additions and 1 deletions

View file

@ -215,6 +215,16 @@ Value ForStatement::execute(Interpreter& interpreter) const
last_value = interpreter.run(*m_body);
if (interpreter.exception())
return {};
if (interpreter.should_unwind()) {
if (interpreter.should_unwind_until(ScopeType::Continuable)) {
interpreter.stop_unwind();
} else if (interpreter.should_unwind_until(ScopeType::Breakable)) {
interpreter.stop_unwind();
break;
} else {
return {};
}
}
if (m_update) {
m_update->execute(interpreter);
if (interpreter.exception())
@ -226,6 +236,16 @@ Value ForStatement::execute(Interpreter& interpreter) const
last_value = interpreter.run(*m_body);
if (interpreter.exception())
return {};
if (interpreter.should_unwind()) {
if (interpreter.should_unwind_until(ScopeType::Continuable)) {
interpreter.stop_unwind();
} else if (interpreter.should_unwind_until(ScopeType::Breakable)) {
interpreter.stop_unwind();
break;
} else {
return {};
}
}
if (m_update) {
m_update->execute(interpreter);
if (interpreter.exception())
@ -759,7 +779,7 @@ Value VariableDeclaration::execute(Interpreter& interpreter) const
return {};
}
Value VariableDeclarator::execute(Interpreter &) const
Value VariableDeclarator::execute(Interpreter&) const
{
// NOTE: This node is handled by VariableDeclaration.
ASSERT_NOT_REACHED();
@ -1005,6 +1025,12 @@ Value BreakStatement::execute(Interpreter& interpreter) const
return {};
}
Value ContinueStatement::execute(Interpreter& interpreter) const
{
interpreter.unwind(ScopeType::Continuable);
return {};
}
void SwitchStatement::dump(int indent) const
{
ASTNode::dump(indent);

View file

@ -814,4 +814,14 @@ private:
virtual const char* class_name() const override { return "BreakStatement"; }
};
class ContinueStatement final : public Statement {
public:
ContinueStatement() {}
virtual Value execute(Interpreter&) const override;
private:
virtual const char* class_name() const override { return "ContinueStatement"; }
};
}

View file

@ -43,6 +43,7 @@ enum class ScopeType {
Block,
Try,
Breakable,
Continuable,
};
struct Variable {

View file

@ -48,6 +48,7 @@ Lexer::Lexer(StringView source)
s_keywords.set("catch", TokenType::Catch);
s_keywords.set("class", TokenType::Class);
s_keywords.set("const", TokenType::Const);
s_keywords.set("continue", TokenType::Continue);
s_keywords.set("default", TokenType::Default);
s_keywords.set("delete", TokenType::Delete);
s_keywords.set("do", TokenType::Do);

View file

@ -208,6 +208,8 @@ NonnullRefPtr<Statement> Parser::parse_statement()
return parse_try_statement();
case TokenType::Break:
return parse_break_statement();
case TokenType::Continue:
return parse_continue_statement();
case TokenType::Switch:
return parse_switch_statement();
case TokenType::Do:
@ -686,6 +688,13 @@ NonnullRefPtr<BreakStatement> Parser::parse_break_statement()
return create_ast_node<BreakStatement>();
}
NonnullRefPtr<ContinueStatement> Parser::parse_continue_statement()
{
consume(TokenType::Continue);
// FIXME: Handle labels.
return create_ast_node<ContinueStatement>();
}
NonnullRefPtr<ConditionalExpression> Parser::parse_conditional_expression(NonnullRefPtr<Expression> test)
{
consume(TokenType::QuestionMark);
@ -938,6 +947,7 @@ bool Parser::match_statement() const
|| type == TokenType::CurlyOpen
|| type == TokenType::Switch
|| type == TokenType::Break
|| type == TokenType::Continue
|| type == TokenType::Var;
}

View file

@ -58,6 +58,7 @@ public:
NonnullRefPtr<SwitchStatement> parse_switch_statement();
NonnullRefPtr<SwitchCase> parse_switch_case();
NonnullRefPtr<BreakStatement> parse_break_statement();
NonnullRefPtr<ContinueStatement> parse_continue_statement();
NonnullRefPtr<DoWhileStatement> parse_do_while_statement();
NonnullRefPtr<ConditionalExpression> parse_conditional_expression(NonnullRefPtr<Expression> test);

View file

@ -0,0 +1,14 @@
function assert(x) { if (!x) throw 1; }
try {
var j = 0;
for (var i = 0; i < 9; ++i) {
if (i == 3)
continue;
++j;
}
assert(j == 8);
console.log("PASS");
} catch {
}

View file

@ -50,6 +50,7 @@ namespace JS {
__ENUMERATE_JS_TOKEN(Colon) \
__ENUMERATE_JS_TOKEN(Comma) \
__ENUMERATE_JS_TOKEN(Const) \
__ENUMERATE_JS_TOKEN(Continue) \
__ENUMERATE_JS_TOKEN(CurlyClose) \
__ENUMERATE_JS_TOKEN(CurlyOpen) \
__ENUMERATE_JS_TOKEN(Default) \