2 files modified
8 files added
2 files deleted
| New file |
| | |
| | | <!-- |
| | | 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.* |
| New file |
| | |
| | | # 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 |
| | | ``` |
| New file |
| | |
| | | # 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); |
| | | ``` |
| New file |
| | |
| | | # 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 |
| | | ``` |
| New file |
| | |
| | | # 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 |
| | | ``` |
| New file |
| | |
| | | # 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 |
| | | ``` |
| New file |
| | |
| | | # 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 |
| | | ``` |
| New file |
| | |
| | | #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 |
| | |
| | | #include "Interpreter/DeclareVariableStatementNode.hpp" |
| | | #include "Interpreter/ExpressionBuilder.hpp" |
| | | #include "Interpreter/ForStatementNode.hpp" |
| | | #include "Interpreter/CStyleForStatementNode.hpp" |
| | | #include "Interpreter/ReturnStatementNode.hpp" |
| | | #include "Symbols/SymbolContainer.hpp" |
| | | |
| | |
| | | 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; |
| | |
| | | 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; |
| | |
| | | |
| | | int $size = sizeof($array); |
| | | |
| | | printnl("The size of the $array: ", $size); |
| | | printnl("The size of the $array: ", $size); |
| | | |
| | | for (int $i = 0; $i < sizeof($intArray); $i++) { |
| | | printnl("Value: ", $intArray[$i]); |
| | | } |