From ea9af87ba4399d094180f06be59c878d864a17e0 Mon Sep 17 00:00:00 2001
From: Ferenc Szontágh <szf@fsociety.hu>
Date: Sat, 19 Apr 2025 17:06:48 +0000
Subject: [PATCH] implemented array, added some new builtin functions

---
 src/Parser/Parser.cpp |  155 ++++++++++++++++++++++++++++++++++++++++-----------
 1 files changed, 121 insertions(+), 34 deletions(-)

diff --git a/src/Parser/Parser.cpp b/src/Parser/Parser.cpp
index baff197..1ec0322 100644
--- a/src/Parser/Parser.cpp
+++ b/src/Parser/Parser.cpp
@@ -55,8 +55,15 @@
 void Parser::parseVariableDefinition() {
     Symbols::Variables::Type var_type = parseType();
 
-    Lexer::Tokens::Token id_token = expect(Lexer::Tokens::Type::VARIABLE_IDENTIFIER);
-    std::string          var_name = id_token.value;
+    // Variable name: allow names with or without leading '$'
+    Lexer::Tokens::Token id_token;
+    if (currentToken().type == Lexer::Tokens::Type::VARIABLE_IDENTIFIER ||
+        currentToken().type == Lexer::Tokens::Type::IDENTIFIER) {
+        id_token = consumeToken();
+    } else {
+        reportError("Expected variable name", currentToken());
+    }
+    std::string var_name = id_token.value;
 
     if (!var_name.empty() && var_name[0] == '$') {
         var_name = var_name.substr(1);
@@ -154,23 +161,39 @@
 std::unique_ptr<Interpreter::StatementNode> Parser::parseForStatementNode() {
     auto forToken = expect(Lexer::Tokens::Type::KEYWORD, "for");
     expect(Lexer::Tokens::Type::PUNCTUATION, "(");
-    Symbols::Variables::Type keyType = parseType();
-    auto                     keyTok  = expect(Lexer::Tokens::Type::VARIABLE_IDENTIFIER);
-    std::string              keyName = keyTok.value;
-    if (!keyName.empty() && keyName[0] == '$') {
-        keyName = keyName.substr(1);
+    // Parse element type and variable name
+    Symbols::Variables::Type elemType = parseType();
+    auto firstTok = expect(Lexer::Tokens::Type::VARIABLE_IDENTIFIER);
+    std::string firstName = firstTok.value;
+    if (!firstName.empty() && firstName[0] == '$') {
+        firstName = firstName.substr(1);
     }
-    expect(Lexer::Tokens::Type::PUNCTUATION, ",");
-    if (!(currentToken().type == Lexer::Tokens::Type::IDENTIFIER && currentToken().value == "auto")) {
-        reportError("Expected 'auto' in for-in loop");
+    // Determine loop form: key,value or simple element loop
+    std::string keyName, valName;
+    Symbols::Variables::Type keyType;
+    if (match(Lexer::Tokens::Type::PUNCTUATION, ",")) {
+        // Key, value syntax
+        keyType = elemType;
+        keyName = firstName;
+        // Expect 'auto' for value variable
+        if (!(currentToken().type == Lexer::Tokens::Type::IDENTIFIER && currentToken().value == "auto")) {
+            reportError("Expected 'auto' in for-in loop");
+        }
+        consumeToken();
+        auto valTok = expect(Lexer::Tokens::Type::VARIABLE_IDENTIFIER);
+        valName = valTok.value;
+        if (!valName.empty() && valName[0] == '$') {
+            valName = valName.substr(1);
+        }
+        expect(Lexer::Tokens::Type::PUNCTUATION, ":");
+    } else if (match(Lexer::Tokens::Type::PUNCTUATION, ":")) {
+        // Simple element loop
+        keyType = elemType;
+        keyName = firstName;
+        valName = firstName;
+    } else {
+        reportError("Expected ',' or ':' in for-in loop");
     }
-    consumeToken();
-    auto        valTok  = expect(Lexer::Tokens::Type::VARIABLE_IDENTIFIER);
-    std::string valName = valTok.value;
-    if (!valName.empty() && valName[0] == '$') {
-        valName = valName.substr(1);
-    }
-    expect(Lexer::Tokens::Type::PUNCTUATION, ":");
     auto iterableExpr = parseParsedExpression(Symbols::Variables::Type::NULL_TYPE);
     expect(Lexer::Tokens::Type::PUNCTUATION, ")");
     expect(Lexer::Tokens::Type::PUNCTUATION, "{");
@@ -401,25 +424,39 @@
     // 'for'
     auto forToken = expect(Lexer::Tokens::Type::KEYWORD, "for");
     expect(Lexer::Tokens::Type::PUNCTUATION, "(");
-    // Parse key type and name
-    Symbols::Variables::Type keyType = parseType();
-    auto                     keyTok  = expect(Lexer::Tokens::Type::VARIABLE_IDENTIFIER);
-    std::string              keyName = keyTok.value;
-    if (!keyName.empty() && keyName[0] == '$') {
-        keyName = keyName.substr(1);
+    // Parse element type and variable name
+    Symbols::Variables::Type elemType = parseType();
+    auto firstTok = expect(Lexer::Tokens::Type::VARIABLE_IDENTIFIER);
+    std::string firstName = firstTok.value;
+    if (!firstName.empty() && firstName[0] == '$') {
+        firstName = firstName.substr(1);
     }
-    expect(Lexer::Tokens::Type::PUNCTUATION, ",");
-    // Parse 'auto' keyword for value
-    if (!(currentToken().type == Lexer::Tokens::Type::IDENTIFIER && currentToken().value == "auto")) {
-        reportError("Expected 'auto' in for-in loop");
+    // Determine loop form: key,value or simple element loop
+    std::string keyName, valName;
+    Symbols::Variables::Type keyType;
+    if (match(Lexer::Tokens::Type::PUNCTUATION, ",")) {
+        // Key, value syntax
+        keyType = elemType;
+        keyName = firstName;
+        // Expect 'auto' for value variable
+        if (!(currentToken().type == Lexer::Tokens::Type::IDENTIFIER && currentToken().value == "auto")) {
+            reportError("Expected 'auto' in for-in loop");
+        }
+        consumeToken();
+        auto valTok = expect(Lexer::Tokens::Type::VARIABLE_IDENTIFIER);
+        valName = valTok.value;
+        if (!valName.empty() && valName[0] == '$') {
+            valName = valName.substr(1);
+        }
+        expect(Lexer::Tokens::Type::PUNCTUATION, ":");
+    } else if (match(Lexer::Tokens::Type::PUNCTUATION, ":")) {
+        // Simple element loop
+        keyType = elemType;
+        keyName = firstName;
+        valName = firstName;
+    } else {
+        reportError("Expected ',' or ':' in for-in loop");
     }
-    consumeToken();
-    auto        valTok  = expect(Lexer::Tokens::Type::VARIABLE_IDENTIFIER);
-    std::string valName = valTok.value;
-    if (!valName.empty() && valName[0] == '$') {
-        valName = valName.substr(1);
-    }
-    expect(Lexer::Tokens::Type::PUNCTUATION, ":");
     // Parse iterable expression
     auto iterableExpr = parseParsedExpression(Symbols::Variables::Type::NULL_TYPE);
     expect(Lexer::Tokens::Type::PUNCTUATION, ")");
@@ -535,9 +572,52 @@
     }
 
     bool expect_unary = true;
+    // Track if at start of expression (to distinguish array literal vs indexing)
+    bool atStart = true;
 
     while (true) {
         auto token = currentToken();
+        // Array literal (at start) or dynamic indexing (postfix)
+        if (token.type == Lexer::Tokens::Type::PUNCTUATION && token.value == "[") {
+            if (atStart) {
+                // Parse array literal as object with numeric keys
+                consumeToken(); // consume '['
+                std::vector<std::pair<std::string, ParsedExpressionPtr>> members;
+                size_t idx = 0;
+                // Elements until ']'
+                if (!(currentToken().type == Lexer::Tokens::Type::PUNCTUATION && currentToken().value == "]")) {
+                    while (true) {
+                        auto elem = parseParsedExpression(Symbols::Variables::Type::NULL_TYPE);
+                        members.emplace_back(std::to_string(idx++), std::move(elem));
+                        if (match(Lexer::Tokens::Type::PUNCTUATION, ",")) {
+                            continue;
+                        }
+                        break;
+                    }
+                }
+                expect(Lexer::Tokens::Type::PUNCTUATION, "]");
+                // Build as object literal
+                output_queue.push_back(ParsedExpression::makeObject(std::move(members)));
+                expect_unary = false;
+                atStart = false;
+                continue;
+            } else {
+                // Parse dynamic array/object indexing: lhs[index]
+                consumeToken(); // consume '['
+                auto indexExpr = parseParsedExpression(Symbols::Variables::Type::NULL_TYPE);
+                expect(Lexer::Tokens::Type::PUNCTUATION, "]");
+                if (output_queue.empty()) {
+                    reportError("Missing array/object for indexing");
+                }
+                auto lhsExpr = std::move(output_queue.back());
+                output_queue.pop_back();
+                auto accessExpr = ParsedExpression::makeBinary("[]", std::move(lhsExpr), std::move(indexExpr));
+                output_queue.push_back(std::move(accessExpr));
+                expect_unary = false;
+                atStart = false;
+                continue;
+            }
+        }
         // Object literal: { key: value, ... }
         if (token.type == Lexer::Tokens::Type::PUNCTUATION && token.value == "{") {
             // Consume '{'
@@ -737,8 +817,10 @@
                     Parser::reportError("Invalid type", token, "literal or variable");
                 }
             }
+            // Consume operand and mark that expression start has passed
             consumeToken();
             expect_unary = false;
+            atStart = false;
         } else {
             break;
         }
@@ -853,7 +935,12 @@
     // Direct lookup for type keyword
     auto         it    = Parser::variable_types.find(token.type);
     if (it != Parser::variable_types.end()) {
+        // Base type
         consumeToken();
+        // Array type syntax: baseType[] -> treat as OBJECT/array map
+        if (match(Lexer::Tokens::Type::PUNCTUATION, "[") && match(Lexer::Tokens::Type::PUNCTUATION, "]")) {
+            return Symbols::Variables::Type::OBJECT;
+        }
         return it->second;
     }
     reportError("Expected type keyword (string, int, double, float)");

--
Gitblit v1.9.3