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
Notes: sideshowbarker 2024-07-19 07:55:51 +09:00
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
{
interpreter.declare_variable(name().string(), m_declaration_type);
if (m_initializer) {
auto initalizer_result = m_initializer->execute(interpreter);
if (interpreter.exception())
return {};
interpreter.set_variable(name().string(), initalizer_result, true);
for (auto& declarator : m_declarations) {
interpreter.declare_variable(declarator.id().string(), m_declaration_type);
if (auto* init = declarator.init()) {
auto initalizer_result = init->execute(interpreter);
if (interpreter.exception())
return {};
interpreter.set_variable(declarator.id().string(), initalizer_result, true);
}
}
return {};
}
Value VariableDeclarator::execute(Interpreter &) const
{
// NOTE: This node is handled by VariableDeclaration.
ASSERT_NOT_REACHED();
}
void VariableDeclaration::dump(int indent) const
{
const char* declaration_type_string = nullptr;
@ -776,9 +783,17 @@ void VariableDeclaration::dump(int indent) const
ASTNode::dump(indent);
print_indent(indent + 1);
printf("%s\n", declaration_type_string);
m_name->dump(indent + 1);
if (m_initializer)
m_initializer->dump(indent + 1);
for (auto& declarator : m_declarations)
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

View file

@ -579,17 +579,36 @@ enum class DeclarationType {
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 {
public:
VariableDeclaration(NonnullRefPtr<Identifier> name, RefPtr<Expression> initializer, DeclarationType declaration_type)
VariableDeclaration(DeclarationType declaration_type, NonnullRefPtrVector<VariableDeclarator> declarations)
: m_declaration_type(declaration_type)
, m_name(move(name))
, m_initializer(move(initializer))
, m_declarations(move(declarations))
{
}
virtual bool is_variable_declaration() const override { return true; }
const Identifier& name() const { return *m_name; }
DeclarationType declaration_type() const { return m_declaration_type; }
virtual Value execute(Interpreter&) const override;
@ -599,8 +618,7 @@ private:
virtual const char* class_name() const override { return "VariableDeclaration"; }
DeclarationType m_declaration_type;
NonnullRefPtr<Identifier> m_name;
RefPtr<Expression> m_initializer;
NonnullRefPtrVector<VariableDeclarator> m_declarations;
};
class ObjectExpression : public Expression {

View file

@ -654,13 +654,23 @@ NonnullRefPtr<VariableDeclaration> Parser::parse_variable_declaration()
default:
ASSERT_NOT_REACHED();
}
auto name = consume(TokenType::Identifier).value();
RefPtr<Expression> initializer;
if (match(TokenType::Equals)) {
consume();
initializer = parse_expression(0);
NonnullRefPtrVector<VariableDeclarator> declarations;
for (;;) {
auto id = consume(TokenType::Identifier).value();
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()

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);
}