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