src/Interpreter/ArrayAccessExpressionNode.hpp
New file @@ -0,0 +1,55 @@ #ifndef INTERPRETER_ARRAY_ACCESS_EXPRESSION_NODE_HPP #define INTERPRETER_ARRAY_ACCESS_EXPRESSION_NODE_HPP #include "ExpressionNode.hpp" #include "Symbols/Value.hpp" #include <stdexcept> #include <string> namespace Interpreter { /** * @brief Expression node for dynamic array/object indexing: expr[index] */ class ArrayAccessExpressionNode : public ExpressionNode { private: std::unique_ptr<ExpressionNode> arrayExpr_; std::unique_ptr<ExpressionNode> indexExpr_; public: ArrayAccessExpressionNode(std::unique_ptr<ExpressionNode> arrayExpr, std::unique_ptr<ExpressionNode> indexExpr) : arrayExpr_(std::move(arrayExpr)), indexExpr_(std::move(indexExpr)) {} Symbols::Value evaluate(Interpreter &interpreter) const override { // Evaluate the container (object or array) Symbols::Value container = arrayExpr_->evaluate(interpreter); if (container.getType() != Symbols::Variables::Type::OBJECT) { throw std::runtime_error("Attempted to index non-array"); } const auto & map = std::get<Symbols::Value::ObjectMap>(container.get()); // Evaluate the index Symbols::Value idxVal = indexExpr_->evaluate(interpreter); std::string key; if (idxVal.getType() == Symbols::Variables::Type::INTEGER) { key = std::to_string(idxVal.get<int>()); } else if (idxVal.getType() == Symbols::Variables::Type::STRING) { key = idxVal.get<std::string>(); } else { throw std::runtime_error("Array index must be integer or string"); } auto it = map.find(key); if (it == map.end()) { throw std::runtime_error("Index not found: " + key); } return it->second; } std::string toString() const override { return arrayExpr_->toString() + "[" + indexExpr_->toString() + "]"; } }; } // namespace Interpreter #endif // INTERPRETER_ARRAY_ACCESS_EXPRESSION_NODE_HPP src/Interpreter/ExpressionBuilder.hpp
@@ -11,6 +11,7 @@ #include "Interpreter/UnaryExpressionNode.hpp" // <-- új include #include "Interpreter/CallExpressionNode.hpp" #include "Interpreter/MemberExpressionNode.hpp" #include "Interpreter/ArrayAccessExpressionNode.hpp" #include "Interpreter/ObjectExpressionNode.hpp" #include "Interpreter/ObjectExpressionNode.hpp" #include "Parser/ParsedExpression.hpp" @@ -29,10 +30,16 @@ case Kind::Binary: { // Array/object dynamic indexing: operator [] if (expr->op == "[]") { auto arrExpr = buildExpressionFromParsed(expr->lhs); auto idxExpr = buildExpressionFromParsed(expr->rhs); return std::make_unique<Interpreter::ArrayAccessExpressionNode>(std::move(arrExpr), std::move(idxExpr)); } // Member access for object properties: '->' if (expr->op == "->") { auto objExpr = buildExpressionFromParsed(expr->lhs); std::string propName; // RHS parsed expression should be a literal string or variable parser node if (expr->rhs->kind == ParsedExpression::Kind::Literal && expr->rhs->value.getType() == Symbols::Variables::Type::STRING) { propName = expr->rhs->value.get<std::string>(); @@ -43,6 +50,7 @@ } return std::make_unique<Interpreter::MemberExpressionNode>(std::move(objExpr), propName); } // Default binary operator auto lhs = buildExpressionFromParsed(expr->lhs); auto rhs = buildExpressionFromParsed(expr->rhs); return std::make_unique<Interpreter::BinaryExpressionNode>(std::move(lhs), expr->op, std::move(rhs)); src/Modules/BuiltIn/ArrayModule.hpp
New file @@ -0,0 +1,44 @@ // ArrayModule.hpp #ifndef MODULES_ARRAYMODULE_HPP #define MODULES_ARRAYMODULE_HPP #include <stdexcept> #include <string> #include <vector> #include "Modules/BaseModule.hpp" #include "Modules/ModuleManager.hpp" #include "Symbols/Value.hpp" #include "Symbols/VariableTypes.hpp" namespace Modules { /** * @brief Module providing a sizeof() function for array variables. * Usage: * sizeof($array) -> returns number of elements in the array */ class ArrayModule : public BaseModule { public: void registerModule() override { auto & mgr = ModuleManager::instance(); mgr.registerFunction("sizeof", [](const std::vector<Symbols::Value> & args) { using namespace Symbols; if (args.size() != 1) { throw std::runtime_error("sizeof expects exactly one argument"); } const auto & val = args[0]; auto type = val.getType(); // Only allow array types (OBJECT) if (type == Variables::Type::OBJECT) { const auto & map = std::get<Value::ObjectMap>(val.get()); return Value(static_cast<int>(map.size())); } throw std::runtime_error("sizeof expects an array variable"); }); } }; } // namespace Modules #endif // MODULES_ARRAYMODULE_HPP src/Modules/BuiltIn/FileModule.hpp
File was renamed from src/Modules/FileModule.hpp @@ -8,8 +8,8 @@ #include <stdexcept> #include <vector> #include <string> #include "BaseModule.hpp" #include "ModuleManager.hpp" #include "Modules/BaseModule.hpp" #include "Modules/ModuleManager.hpp" #include "Symbols/Value.hpp" namespace Modules { src/Modules/BuiltIn/JsonModule.hpp
New file @@ -0,0 +1,328 @@ // JsonModule.hpp #ifndef MODULES_JSONMODULE_HPP #define MODULES_JSONMODULE_HPP #include <cctype> #include <stdexcept> #include <string> #include <variant> #include "Modules/BaseModule.hpp" #include "Modules/ModuleManager.hpp" #include "Symbols/Value.hpp" #include "Symbols/VariableTypes.hpp" namespace Modules { /** * @brief Module providing JSON encode/decode functions. * json_encode(value) -> string * json_decode(string) -> object/value */ class JsonModule : public BaseModule { public: void registerModule() override { auto & mgr = ModuleManager::instance(); // json_encode: serialize a Value to JSON string mgr.registerFunction("json_encode", [](const std::vector<Symbols::Value> & args) { using namespace Symbols; if (args.size() != 1) { throw std::runtime_error("json_encode expects 1 argument"); } // forward to encoder std::function<std::string(const Value &)> encode; encode = [&](const Value & v) -> std::string { const auto & var = v.get(); return std::visit( [&](auto && x) -> std::string { using T = std::decay_t<decltype(x)>; if constexpr (std::is_same_v<T, bool>) { return x ? "true" : "false"; } else if constexpr (std::is_same_v<T, int> || std::is_same_v<T, double> || std::is_same_v<T, float>) { return std::to_string(x); } else if constexpr (std::is_same_v<T, std::string>) { // escape string std::string out = "\""; for (char c : x) { switch (c) { case '"': out += "\\\""; break; case '\\': out += "\\\\"; break; case '\b': out += "\\b"; break; case '\f': out += "\\f"; break; case '\n': out += "\\n"; break; case '\r': out += "\\r"; break; case '\t': out += "\\t"; break; default: if (static_cast<unsigned char>(c) < 0x20) { // control character char buf[7]; std::snprintf(buf, sizeof(buf), "\\u%04x", c); out += buf; } else { out += c; } } } out += "\""; return out; } else if constexpr (std::is_same_v<T, Value::ObjectMap>) { std::string out = "{"; bool first = true; for (const auto & kv : x) { if (!first) { out += ","; } first = false; // key out += '"'; // escape key string for (char c : kv.first) { switch (c) { case '"': out += "\\\""; break; case '\\': out += "\\\\"; break; case '\b': out += "\\b"; break; case '\f': out += "\\f"; break; case '\n': out += "\\n"; break; case '\r': out += "\\r"; break; case '\t': out += "\\t"; break; default: if (static_cast<unsigned char>(c) < 0x20) { char buf[7]; std::snprintf(buf, sizeof(buf), "\\u%04x", c); out += buf; } else { out += c; } } } out += '"'; out += ':'; out += encode(kv.second); } out += "}"; return out; } else { return "null"; } }, var); }; std::string result = encode(args[0]); return Symbols::Value(result); }); // json_decode: parse JSON string to Value (object/value) mgr.registerFunction("json_decode", [](const std::vector<Symbols::Value> & args) { using namespace Symbols; if (args.size() != 1) { throw std::runtime_error("json_decode expects 1 argument"); } if (args[0].getType() != Variables::Type::STRING) { throw std::runtime_error("json_decode expects a JSON string"); } const std::string s = args[0].get<std::string>(); struct Parser { const std::string & s; size_t pos = 0; Parser(const std::string & str) : s(str), pos(0) {} void skip() { while (pos < s.size() && std::isspace(static_cast<unsigned char>(s[pos]))) { pos++; } } std::string parseString() { skip(); if (s[pos] != '"') { throw std::runtime_error("Invalid JSON string"); } pos++; std::string out; while (pos < s.size()) { char c = s[pos++]; if (c == '"') { break; } if (c == '\\') { if (pos >= s.size()) { break; } char e = s[pos++]; switch (e) { case '"': out += '"'; break; case '\\': out += '\\'; break; case '/': out += '/'; break; case 'b': out += '\b'; break; case 'f': out += '\f'; break; case 'n': out += '\n'; break; case 'r': out += '\r'; break; case 't': out += '\t'; break; default: out += e; break; } } else { out += c; } } return out; } Value parseNumber() { skip(); size_t start = pos; if (s[pos] == '-') { pos++; } while (pos < s.size() && std::isdigit(static_cast<unsigned char>(s[pos]))) { pos++; } bool isDouble = false; if (pos < s.size() && s[pos] == '.') { isDouble = true; pos++; while (pos < s.size() && std::isdigit(static_cast<unsigned char>(s[pos]))) { pos++; } } std::string num = s.substr(start, pos - start); try { if (isDouble) { return Value(std::stod(num)); } return Value(std::stoi(num)); } catch (...) { throw std::runtime_error("Invalid JSON number: " + num); } } Value parseBool() { skip(); if (s.compare(pos, 4, "true") == 0) { pos += 4; return Value(true); } if (s.compare(pos, 5, "false") == 0) { pos += 5; return Value(false); } throw std::runtime_error("Invalid JSON boolean"); } Value parseNull() { skip(); if (s.compare(pos, 4, "null") == 0) { pos += 4; return Value::makeNull(); } throw std::runtime_error("Invalid JSON null"); } Value parseObject() { skip(); if (s[pos] != '{') { throw std::runtime_error("Invalid JSON object"); } pos++; skip(); Value::ObjectMap obj; if (s[pos] == '}') { pos++; return Value(obj); } while (pos < s.size()) { skip(); std::string key = parseString(); skip(); if (s[pos] != ':') { throw std::runtime_error("Expected ':' in object"); } pos++; skip(); Value val = parseValue(); obj.emplace(key, val); skip(); if (s[pos] == ',') { pos++; continue; } if (s[pos] == '}') { pos++; break; } throw std::runtime_error("Expected ',' or '}' in object"); } return Value(obj); } Value parseValue() { skip(); if (pos >= s.size()) { throw std::runtime_error("Empty JSON"); } char c = s[pos]; if (c == '{') { return parseObject(); } if (c == '"') { std::string str = parseString(); return Value(str); } if (c == 't' || c == 'f') { return parseBool(); } if (c == 'n') { return parseNull(); } if (c == '-' || std::isdigit(static_cast<unsigned char>(c))) { return parseNumber(); } throw std::runtime_error(std::string("Invalid JSON value at pos ") + std::to_string(pos)); } } parser(s); Value result = parser.parseValue(); return result; }); } }; } // namespace Modules #endif // MODULES_JSONMODULE_HPP src/Modules/BuiltIn/PrintModule.hpp
New file @@ -0,0 +1,44 @@ // PrintModule.hpp #ifndef MODULES_PRINTMODULE_HPP #define MODULES_PRINTMODULE_HPP #include <iostream> #include "Modules/BaseModule.hpp" #include "Modules/ModuleManager.hpp" #include "Symbols/Value.hpp" namespace Modules { /** * @brief Module that provides a built-in print function. */ class PrintModule : public BaseModule { public: void registerModule() override { auto & mgr = ModuleManager::instance(); mgr.registerFunction("print", [](const std::vector<Symbols::Value> & args) { for (const auto & v : args) { std::cout << Symbols::Value::to_string(v); } return Symbols::Value(); }); mgr.registerFunction("printnl", [](const std::vector<Symbols::Value> & args) { for (const auto & v : args) { std::cout << Symbols::Value::to_string(v); } std::cout << "\n"; return Symbols::Value(); }); mgr.registerFunction("error", [](const std::vector<Symbols::Value> & args) { for (const auto & v : args) { std::cerr << Symbols::Value::to_string(v); } std::cerr << "\n"; return Symbols::Value(); }); } }; } // namespace Modules #endif // MODULES_PRINTMODULE_HPP src/Modules/BuiltIn/StringModule.hpp
New file @@ -0,0 +1,101 @@ // StringModule.hpp #ifndef MODULES_STRINGMODULE_HPP #define MODULES_STRINGMODULE_HPP #include <string> #include <vector> #include <stdexcept> #include "Modules/BaseModule.hpp" #include "Modules/ModuleManager.hpp" #include "Symbols/Value.hpp" #include "Symbols/VariableTypes.hpp" namespace Modules { /** * @brief Module providing string helper functions. * Functions: * string_length(string $in) -> length of the string * string_replace(string $in, string $from, string $to, bool $replace_all) * string_substr(string $in, int from, int length) -> substring */ class StringModule : public BaseModule { public: void registerModule() override { auto &mgr = ModuleManager::instance(); // string_length mgr.registerFunction("string_length", [](const std::vector<Symbols::Value> &args) { using namespace Symbols; if (args.size() != 1) { throw std::runtime_error("string_length expects exactly one argument"); } if (args[0].getType() != Variables::Type::STRING) { throw std::runtime_error("string_length expects a string argument"); } const std::string &s = args[0].get<std::string>(); return Value(static_cast<int>(s.size())); }); // string_replace mgr.registerFunction("string_replace", [](const std::vector<Symbols::Value> &args) { using namespace Symbols; if (args.size() != 4) { throw std::runtime_error("string_replace expects 4 arguments"); } if (args[0].getType() != Variables::Type::STRING || args[1].getType() != Variables::Type::STRING || args[2].getType() != Variables::Type::STRING || args[3].getType() != Variables::Type::BOOLEAN) { throw std::runtime_error("string_replace argument types must be (string, string, string, boolean)"); } std::string in = args[0].get<std::string>(); const std::string &from = args[1].get<std::string>(); const std::string &to = args[2].get<std::string>(); bool replace_all = args[3].get<bool>(); if (from.empty()) { throw std::runtime_error("string_replace: 'from' cannot be empty"); } size_t pos = 0; if (replace_all) { while ((pos = in.find(from, pos)) != std::string::npos) { in.replace(pos, from.length(), to); pos += to.length(); } } else { pos = in.find(from); if (pos != std::string::npos) { in.replace(pos, from.length(), to); } } return Value(in); }); // string_substr mgr.registerFunction("string_substr", [](const std::vector<Symbols::Value> &args) { using namespace Symbols; if (args.size() != 3) { throw std::runtime_error("string_substr expects 3 arguments"); } if (args[0].getType() != Variables::Type::STRING || args[1].getType() != Variables::Type::INTEGER || args[2].getType() != Variables::Type::INTEGER) { throw std::runtime_error("string_substr argument types must be (string, int, int)"); } const std::string &s = args[0].get<std::string>(); int from = args[1].get<int>(); int length = args[2].get<int>(); if (from < 0 || length < 0) { throw std::runtime_error("string_substr: 'from' and 'length' must be non-negative"); } size_t pos = static_cast<size_t>(from); if (pos > s.size()) { throw std::runtime_error("string_substr: 'from' out of range"); } size_t len = static_cast<size_t>(length); std::string sub = s.substr(pos, len); return Value(sub); }); } }; } // namespace Modules #endif // MODULES_STRINGMODULE_HPP src/Modules/BuiltIn/VariableHelpersModule.hpp
New file @@ -0,0 +1,48 @@ // VariableHelpersModule.hpp #ifndef MODULES_VARIABLEHELPERSMODULE_HPP #define MODULES_VARIABLEHELPERSMODULE_HPP #include <stdexcept> #include <string> #include <vector> #include "Modules/BaseModule.hpp" #include "Modules/ModuleManager.hpp" #include "Symbols/Value.hpp" #include "Symbols/VariableTypes.hpp" namespace Modules { /** * @brief Module providing helper functions for variables. * Currently supports: * typeof($var) -> returns string name of type * typeof($var, "int") -> returns bool if type matches */ class VariableHelpersModule : public BaseModule { public: void registerModule() override { auto & mgr = ModuleManager::instance(); mgr.registerFunction("typeof", [](const std::vector<Symbols::Value> & args) { using namespace Symbols; if (args.size() == 1) { auto t = args[0].getType(); return Value(Variables::TypeToString(t)); } if (args.size() == 2) { auto t = args[0].getType(); std::string name = Variables::TypeToString(t); if (args[1].getType() != Variables::Type::STRING) { throw std::runtime_error("Second argument to typeof must be string"); } bool match = (name == args[1].get<std::string>()); return Value(match); } throw std::runtime_error("typeof expects 1 or 2 arguments"); }); } }; } // namespace Modules #endif // MODULES_VARIABLEHELPERSMODULE_HPP src/Modules/JsonModule.hpp
File was deleted src/Modules/PrintModule.hpp
File was deleted src/Modules/PrintNlModule.hpp
File was deleted src/Modules/TypeofModule.hpp
File was deleted src/Parser/Parser.cpp
@@ -55,7 +55,14 @@ void Parser::parseVariableDefinition() { Symbols::Variables::Type var_type = parseType(); Lexer::Tokens::Token id_token = expect(Lexer::Tokens::Type::VARIABLE_IDENTIFIER); // 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] == '$') { @@ -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, ","); // 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); std::string valName = valTok.value; 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"); } 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 // 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); std::string valName = valTok.value; 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"); } // 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)"); src/VoidScript.hpp
@@ -6,12 +6,18 @@ #include "Interpreter/Interpreter.hpp" #include "Lexer/Lexer.hpp" #include "Modules/BuiltIn/PrintModule.hpp" #include "Modules/ModuleManager.hpp" #include "Modules/PrintNlModule.hpp" #include "Modules/PrintModule.hpp" #include "Modules/TypeofModule.hpp" #include "Modules/FileModule.hpp" #include "Modules/JsonModule.hpp" // Variable helper functions (typeof) #include "Modules/BuiltIn/VariableHelpersModule.hpp" // String helper functions #include "Modules/BuiltIn/StringModule.hpp" // Array helper functions (sizeof) #include "Modules/BuiltIn/ArrayModule.hpp" // File I/O #include "Modules/BuiltIn/FileModule.hpp" // JSON encode/decode #include "Modules/BuiltIn/JsonModule.hpp" #include "Parser/Parser.hpp" class VoidScript { @@ -55,10 +61,14 @@ lexer(std::make_shared<Lexer::Lexer>()), parser(std::make_shared<Parser::Parser>()) { // Register built-in modules (print, etc.) // print functions Modules::ModuleManager::instance().addModule(std::make_unique<Modules::PrintModule>()); Modules::ModuleManager::instance().addModule(std::make_unique<Modules::PrintNlModule>()); // typeof() builtin Modules::ModuleManager::instance().addModule(std::make_unique<Modules::TypeofModule>()); // variable helpers (typeof) Modules::ModuleManager::instance().addModule(std::make_unique<Modules::VariableHelpersModule>()); // string helper functions Modules::ModuleManager::instance().addModule(std::make_unique<Modules::StringModule>()); // array helper functions (sizeof) Modules::ModuleManager::instance().addModule(std::make_unique<Modules::ArrayModule>()); // file I/O builtin Modules::ModuleManager::instance().addModule(std::make_unique<Modules::FileModule>()); // JSON encode/decode builtin test_scripts/array.vs
@@ -1,8 +1,20 @@ array[string] $array = ["cat", "dog", "girafe"]; string[] $array = ["cat", "dog", "girafe"]; array[int] $intArray = [10,11,0,1,2,44,2]; int[] $intArray = [10,11,0,1,2,44,2]; array[int] $emptyIntArray = []; int[] $emptyIntArray = []; printnl("First key: ", $array[0]); int index = 0; for (string $value : $array) { printnl("$value =",$value, " ?= $array[$index] =", $array[$index]); $index = $index + 1; } int $size = sizeof($array); printnl("The size of the $array: ", $size); test_scripts/test_array.vs
New file @@ -0,0 +1,2 @@ int[] $arr = [0,1,2,3]; printnl(sizeof($arr)); test_scripts/test_string.vs
New file @@ -0,0 +1,3 @@ string $s = "hello"; printnl(sizeof($s)); printnl(sizeof("abc")); test_scripts/test_substr.vs
New file @@ -0,0 +1,4 @@ string $s = "hello_world"; printnl(string_substr($s, 6, 5)); printnl(string_substr($s, 0, 5)); printnl(string_substr($s, 0, 50));