mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-22 07:30:19 +00:00
LibJS: Implement "else" parsing
We can now handle scripts with if/else in LibJS. Most of the changes are about fixing IfStatement to store the consequent and alternate node as Statements. Interpreter now also runs Statements, rather than running ScopeNodes.
This commit is contained in:
parent
b2f005125d
commit
fbb9e1b715
Notes:
sideshowbarker
2024-07-19 08:10:13 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/fbb9e1b7150
5 changed files with 31 additions and 16 deletions
|
@ -26,11 +26,11 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <AK/FlyString.h>
|
||||
#include <AK/HashMap.h>
|
||||
#include <AK/NonnullRefPtrVector.h>
|
||||
#include <AK/RefPtr.h>
|
||||
#include <AK/String.h>
|
||||
#include <AK/FlyString.h>
|
||||
#include <AK/Vector.h>
|
||||
#include <LibJS/Forward.h>
|
||||
#include <LibJS/Runtime/Value.h>
|
||||
|
@ -52,6 +52,7 @@ public:
|
|||
virtual void dump(int indent) const;
|
||||
virtual bool is_identifier() const { return false; }
|
||||
virtual bool is_member_expression() const { return false; }
|
||||
virtual bool is_scope_node() const { return false; }
|
||||
|
||||
protected:
|
||||
ASTNode() {}
|
||||
|
@ -107,6 +108,7 @@ protected:
|
|||
ScopeNode() {}
|
||||
|
||||
private:
|
||||
virtual bool is_scope_node() const final { return true; }
|
||||
NonnullRefPtrVector<Statement> m_children;
|
||||
};
|
||||
|
||||
|
@ -212,7 +214,7 @@ private:
|
|||
|
||||
class IfStatement : public Statement {
|
||||
public:
|
||||
IfStatement(NonnullRefPtr<Expression> predicate, NonnullRefPtr<ScopeNode> consequent, RefPtr<ScopeNode> alternate)
|
||||
IfStatement(NonnullRefPtr<Expression> predicate, NonnullRefPtr<Statement> consequent, RefPtr<Statement> alternate)
|
||||
: m_predicate(move(predicate))
|
||||
, m_consequent(move(consequent))
|
||||
, m_alternate(move(alternate))
|
||||
|
@ -220,8 +222,8 @@ public:
|
|||
}
|
||||
|
||||
const Expression& predicate() const { return *m_predicate; }
|
||||
const ScopeNode& consequent() const { return *m_consequent; }
|
||||
const ScopeNode* alternate() const { return m_alternate; }
|
||||
const Statement& consequent() const { return *m_consequent; }
|
||||
const Statement* alternate() const { return m_alternate; }
|
||||
|
||||
virtual Value execute(Interpreter&) const override;
|
||||
virtual void dump(int indent) const override;
|
||||
|
@ -230,8 +232,8 @@ private:
|
|||
virtual const char* class_name() const override { return "IfStatement"; }
|
||||
|
||||
NonnullRefPtr<Expression> m_predicate;
|
||||
NonnullRefPtr<ScopeNode> m_consequent;
|
||||
RefPtr<ScopeNode> m_alternate;
|
||||
NonnullRefPtr<Statement> m_consequent;
|
||||
RefPtr<Statement> m_alternate;
|
||||
};
|
||||
|
||||
class WhileStatement : public Statement {
|
||||
|
|
|
@ -40,6 +40,7 @@ class Interpreter;
|
|||
class Object;
|
||||
class PrimitiveString;
|
||||
class ScopeNode;
|
||||
class Statement;
|
||||
class Value;
|
||||
enum class DeclarationType;
|
||||
|
||||
|
|
|
@ -50,16 +50,20 @@ Interpreter::~Interpreter()
|
|||
{
|
||||
}
|
||||
|
||||
Value Interpreter::run(const ScopeNode& scope_node, Vector<Argument> arguments, ScopeType scope_type)
|
||||
Value Interpreter::run(const Statement& statement, Vector<Argument> arguments, ScopeType scope_type)
|
||||
{
|
||||
enter_scope(scope_node, move(arguments), scope_type);
|
||||
if (!statement.is_scope_node())
|
||||
return statement.execute(*this);
|
||||
|
||||
auto& block = static_cast<const BlockStatement&>(statement);
|
||||
enter_scope(block, move(arguments), scope_type);
|
||||
|
||||
Value last_value = js_undefined();
|
||||
for (auto& node : scope_node.children()) {
|
||||
for (auto& node : block.children()) {
|
||||
last_value = node.execute(*this);
|
||||
}
|
||||
|
||||
exit_scope(scope_node);
|
||||
exit_scope(block);
|
||||
return last_value;
|
||||
}
|
||||
|
||||
|
|
|
@ -67,7 +67,7 @@ public:
|
|||
Interpreter();
|
||||
~Interpreter();
|
||||
|
||||
Value run(const ScopeNode&, Vector<Argument> = {}, ScopeType = ScopeType::Block);
|
||||
Value run(const Statement&, Vector<Argument> = {}, ScopeType = ScopeType::Block);
|
||||
|
||||
Object& global_object() { return *m_global_object; }
|
||||
const Object& global_object() const { return *m_global_object; }
|
||||
|
|
|
@ -197,8 +197,12 @@ NonnullRefPtr<Statement> Parser::parse_statement()
|
|||
case TokenType::If:
|
||||
return parse_if_statement();
|
||||
default:
|
||||
if (match_expression())
|
||||
return adopt(*new ExpressionStatement(parse_expression(0)));
|
||||
if (match_expression()) {
|
||||
auto statement = adopt(*new ExpressionStatement(parse_expression(0)));
|
||||
if (match(TokenType::Semicolon))
|
||||
consume();
|
||||
return statement;
|
||||
}
|
||||
m_has_errors = true;
|
||||
expected("statement (missing switch case)");
|
||||
consume();
|
||||
|
@ -520,9 +524,13 @@ NonnullRefPtr<IfStatement> Parser::parse_if_statement()
|
|||
consume(TokenType::ParenOpen);
|
||||
auto predicate = parse_expression(0);
|
||||
consume(TokenType::ParenClose);
|
||||
auto consequent = parse_block_statement();
|
||||
// FIXME: Parse "else"
|
||||
return create_ast_node<IfStatement>(move(predicate), move(consequent), nullptr);
|
||||
auto consequent = parse_statement();
|
||||
RefPtr<Statement> alternate;
|
||||
if (match(TokenType::Else)) {
|
||||
consume(TokenType::Else);
|
||||
alternate = parse_statement();
|
||||
}
|
||||
return create_ast_node<IfStatement>(move(predicate), move(consequent), move(alternate));
|
||||
}
|
||||
|
||||
NonnullRefPtr<ForStatement> Parser::parse_for_statement()
|
||||
|
|
Loading…
Reference in a new issue