mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-22 07:30:19 +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:
parent
9691286cf0
commit
5e40aa182b
Notes:
sideshowbarker
2024-07-19 07:55:51 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/5e40aa182b9
4 changed files with 76 additions and 22 deletions
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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()
|
||||
|
|
11
Libraries/LibJS/Tests/var-multiple-declarator.js
Normal file
11
Libraries/LibJS/Tests/var-multiple-declarator.js
Normal 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);
|
||||
}
|
Loading…
Reference in a new issue