From 48d9278f0b75098e83e58c589ea86d006358604d Mon Sep 17 00:00:00 2001
From: Ferenc Szontágh <szf@fsociety.hu>
Date: Sat, 19 Apr 2025 18:02:04 +0000
Subject: [PATCH] add for ( loop, and docs

---
 docs/FileModule.md                         |   54 ++++++
 src/Parser/Parser.cpp                      |   99 +++++++++++
 /dev/null                                  |    1 
 docs/ArrayModule.md                        |   25 ++
 docs/JsonModule.md                         |   41 ++++
 docs/StringModule.md                       |   54 ++++++
 codex.md                                   |  111 ++++++++++++
 src/Interpreter/CStyleForStatementNode.hpp |   70 +++++++
 test_scripts/array.vs                      |    6 
 docs/PrintModule.md                        |   34 +++
 docs/VariableHelpersModule.md              |   37 ++++
 11 files changed, 530 insertions(+), 2 deletions(-)

diff --git a/codex.md b/codex.md
new file mode 100644
index 0000000..79b3f90
--- /dev/null
+++ b/codex.md
@@ -0,0 +1,111 @@
+<!--
+  Codex Developer Guide
+  Provides quick references for navigating and extending the VoidScript codebase.
+-->
+# VoidScript Codex
+
+## Table of Contents
+- [1. Project Structure](#1-project-structure)
+- [2. Build System](#2-build-system)
+- [3. Modules](#3-modules)
+- [4. Lexer](#4-lexer)
+- [5. Parser](#5-parser)
+- [6. AST & Interpreter](#6-ast--interpreter)
+- [7. OperationsFactory & Container](#7-operationsfactory--container)
+- [8. Adding New Syntax](#8-adding-new-syntax)
+- [9. Testing & Debugging](#9-testing--debugging)
+
+---
+
+## 1. Project Structure
+
+```
+/cli                  # CLI binary entrypoint (main.cpp)
+/src
+  /Lexer              # Tokenizer: Lexer.cpp, Operators.hpp/.cpp, Token.hpp
+  /Parser             # Parser: Parser.hpp/.cpp, ParsedExpression.hpp
+  /Interpreter        # AST nodes (ExpressionNode, StatementNode, OperationsFactory, etc.)
+  /Modules            # Built‑in modules (Array, File, JSON, Print, String, VariableHelpers)
+  /Symbols            # SymbolTable, SymbolContainer, Value, Types
+/Modules              # External/plugin modules (e.g., CurlModule)
+test_scripts          # Reference scripts (.vs) for tests/examples
+build                 # Out‑of‑source build directory
+```
+
+## 2. Build System
+
+- Uses CMake (top‑level `CMakeLists.txt`).
+- Configure: `cmake -S . -B build`
+- Build: `cmake --build build` (or `ninja -C build`).
+- Binaries & libraries under `build/`:
+  - `build/voidscript` (CLI)
+  - `build/libvoidscript.so`
+  - `build/Modules/<ModuleName>`
+
+## 3. Modules
+
+### Built‑in
+Located in `src/Modules/BuiltIn/`. They export C++ functions to the interpreter via `BuiltinModule` interface.
+
+### Plugins
+Under `/Modules/<YourModule>/`:
+1. Create `CMakeLists.txt` next to `PluginInit.cpp`.
+2. Implement hook `VS_MODULE_INIT()` to register functions.
+3. Build installs to `build/Modules/<YourModule>`.
+
+## 4. Lexer
+- Files: `src/Lexer/Lexer.hpp/.cpp`, `Operators.hpp/.cpp`, `Token.hpp`.
+- `Operators.hpp` defines token categories (arithmetic, logical, relational, assignment, punctuation).
+- In `Lexer::matchOperatorOrPunctuation`, longest‑match two‑char operators first.
+- To add a token:
+  1. Update the appropriate vector in `Operators.cpp`.
+  2. If it’s a literal/identifier change, adjust `matchIdentifierOrKeyword` or `matchNumber`.
+
+## 5. Parser
+- Files: `src/Parser/Parser.hpp/.cpp`.
+- Entry: `Parser::parseScript()`, which loops `parseStatement()` until EOF.
+- Statement handlers:
+  - Top‑level: `parseVariableDefinition()`, `parseAssignmentStatement()`, `parseIfStatement()`, `parseWhileStatement()`, `parseForStatement()`, `parseCallStatement()`, `parseReturnStatement()`.
+  - In‑block: `parseStatementNode()`, plus `parseIfStatementNode()`, `parseForStatementNode()`.
+- Expression parsing: `parseParsedExpression()` implements a shunting‑yard algorithm; outputs `ParsedExpression` AST fragments.
+
+## 6. AST & Interpreter
+- AST node interfaces under `src/Interpreter/`:
+  - `ExpressionNode` (evaluate returns `Symbols::Value`)
+  - `StatementNode` (interpret for side‑effects)
+- Mapping from `ParsedExpression` to concrete `ExpressionNode` in `Parser/ExpressionBuilder.hpp`.
+- Each node implements `evaluate()` or `interpret()`.
+- To add a node:
+  1. Create header & source in `Interpreter/`.
+  2. Update `ExpressionBuilder` (for expr nodes) or parser (for stmt nodes).
+
+## 7. OperationsFactory & Container
+- `Interpreter/OperationsFactory.hpp/.cpp`: factories to record operations (Assignment, Call, Conditional, Loop, Return).
+- `Operations::Container` holds a list of operations per scope; executed by `Interpreter`.
+- Top‑level parser uses `OperationsFactory` to enqueue AST `StatementNode` into the container.
+
+## 8. Adding New Syntax
+1. **Lexer**: add or extend token definitions in `Operators.hpp` and adjust `Lexer.cpp` matching logic.
+2. **Parser**:
+   - Register new keyword in `Parser::keywords` (if needed).
+   - Write a new `parseXxx()` or extend `parseStatementNode()`/`parseParsedExpression()`.
+   - For expressions, integrate into the shunting‑yard switch.
+3. **AST**: implement a new `ExpressionNode` or `StatementNode` subclass with semantics.
+4. **Interpreter**: define `evaluate()` or `interpret()` in the node.
+5. **OperationsFactory**: if top‑level, add a factory method to emit the operation.
+6. **Tests**: write a `.vs` script under `test_scripts/` and run with debug flags.
+
+## 9. Testing & Debugging
+- Sample scripts in `test_scripts/`.
+- Run interpreter with debug levels:
+  - Lexer: `voidscript --debug=lexer script.vs`
+  - Parser: `voidscript --debug=parser script.vs`
+  - Interpreter: `voidscript --debug=interpreter script.vs`
+- Use `printnl(...)` functions in scripts to observe runtime behavior.
+
+---
+## Maintenance
+This document must be updated whenever changes are made to the codebase (lexer, parser, AST nodes, modules, build system, etc.) to keep the guide current.
+
+*Generated by Codex CLI Agent*  
+*Always keep this file in sync with project changes.*
diff --git a/docs/ArrayModule.md b/docs/ArrayModule.md
new file mode 100644
index 0000000..77f50d7
--- /dev/null
+++ b/docs/ArrayModule.md
@@ -0,0 +1,25 @@
+ # ArrayModule
+
+ Provides the `sizeof` function to get the number of elements in an array (object map).
+
+ ## Functions
+
+ ### sizeof
+
+ - **Signature:** `sizeof(array) -> int`
+ - **Description:** Returns the number of elements in `array`.
+ - **Parameters:**
+   - `array` (object): The array (object map) whose elements to count.
+ - **Returns:** Integer count of elements.
+ - **Errors:**
+   - Incorrect number of arguments.
+   - Argument is not an array (object).
+
+ ## Example
+
+ ```vs
+ var arr = {};
+ arr["first"] = 10;
+ arr["second"] = 20;
+ printnl("Length:", sizeof(arr));  // Length: 2
+ ```
\ No newline at end of file
diff --git a/docs/FileModule.md b/docs/FileModule.md
new file mode 100644
index 0000000..c30320b
--- /dev/null
+++ b/docs/FileModule.md
@@ -0,0 +1,54 @@
+ # FileModule
+
+ Provides simple file I/O functions.
+
+ ## Functions
+
+ ### file_get_contents
+
+ - **Signature:** `file_get_contents(filename) -> string`
+ - **Description:** Reads entire content of a file.
+ - **Parameters:**
+   - `filename` (string): Path to the file.
+ - **Returns:** File content as a string.
+ - **Errors:**
+   - Incorrect number of arguments.
+   - `filename` not a string.
+   - File does not exist or cannot be opened.
+
+ ### file_put_contents
+
+ - **Signature:** `file_put_contents(filename, content, overwrite) -> undefined`
+ - **Description:** Writes `content` to `filename`.
+ - **Parameters:**
+   - `filename` (string): Path to the file.
+   - `content` (string): Content to write.
+   - `overwrite` (bool): Whether to overwrite existing file.
+ - **Returns:** VoidScript `undefined`.
+ - **Errors:**
+   - Incorrect number of arguments.
+   - Wrong types of arguments.
+   - File exists when `overwrite` is false.
+   - Unable to open or write to file.
+
+ ### file_exists
+
+ - **Signature:** `file_exists(filename) -> bool`
+ - **Description:** Checks if a file exists.
+ - **Parameters:**
+   - `filename` (string): Path to the file.
+ - **Returns:** Boolean (true if exists, false otherwise).
+ - **Errors:**
+   - Incorrect number of arguments.
+   - `filename` not a string.
+
+ ## Example
+
+ ```vs
+ var filename = "example.txt";
+ if (!file_exists(filename)) {
+     file_put_contents(filename, "Hello, VoidScript!", true);
+ }
+ var content = file_get_contents(filename);
+ printnl(content);
+ ```
\ No newline at end of file
diff --git a/docs/JsonModule.md b/docs/JsonModule.md
new file mode 100644
index 0000000..8ad9c5f
--- /dev/null
+++ b/docs/JsonModule.md
@@ -0,0 +1,41 @@
+ # JsonModule
+
+ Provides JSON serialization and deserialization functions.
+
+ ## Functions
+
+ ### json_encode
+
+ - **Signature:** `json_encode(value) -> string`
+ - **Description:** Serializes a VoidScript value to a JSON string.
+ - **Parameters:**
+   - `value`: A VoidScript value (int, double, bool, string, object, null).
+ - **Returns:** JSON string representation.
+ - **Errors:**
+   - Incorrect number of arguments.
+
+ ### json_decode
+
+ - **Signature:** `json_decode(json) -> object|value`
+ - **Description:** Parses a JSON string into a VoidScript value.
+ - **Parameters:**
+   - `json` (string): A valid JSON string.
+ - **Returns:** VoidScript value (object, number, bool, null).
+ - **Errors:**
+   - Incorrect number of arguments.
+   - `json` not a string.
+   - Invalid JSON format.
+ - **Note:** Only JSON objects (`{}`), primitives, and null are supported; arrays (`[]`) are not supported.
+
+ ## Example
+
+ ```vs
+ var obj = {};
+ obj["name"] = "Alice";
+ obj["age"] = 30;
+ var jsonStr = json_encode(obj);
+ printnl(jsonStr);  // {"name":"Alice","age":30}
+
+ var decoded = json_decode(jsonStr);
+ printnl(decoded["name"]);  // Alice
+ ```
\ No newline at end of file
diff --git a/docs/PrintModule.md b/docs/PrintModule.md
new file mode 100644
index 0000000..b02f41d
--- /dev/null
+++ b/docs/PrintModule.md
@@ -0,0 +1,34 @@
+ # PrintModule
+
+ Provides printing functions to standard output and error.
+
+ ## Functions
+
+ ### print
+
+ - **Signature:** `print(...values) -> undefined`
+ - **Description:** Prints the string representation of each value without a newline.
+ - **Parameters:** Any number of values.
+ - **Returns:** undefined.
+
+ ### printnl
+
+ - **Signature:** `printnl(...values) -> undefined`
+ - **Description:** Prints the string representation of each value followed by a newline.
+ - **Parameters:** Any number of values.
+ - **Returns:** undefined.
+
+ ### error
+
+ - **Signature:** `error(...values) -> undefined`
+ - **Description:** Prints the string representation of each value to standard error followed by a newline.
+ - **Parameters:** Any number of values.
+ - **Returns:** undefined.
+
+ ## Example
+
+ ```vs
+ print("Hello, ");
+ printnl("world!");  // prints "Hello, world!" with newline
+ error("An error occurred");  // prints to stderr
+ ```
\ No newline at end of file
diff --git a/docs/StringModule.md b/docs/StringModule.md
new file mode 100644
index 0000000..66d74f9
--- /dev/null
+++ b/docs/StringModule.md
@@ -0,0 +1,54 @@
+ # StringModule
+
+ Provides helper functions for string manipulation.
+
+ ## Functions
+
+ ### string_length
+
+ - **Signature:** `string_length(str) -> int`
+ - **Description:** Returns the length of the string `str`.
+ - **Parameters:**
+   - `str` (string): The input string.
+ - **Returns:** Integer length.
+ - **Errors:**
+   - Incorrect number of arguments.
+   - `str` not a string.
+
+ ### string_replace
+
+ - **Signature:** `string_replace(str, from, to, replace_all) -> string`
+ - **Description:** Replaces occurrences of substring `from` with `to` in `str`.
+ - **Parameters:**
+   - `str` (string): The input string.
+   - `from` (string): Substring to replace.
+   - `to` (string): Replacement substring.
+   - `replace_all` (bool): `true` to replace all occurrences, `false` to replace only the first.
+ - **Returns:** New string with replacements.
+ - **Errors:**
+   - Incorrect number of arguments.
+   - Wrong argument types.
+   - `from` is empty.
+
+ ### string_substr
+
+ - **Signature:** `string_substr(str, from, length) -> string`
+ - **Description:** Extracts a substring from `str`.
+ - **Parameters:**
+   - `str` (string): The input string.
+   - `from` (int): Starting index (0-based).
+   - `length` (int): Number of characters to extract.
+ - **Returns:** The substring.
+ - **Errors:**
+   - Incorrect number of arguments.
+   - Wrong argument types.
+   - `from` or `length` negative or out of range.
+
+ ## Example
+
+ ```vs
+ var s = "Hello, world!";
+ printnl(string_length(s));  // 13
+ printnl(string_replace(s, "world", "VoidScript", false));  // Hello, VoidScript!
+ printnl(string_substr(s, 7, 5));  // world
+ ```
\ No newline at end of file
diff --git a/docs/VariableHelpersModule.md b/docs/VariableHelpersModule.md
new file mode 100644
index 0000000..52d0dd4
--- /dev/null
+++ b/docs/VariableHelpersModule.md
@@ -0,0 +1,37 @@
+ # VariableHelpersModule
+
+ Provides helper functions to inspect variable types.
+
+ ## Functions
+
+ ### typeof
+
+ - **Signature:** `typeof(value) -> string`
+ - **Description:** Returns the type name of `value`: `"int"`, `"double"`, `"float"`, `"string"`, `"bool"`, `"object"`, `"null"`, or `"undefined"`.
+ - **Parameters:**
+   - `value`: Any VoidScript value.
+ - **Returns:** Type name as string.
+ - **Errors:** Incorrect number of arguments.
+
+ - **Signature:** `typeof(value, typeName) -> bool`
+ - **Description:** Checks if the type of `value` matches `typeName`.
+ - **Parameters:**
+   - `value`: Any VoidScript value.
+   - `typeName` (string): The type name to compare.
+ - **Returns:** Boolean indicating if types match.
+ - **Errors:**
+   - Incorrect number of arguments.
+   - `typeName` not a string.
+
+ ## Example
+
+ ```vs
+ var x = 42;
+ printnl(typeof(x));              // int
+ printnl(typeof(x, "int"));     // true
+ printnl(typeof(x, "string"));  // false
+
+ var s = "hello";
+ printnl(typeof(s));              // string
+ printnl(typeof(s, "bool"));    // false
+ ```
\ No newline at end of file
diff --git a/src/Interpreter/CStyleForStatementNode.hpp b/src/Interpreter/CStyleForStatementNode.hpp
new file mode 100644
index 0000000..80fa59d
--- /dev/null
+++ b/src/Interpreter/CStyleForStatementNode.hpp
@@ -0,0 +1,70 @@
+ #ifndef INTERPRETER_CSTYLEFORSTATEMENTNODE_HPP
+ #define INTERPRETER_CSTYLEFORSTATEMENTNODE_HPP
+
+ #include <vector>
+ #include <memory>
+ #include <string>
+ #include "Interpreter/StatementNode.hpp"
+ #include "Interpreter/Interpreter.hpp"
+ #include "Interpreter/ExpressionNode.hpp"
+ #include "Symbols/Value.hpp"
+
+ namespace Interpreter {
+
+ /**
+  * @brief Statement node representing a C-style for loop: for(init; cond; incr) { body }
+  */
+ class CStyleForStatementNode : public StatementNode {
+  private:
+    std::unique_ptr<StatementNode> initStmt_;
+    std::unique_ptr<ExpressionNode> condExpr_;
+    std::unique_ptr<StatementNode> incrStmt_;
+    std::vector<std::unique_ptr<StatementNode>> body_;
+
+  public:
+    CStyleForStatementNode(std::unique_ptr<StatementNode> initStmt,
+                           std::unique_ptr<ExpressionNode> condExpr,
+                           std::unique_ptr<StatementNode> incrStmt,
+                           std::vector<std::unique_ptr<StatementNode>> body,
+                           const std::string & file_name,
+                           int line,
+                           size_t column)
+      : StatementNode(file_name, line, column),
+        initStmt_(std::move(initStmt)),
+        condExpr_(std::move(condExpr)),
+        incrStmt_(std::move(incrStmt)),
+        body_(std::move(body)) {}
+
+    void interpret(Interpreter & interpreter) const override {
+        try {
+            using namespace Symbols;
+            // Initialization
+            initStmt_->interpret(interpreter);
+            // Loop condition and body
+            while (true) {
+                Value condVal = condExpr_->evaluate(interpreter);
+                if (condVal.getType() != Variables::Type::BOOLEAN) {
+                    throw Exception("For loop condition not boolean", filename_, line_, column_);
+                }
+                if (!condVal.get<bool>()) break;
+                for (const auto & stmt : body_) {
+                    stmt->interpret(interpreter);
+                }
+                // Increment step
+                incrStmt_->interpret(interpreter);
+            }
+        } catch (const Exception &) {
+            throw;
+        } catch (const std::exception & e) {
+            throw Exception(e.what(), filename_, line_, column_);
+        }
+    }
+
+    std::string toString() const override {
+        return "CStyleForStatementNode at " + filename_ + ":" + std::to_string(line_);
+    }
+};
+
+} // namespace Interpreter
+
+#endif // INTERPRETER_CSTYLEFORSTATEMENTNODE_HPP
\ No newline at end of file
diff --git a/src/Parser/Parser.cpp b/src/Parser/Parser.cpp
index 1ec0322..42b3d45 100644
--- a/src/Parser/Parser.cpp
+++ b/src/Parser/Parser.cpp
@@ -13,6 +13,7 @@
 #include "Interpreter/DeclareVariableStatementNode.hpp"
 #include "Interpreter/ExpressionBuilder.hpp"
 #include "Interpreter/ForStatementNode.hpp"
+#include "Interpreter/CStyleForStatementNode.hpp"
 #include "Interpreter/ReturnStatementNode.hpp"
 #include "Symbols/SymbolContainer.hpp"
 
@@ -167,6 +168,54 @@
     std::string firstName = firstTok.value;
     if (!firstName.empty() && firstName[0] == '$') {
         firstName = firstName.substr(1);
+    }
+    // C-style for loop: for (type $i = init; cond; incr) { ... }
+    if (match(Lexer::Tokens::Type::OPERATOR_ASSIGNMENT, "=")) {
+        // Parse initialization expression
+        auto initExpr = parseParsedExpression(elemType);
+        expect(Lexer::Tokens::Type::PUNCTUATION, ";");
+        // Parse condition expression
+        auto condExpr = parseParsedExpression(Symbols::Variables::Type::NULL_TYPE);
+        expect(Lexer::Tokens::Type::PUNCTUATION, ";");
+        // Parse increment statement
+        std::unique_ptr<Interpreter::StatementNode> incrStmt;
+        {
+            auto incrTok = currentToken();
+            if (incrTok.type == Lexer::Tokens::Type::VARIABLE_IDENTIFIER) {
+                auto identTok = consumeToken();
+                std::string incrName = identTok.value;
+                if (!incrName.empty() && incrName[0] == '$') incrName = incrName.substr(1);
+                if (match(Lexer::Tokens::Type::OPERATOR_INCREMENT, "++")) {
+                    auto lhs = std::make_unique<Interpreter::IdentifierExpressionNode>(incrName);
+                    auto rhs = std::make_unique<Interpreter::LiteralExpressionNode>(Symbols::Value(1));
+                    auto bin = std::make_unique<Interpreter::BinaryExpressionNode>(std::move(lhs), "+", std::move(rhs));
+                    incrStmt = std::make_unique<Interpreter::AssignmentStatementNode>(incrName, std::vector<std::string>(), std::move(bin), this->current_filename_, incrTok.line_number, incrTok.column_number);
+                } else if (match(Lexer::Tokens::Type::OPERATOR_INCREMENT, "--")) {
+                    auto lhs = std::make_unique<Interpreter::IdentifierExpressionNode>(incrName);
+                    auto rhs = std::make_unique<Interpreter::LiteralExpressionNode>(Symbols::Value(1));
+                    auto bin = std::make_unique<Interpreter::BinaryExpressionNode>(std::move(lhs), "-", std::move(rhs));
+                    incrStmt = std::make_unique<Interpreter::AssignmentStatementNode>(incrName, std::vector<std::string>(), std::move(bin), this->current_filename_, incrTok.line_number, incrTok.column_number);
+                } else {
+                    reportError("Expected '++' or '--' in for-loop increment");
+                }
+            } else {
+                reportError("Expected variable name in for-loop increment");
+            }
+        }
+        expect(Lexer::Tokens::Type::PUNCTUATION, ")");
+        expect(Lexer::Tokens::Type::PUNCTUATION, "{");
+        // Parse loop body
+        std::vector<std::unique_ptr<Interpreter::StatementNode>> body;
+        while (!(currentToken().type == Lexer::Tokens::Type::PUNCTUATION && currentToken().value == "}")) {
+            body.push_back(parseStatementNode());
+        }
+        expect(Lexer::Tokens::Type::PUNCTUATION, "}");
+        // Build nodes for C-style for
+        auto initExprNode = buildExpressionFromParsed(initExpr);
+        auto initStmt = std::make_unique<Interpreter::DeclareVariableStatementNode>(firstName, Symbols::SymbolContainer::instance()->currentScopeName(), elemType, std::move(initExprNode), this->current_filename_, firstTok.line_number, firstTok.column_number);
+        auto condExprNode = buildExpressionFromParsed(condExpr);
+        auto * cnode = new Interpreter::CStyleForStatementNode(std::move(initStmt), std::move(condExprNode), std::move(incrStmt), std::move(body), this->current_filename_, forToken.line_number, forToken.column_number);
+        return std::unique_ptr<Interpreter::StatementNode>(cnode);
     }
     // Determine loop form: key,value or simple element loop
     std::string keyName, valName;
@@ -431,6 +480,56 @@
     if (!firstName.empty() && firstName[0] == '$') {
         firstName = firstName.substr(1);
     }
+    // C-style for loop: for (type $i = init; cond; incr) { ... }
+    if (match(Lexer::Tokens::Type::OPERATOR_ASSIGNMENT, "=")) {
+        // Parse initialization expression
+        auto initExpr = parseParsedExpression(elemType);
+        expect(Lexer::Tokens::Type::PUNCTUATION, ";");
+        // Parse condition expression
+        auto condExpr = parseParsedExpression(Symbols::Variables::Type::NULL_TYPE);
+        expect(Lexer::Tokens::Type::PUNCTUATION, ";");
+        // Parse increment statement
+        std::unique_ptr<Interpreter::StatementNode> incrStmt;
+        {
+            auto incrTok = currentToken();
+            if (incrTok.type == Lexer::Tokens::Type::VARIABLE_IDENTIFIER) {
+                auto identTok = consumeToken();
+                std::string incrName = identTok.value;
+                if (!incrName.empty() && incrName[0] == '$') incrName = incrName.substr(1);
+                if (match(Lexer::Tokens::Type::OPERATOR_INCREMENT, "++")) {
+                    auto lhs = std::make_unique<Interpreter::IdentifierExpressionNode>(incrName);
+                    auto rhs = std::make_unique<Interpreter::LiteralExpressionNode>(Symbols::Value(1));
+                    auto bin = std::make_unique<Interpreter::BinaryExpressionNode>(std::move(lhs), "+", std::move(rhs));
+                    incrStmt = std::make_unique<Interpreter::AssignmentStatementNode>(incrName, std::vector<std::string>(), std::move(bin), this->current_filename_, incrTok.line_number, incrTok.column_number);
+                } else if (match(Lexer::Tokens::Type::OPERATOR_INCREMENT, "--")) {
+                    auto lhs = std::make_unique<Interpreter::IdentifierExpressionNode>(incrName);
+                    auto rhs = std::make_unique<Interpreter::LiteralExpressionNode>(Symbols::Value(1));
+                    auto bin = std::make_unique<Interpreter::BinaryExpressionNode>(std::move(lhs), "-", std::move(rhs));
+                    incrStmt = std::make_unique<Interpreter::AssignmentStatementNode>(incrName, std::vector<std::string>(), std::move(bin), this->current_filename_, incrTok.line_number, incrTok.column_number);
+                } else {
+                    reportError("Expected '++' or '--' in for-loop increment");
+                }
+            } else {
+                reportError("Expected variable name in for-loop increment");
+            }
+        }
+        expect(Lexer::Tokens::Type::PUNCTUATION, ")");
+        expect(Lexer::Tokens::Type::PUNCTUATION, "{");
+        // Parse loop body
+        std::vector<std::unique_ptr<Interpreter::StatementNode>> body;
+        while (!(currentToken().type == Lexer::Tokens::Type::PUNCTUATION && currentToken().value == "}")) {
+            body.push_back(parseStatementNode());
+        }
+        expect(Lexer::Tokens::Type::PUNCTUATION, "}");
+        // Build nodes for C-style for
+        auto initExprNode = buildExpressionFromParsed(initExpr);
+        auto initStmt = std::make_unique<Interpreter::DeclareVariableStatementNode>(firstName, Symbols::SymbolContainer::instance()->currentScopeName(), elemType, std::move(initExprNode), this->current_filename_, firstTok.line_number, firstTok.column_number);
+        auto condExprNode = buildExpressionFromParsed(condExpr);
+        auto cnode = std::make_unique<Interpreter::CStyleForStatementNode>(std::move(initStmt), std::move(condExprNode), std::move(incrStmt), std::move(body), this->current_filename_, forToken.line_number, forToken.column_number);
+        Operations::Container::instance()->add(Symbols::SymbolContainer::instance()->currentScopeName(),
+                                               Operations::Operation{Operations::Type::Loop, "", std::move(cnode)});
+        return;
+    }
     // Determine loop form: key,value or simple element loop
     std::string keyName, valName;
     Symbols::Variables::Type keyType;
diff --git a/temp_test_io.txt b/temp_test_io.txt
deleted file mode 100644
index b6fc4c6..0000000
--- a/temp_test_io.txt
+++ /dev/null
@@ -1 +0,0 @@
-hello
\ No newline at end of file
diff --git a/temp_test_io2.txt b/temp_test_io2.txt
deleted file mode 100644
index 2147e41..0000000
--- a/temp_test_io2.txt
+++ /dev/null
@@ -1 +0,0 @@
-second
\ No newline at end of file
diff --git a/test_scripts/array.vs b/test_scripts/array.vs
index 10d1b27..798da03 100644
--- a/test_scripts/array.vs
+++ b/test_scripts/array.vs
@@ -17,4 +17,8 @@
 
 int $size = sizeof($array);
 
-printnl("The size of the $array: ", $size);
\ No newline at end of file
+printnl("The size of the $array: ", $size);
+
+for (int $i = 0; $i < sizeof($intArray); $i++) {
+    printnl("Value: ", $intArray[$i]);
+}
\ No newline at end of file

--
Gitblit v1.9.3