Browse Source

LibJS: Parse object expressions

0xtechnobabble 5 years ago
parent
commit
bc002f807a

+ 7 - 0
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);

+ 11 - 1
Libraries/LibJS/AST.cpp

@@ -623,6 +623,11 @@ void VariableDeclaration::dump(int indent) const
 void ObjectExpression::dump(int indent) const
 void ObjectExpression::dump(int indent) const
 {
 {
     ASTNode::dump(indent);
     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
 void ExpressionStatement::dump(int indent) const
@@ -633,7 +638,12 @@ void ExpressionStatement::dump(int indent) const
 
 
 Value ObjectExpression::execute(Interpreter& interpreter) const
 Value ObjectExpression::execute(Interpreter& interpreter) const
 {
 {
-    return interpreter.heap().allocate<Object>();
+    auto object = interpreter.heap().allocate<Object>();
+    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
 void MemberExpression::dump(int indent) const

+ 7 - 1
Libraries/LibJS/AST.h

@@ -26,6 +26,7 @@
 
 
 #pragma once
 #pragma once
 
 
+#include <AK/HashMap.h>
 #include <AK/NonnullRefPtrVector.h>
 #include <AK/NonnullRefPtrVector.h>
 #include <AK/RefPtr.h>
 #include <AK/RefPtr.h>
 #include <AK/String.h>
 #include <AK/String.h>
@@ -572,13 +573,18 @@ private:
 
 
 class ObjectExpression : public Expression {
 class ObjectExpression : public Expression {
 public:
 public:
-    ObjectExpression() {}
+    ObjectExpression(HashMap<String, NonnullRefPtr<Expression>> properties = {})
+        : m_properties(properties)
+    {
+    }
 
 
     virtual Value execute(Interpreter&) const override;
     virtual Value execute(Interpreter&) const override;
     virtual void dump(int indent) const override;
     virtual void dump(int indent) const override;
 
 
 private:
 private:
     virtual const char* class_name() const override { return "ObjectExpression"; }
     virtual const char* class_name() const override { return "ObjectExpression"; }
+
+    HashMap<String, NonnullRefPtr<Expression>> m_properties;
 };
 };
 
 
 class ArrayExpression : public Expression {
 class ArrayExpression : public Expression {

+ 1 - 0
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::BracketOpen);
         s_single_char_tokens.set(']', TokenType::BracketClose);
         s_single_char_tokens.set(']', TokenType::BracketClose);
         s_single_char_tokens.set('^', TokenType::Caret);
         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::Comma);
         s_single_char_tokens.set('{', TokenType::CurlyOpen);
         s_single_char_tokens.set('{', TokenType::CurlyOpen);
         s_single_char_tokens.set('}', TokenType::CurlyClose);
         s_single_char_tokens.set('}', TokenType::CurlyClose);

+ 19 - 2
Libraries/LibJS/Parser.cpp

@@ -269,10 +269,27 @@ NonnullRefPtr<Expression> Parser::parse_unary_prefixed_expression()
 
 
 NonnullRefPtr<ObjectExpression> Parser::parse_object_expression()
 NonnullRefPtr<ObjectExpression> Parser::parse_object_expression()
 {
 {
-    // FIXME: Parse actual object expression
+    HashMap<String, NonnullRefPtr<Expression>> properties;
     consume(TokenType::CurlyOpen);
     consume(TokenType::CurlyOpen);
+
+    while (!match(TokenType::CurlyClose)) {
+        auto identifier = create_ast_node<Identifier>(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);
     consume(TokenType::CurlyClose);
-    return create_ast_node<ObjectExpression>();
+    return create_ast_node<ObjectExpression>(properties);
 }
 }
 
 
 NonnullRefPtr<ArrayExpression> Parser::parse_array_expression()
 NonnullRefPtr<ArrayExpression> Parser::parse_array_expression()

+ 2 - 0
Libraries/LibJS/Token.cpp

@@ -57,6 +57,8 @@ const char* Token::name(TokenType type)
         return "Catch";
         return "Catch";
     case TokenType::Class:
     case TokenType::Class:
         return "Class";
         return "Class";
+    case TokenType::Colon:
+        return "Colon";
     case TokenType::Comma:
     case TokenType::Comma:
         return "Comma";
         return "Comma";
     case TokenType::Const:
     case TokenType::Const:

+ 1 - 0
Libraries/LibJS/Token.h

@@ -44,6 +44,7 @@ enum class TokenType {
     Caret,
     Caret,
     Catch,
     Catch,
     Class,
     Class,
+    Colon,
     Comma,
     Comma,
     Const,
     Const,
     CurlyClose,
     CurlyClose,