diff options
author | Andreas Kling <kling@serenityos.org> | 2020-03-20 20:51:03 +0100 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2020-03-20 21:56:40 +0100 |
commit | a3d2e074466598598ce1b3b8dadbb7c22c54b0a8 (patch) | |
tree | 99cb6578eb77d467360d8060875ba7cbd1a1ebb1 | |
parent | 86642add2facc03297abbdb857e0a127cc51295f (diff) | |
download | serenity-a3d2e074466598598ce1b3b8dadbb7c22c54b0a8.zip |
LibJS: Parse computed MemberExpressions
MemberExpression comes in two flavors:
computed: a[b]
non-computed: a.b
We can now parse both of the types. :^)
-rw-r--r-- | Libraries/LibJS/AST.cpp | 24 | ||||
-rw-r--r-- | Libraries/LibJS/AST.h | 7 | ||||
-rw-r--r-- | Libraries/LibJS/Parser.cpp | 7 |
3 files changed, 26 insertions, 12 deletions
diff --git a/Libraries/LibJS/AST.cpp b/Libraries/LibJS/AST.cpp index 216b7758b5..99087bc5f0 100644 --- a/Libraries/LibJS/AST.cpp +++ b/Libraries/LibJS/AST.cpp @@ -480,7 +480,7 @@ Value AssignmentExpression::execute(Interpreter& interpreter) const commit = [&](Value value) { auto object = static_cast<const MemberExpression&>(*m_lhs).object().execute(interpreter).to_object(interpreter.heap()); ASSERT(object.is_object()); - auto property_name = static_cast<const Identifier&>(static_cast<const MemberExpression&>(*m_lhs).property()).string(); + auto property_name = static_cast<const MemberExpression&>(*m_lhs).computed_property_name(interpreter); object.as_object()->put(property_name, value); }; } else { @@ -638,24 +638,26 @@ Value ObjectExpression::execute(Interpreter& interpreter) const void MemberExpression::dump(int indent) const { - ASTNode::dump(indent); + print_indent(indent); + printf("%s (computed=%s)\n", class_name(), is_computed() ? "true" : "false"); m_object->dump(indent + 1); m_property->dump(indent + 1); } +String MemberExpression::computed_property_name(Interpreter& interpreter) const +{ + if (!is_computed()) { + ASSERT(m_property->is_identifier()); + return static_cast<const Identifier&>(*m_property).string(); + } + return m_property->execute(interpreter).to_string(); +} + Value MemberExpression::execute(Interpreter& interpreter) const { auto object_result = m_object->execute(interpreter).to_object(interpreter.heap()); ASSERT(object_result.is_object()); - - String property_name; - if (m_property->is_identifier()) { - property_name = static_cast<const Identifier&>(*m_property).string(); - } else { - ASSERT_NOT_REACHED(); - } - - return object_result.as_object()->get(property_name); + return object_result.as_object()->get(computed_property_name(interpreter)); } Value StringLiteral::execute(Interpreter& interpreter) const diff --git a/Libraries/LibJS/AST.h b/Libraries/LibJS/AST.h index eb5847a59f..b4943caa59 100644 --- a/Libraries/LibJS/AST.h +++ b/Libraries/LibJS/AST.h @@ -601,24 +601,29 @@ private: class MemberExpression final : public Expression { public: - MemberExpression(NonnullRefPtr<Expression> object, NonnullRefPtr<Expression> property) + MemberExpression(NonnullRefPtr<Expression> object, NonnullRefPtr<Expression> property, bool computed = false) : m_object(move(object)) , m_property(move(property)) + , m_computed(computed) { } virtual Value execute(Interpreter&) const override; virtual void dump(int indent) const override; + bool is_computed() const { return m_computed; } const Expression& object() const { return *m_object; } const Expression& property() const { return *m_property; } + String computed_property_name(Interpreter&) const; + private: virtual bool is_member_expression() const override { return true; } virtual const char* class_name() const override { return "MemberExpression"; } NonnullRefPtr<Expression> m_object; NonnullRefPtr<Expression> m_property; + bool m_computed { false }; }; } diff --git a/Libraries/LibJS/Parser.cpp b/Libraries/LibJS/Parser.cpp index 6e3a3935b0..bd02564ad8 100644 --- a/Libraries/LibJS/Parser.cpp +++ b/Libraries/LibJS/Parser.cpp @@ -369,6 +369,12 @@ NonnullRefPtr<Expression> Parser::parse_secondary_expression(NonnullRefPtr<Expre case TokenType::Period: consume(); return create_ast_node<MemberExpression>(move(lhs), parse_expression(min_precedence, associativity)); + case TokenType::BracketOpen: { + consume(TokenType::BracketOpen); + auto expression = create_ast_node<MemberExpression>(move(lhs), parse_expression(min_precedence, associativity), true); + consume(TokenType::BracketClose); + return expression; + } case TokenType::PlusPlus: consume(); return create_ast_node<UpdateExpression>(UpdateOp::Increment, move(lhs)); @@ -587,6 +593,7 @@ bool Parser::match_secondary_expression() const || type == TokenType::LessThanEquals || type == TokenType::ParenOpen || type == TokenType::Period + || type == TokenType::BracketOpen || type == TokenType::PlusPlus || type == TokenType::MinusMinus; } |