1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 00:57:43 +00:00

LibJS: Support VariableDeclaration with multiple declarators

This patch adds support in the parser and interpreter for this:

    var a = 1, b = 2, c = a + b;

VariableDeclaration is now a sequence of VariableDeclarators. :^)
This commit is contained in:
Andreas Kling 2020-04-04 21:46:25 +02:00
parent 9691286cf0
commit 5e40aa182b
4 changed files with 76 additions and 22 deletions

View file

@ -747,17 +747,24 @@ void UpdateExpression::dump(int indent) const
Value VariableDeclaration::execute(Interpreter& interpreter) const Value VariableDeclaration::execute(Interpreter& interpreter) const
{ {
interpreter.declare_variable(name().string(), m_declaration_type); for (auto& declarator : m_declarations) {
if (m_initializer) { interpreter.declare_variable(declarator.id().string(), m_declaration_type);
auto initalizer_result = m_initializer->execute(interpreter); if (auto* init = declarator.init()) {
if (interpreter.exception()) auto initalizer_result = init->execute(interpreter);
return {}; if (interpreter.exception())
interpreter.set_variable(name().string(), initalizer_result, true); return {};
interpreter.set_variable(declarator.id().string(), initalizer_result, true);
}
} }
return {}; return {};
} }
Value VariableDeclarator::execute(Interpreter &) const
{
// NOTE: This node is handled by VariableDeclaration.
ASSERT_NOT_REACHED();
}
void VariableDeclaration::dump(int indent) const void VariableDeclaration::dump(int indent) const
{ {
const char* declaration_type_string = nullptr; const char* declaration_type_string = nullptr;
@ -776,9 +783,17 @@ void VariableDeclaration::dump(int indent) const
ASTNode::dump(indent); ASTNode::dump(indent);
print_indent(indent + 1); print_indent(indent + 1);
printf("%s\n", declaration_type_string); printf("%s\n", declaration_type_string);
m_name->dump(indent + 1);
if (m_initializer) for (auto& declarator : m_declarations)
m_initializer->dump(indent + 1); declarator.dump(indent + 1);
}
void VariableDeclarator::dump(int indent) const
{
ASTNode::dump(indent);
m_id->dump(indent + 1);
if (m_init)
m_init->dump(indent + 1);
} }
void ObjectExpression::dump(int indent) const void ObjectExpression::dump(int indent) const

View file

@ -579,17 +579,36 @@ enum class DeclarationType {
Const, Const,
}; };
class VariableDeclarator final : public ASTNode {
public:
VariableDeclarator(NonnullRefPtr<Identifier> id, RefPtr<Expression> init)
: m_id(move(id))
, m_init(move(init))
{
}
const Identifier& id() const { return m_id; }
const Expression* init() const { return m_init; }
virtual Value execute(Interpreter&) const override;
virtual void dump(int indent) const override;
private:
virtual const char* class_name() const override { return "VariableDeclarator"; }
NonnullRefPtr<Identifier> m_id;
RefPtr<Expression> m_init;
};
class VariableDeclaration : public Declaration { class VariableDeclaration : public Declaration {
public: public:
VariableDeclaration(NonnullRefPtr<Identifier> name, RefPtr<Expression> initializer, DeclarationType declaration_type) VariableDeclaration(DeclarationType declaration_type, NonnullRefPtrVector<VariableDeclarator> declarations)
: m_declaration_type(declaration_type) : m_declaration_type(declaration_type)
, m_name(move(name)) , m_declarations(move(declarations))
, m_initializer(move(initializer))
{ {
} }
virtual bool is_variable_declaration() const override { return true; } virtual bool is_variable_declaration() const override { return true; }
const Identifier& name() const { return *m_name; }
DeclarationType declaration_type() const { return m_declaration_type; } DeclarationType declaration_type() const { return m_declaration_type; }
virtual Value execute(Interpreter&) const override; virtual Value execute(Interpreter&) const override;
@ -599,8 +618,7 @@ private:
virtual const char* class_name() const override { return "VariableDeclaration"; } virtual const char* class_name() const override { return "VariableDeclaration"; }
DeclarationType m_declaration_type; DeclarationType m_declaration_type;
NonnullRefPtr<Identifier> m_name; NonnullRefPtrVector<VariableDeclarator> m_declarations;
RefPtr<Expression> m_initializer;
}; };
class ObjectExpression : public Expression { class ObjectExpression : public Expression {

View file

@ -654,13 +654,23 @@ NonnullRefPtr<VariableDeclaration> Parser::parse_variable_declaration()
default: default:
ASSERT_NOT_REACHED(); ASSERT_NOT_REACHED();
} }
auto name = consume(TokenType::Identifier).value();
RefPtr<Expression> initializer; NonnullRefPtrVector<VariableDeclarator> declarations;
if (match(TokenType::Equals)) { for (;;) {
consume(); auto id = consume(TokenType::Identifier).value();
initializer = parse_expression(0); RefPtr<Expression> init;
if (match(TokenType::Equals)) {
consume();
init = parse_expression(0);
}
declarations.append(create_ast_node<VariableDeclarator>(create_ast_node<Identifier>(move(id)), move(init)));
if (match(TokenType::Comma)) {
consume();
continue;
}
break;
} }
return create_ast_node<VariableDeclaration>(create_ast_node<Identifier>(name), move(initializer), declaration_type); return create_ast_node<VariableDeclaration>(declaration_type, move(declarations));
} }
NonnullRefPtr<ThrowStatement> Parser::parse_throw_statement() NonnullRefPtr<ThrowStatement> Parser::parse_throw_statement()

View file

@ -0,0 +1,11 @@
function assert(x) { if (!x) throw 1; }
try {
var a = 1, b = 2, c = a + b;
assert(a === 1);
assert(b === 2);
assert(c === 3);
console.log("PASS");
} catch (e) {
console.log("FAIL: " + e);
}