diff --git a/Base/home/anon/js/object-expression.js b/Base/home/anon/js/object-expression.js new file mode 100644 index 0000000000..58449a2c0a --- /dev/null +++ b/Base/home/anon/js/object-expression.js @@ -0,0 +1,7 @@ +const a = 1; +const object = {a, b: 2}; +const emptyObject = {}; + +console.log(object.a); +console.log(object.b); +console.log(emptyObject.foo); diff --git a/Libraries/LibJS/AST.cpp b/Libraries/LibJS/AST.cpp index 2a077f8133..95cb322e74 100644 --- a/Libraries/LibJS/AST.cpp +++ b/Libraries/LibJS/AST.cpp @@ -623,6 +623,11 @@ void VariableDeclaration::dump(int indent) const void ObjectExpression::dump(int indent) const { ASTNode::dump(indent); + for (String property_key : m_properties.keys()) { + print_indent(indent + 1); + printf("%s: ", property_key.characters()); + m_properties.get(property_key).value()->dump(0); + } } void ExpressionStatement::dump(int indent) const @@ -633,7 +638,12 @@ void ExpressionStatement::dump(int indent) const Value ObjectExpression::execute(Interpreter& interpreter) const { - return interpreter.heap().allocate(); + auto object = interpreter.heap().allocate(); + for (String property_key : m_properties.keys()) { + object->put(property_key, m_properties.get(property_key).value()->execute(interpreter)); + } + + return object; } void MemberExpression::dump(int indent) const diff --git a/Libraries/LibJS/AST.h b/Libraries/LibJS/AST.h index b4943caa59..e8a0039ad8 100644 --- a/Libraries/LibJS/AST.h +++ b/Libraries/LibJS/AST.h @@ -26,6 +26,7 @@ #pragma once +#include #include #include #include @@ -572,13 +573,18 @@ private: class ObjectExpression : public Expression { public: - ObjectExpression() {} + ObjectExpression(HashMap> properties = {}) + : m_properties(properties) + { + } virtual Value execute(Interpreter&) const override; virtual void dump(int indent) const override; private: virtual const char* class_name() const override { return "ObjectExpression"; } + + HashMap> m_properties; }; class ArrayExpression : public Expression { diff --git a/Libraries/LibJS/Lexer.cpp b/Libraries/LibJS/Lexer.cpp index 3f59ea1867..a7564f9b46 100644 --- a/Libraries/LibJS/Lexer.cpp +++ b/Libraries/LibJS/Lexer.cpp @@ -107,6 +107,7 @@ Lexer::Lexer(StringView source) s_single_char_tokens.set('[', TokenType::BracketOpen); s_single_char_tokens.set(']', TokenType::BracketClose); s_single_char_tokens.set('^', TokenType::Caret); + s_single_char_tokens.set(':', TokenType::Colon); s_single_char_tokens.set(',', TokenType::Comma); s_single_char_tokens.set('{', TokenType::CurlyOpen); s_single_char_tokens.set('}', TokenType::CurlyClose); diff --git a/Libraries/LibJS/Parser.cpp b/Libraries/LibJS/Parser.cpp index bd02564ad8..badcd97268 100644 --- a/Libraries/LibJS/Parser.cpp +++ b/Libraries/LibJS/Parser.cpp @@ -269,10 +269,27 @@ NonnullRefPtr Parser::parse_unary_prefixed_expression() NonnullRefPtr Parser::parse_object_expression() { - // FIXME: Parse actual object expression + HashMap> properties; consume(TokenType::CurlyOpen); + + while (!match(TokenType::CurlyClose)) { + auto identifier = create_ast_node(consume(TokenType::Identifier).value()); + + if (match(TokenType::Colon)) { + consume(TokenType::Colon); + properties.set(identifier->string(), parse_expression(0)); + } else { + properties.set(identifier->string(), identifier); + } + + if (!match(TokenType::Comma)) + break; + + consume(TokenType::Comma); + } + consume(TokenType::CurlyClose); - return create_ast_node(); + return create_ast_node(properties); } NonnullRefPtr Parser::parse_array_expression() diff --git a/Libraries/LibJS/Token.cpp b/Libraries/LibJS/Token.cpp index a578122d4d..c1902d4e13 100644 --- a/Libraries/LibJS/Token.cpp +++ b/Libraries/LibJS/Token.cpp @@ -57,6 +57,8 @@ const char* Token::name(TokenType type) return "Catch"; case TokenType::Class: return "Class"; + case TokenType::Colon: + return "Colon"; case TokenType::Comma: return "Comma"; case TokenType::Const: diff --git a/Libraries/LibJS/Token.h b/Libraries/LibJS/Token.h index fe120d0212..d278a6f4e5 100644 --- a/Libraries/LibJS/Token.h +++ b/Libraries/LibJS/Token.h @@ -44,6 +44,7 @@ enum class TokenType { Caret, Catch, Class, + Colon, Comma, Const, CurlyClose,