diff --git a/src/headers/common/helperFunctions/HelperFunctions.h b/src/headers/common/helperFunctions/HelperFunctions.h index fac652d..f3133d3 100644 --- a/src/headers/common/helperFunctions/HelperFunctions.h +++ b/src/headers/common/helperFunctions/HelperFunctions.h @@ -3,6 +3,7 @@ #include #include #include +#include inline std::vector splitString(const std::string& input, const std::string& delimiter) { std::vector tokens; @@ -56,9 +57,9 @@ inline bool isHexDigit(char c) { return (std::isdigit(c) || (std::isxdigit(c) && std::islower(c))); } -inline u_long binaryStringToLong(const std::string& binaryString) { +inline unsigned long long binaryStringToLong(const std::string& binaryString) { std::string binaryDigits = binaryString.substr(2); // Remove the '0b' prefix - u_long result = 0; + unsigned long long result = 0; for (char ch : binaryDigits) { result <<= 1; result += (ch - '0'); diff --git a/src/headers/parsing/Lexer.h b/src/headers/parsing/Lexer.h index 59e98da..4f6fcf6 100644 --- a/src/headers/parsing/Lexer.h +++ b/src/headers/parsing/Lexer.h @@ -22,7 +22,7 @@ enum TokenType{ // Increment/decrement operators PLUS_PLUS, MINUS_MINUS, - IDENTIFIER, STRING, NUMBER, BOOL, + IDENTIFIER, STRING, NUMBER, KW_BOOL, AND, OR, TRUE, FALSE, IF, ELSE, FUNCTION, FOR, WHILE, DO, VAR, CLASS, EXTENDS, EXTENSION, SUPER, THIS, NONE, RETURN, BREAK, CONTINUE, @@ -53,7 +53,7 @@ inline std::string enum_mapping[] = {"OPEN_PAREN", "CLOSE_PAREN", "OPEN_BRACE", "PLUS_PLUS", "MINUS_MINUS", - "IDENTIFIER", "STRING", "NUMBER", "BOOL", + "IDENTIFIER", "STRING", "NUMBER", "KW_BOOL", "AND", "OR", "TRUE", "FALSE", "IF", "ELSE", "FUNCTION", "FOR", "WHILE", "DO", "VAR", "CLASS", "EXTENDS", "EXTENSION", "SUPER", "THIS", "NONE", "RETURN", "BREAK", "CONTINUE", diff --git a/src/headers/runtime/Interpreter.h b/src/headers/runtime/Interpreter.h index 85082f5..1bf50c3 100644 --- a/src/headers/runtime/Interpreter.h +++ b/src/headers/runtime/Interpreter.h @@ -74,6 +74,8 @@ private: std::unordered_map>> builtinExtensions; // keys: "string","array","dict","any" std::unordered_map classParents; // child -> parent std::unordered_map> classTemplates; // className -> template dict + // Field initializers per class in source order (to evaluate across inheritance chain) + std::unordered_map>>> classFieldInitializers; // className -> [(field, expr)] ErrorReporter* errorReporter; bool inThunkExecution = false; @@ -138,6 +140,12 @@ public: void setClassTemplate(const std::string& className, const std::unordered_map& tmpl); bool getClassTemplate(const std::string& className, std::unordered_map& out) const; std::unordered_map buildMergedTemplate(const std::string& className) const; + // Field initializer APIs + void setClassFieldInitializers(const std::string& className, const std::vector>>& inits) { classFieldInitializers[className] = inits; } + bool getClassFieldInitializers(const std::string& className, std::vector>>& out) const { + auto it = classFieldInitializers.find(className); + if (it == classFieldInitializers.end()) return false; out = it->second; return true; + } void addStdLibFunctions(); // Module APIs Value importModule(const std::string& spec, int line, int column); // returns module dict diff --git a/src/headers/runtime/Value.h b/src/headers/runtime/Value.h index 56f916b..f0e1449 100644 --- a/src/headers/runtime/Value.h +++ b/src/headers/runtime/Value.h @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include diff --git a/src/sources/builtinModules/os.cpp b/src/sources/builtinModules/os.cpp index 1c1bd69..c4c1928 100644 --- a/src/sources/builtinModules/os.cpp +++ b/src/sources/builtinModules/os.cpp @@ -4,9 +4,19 @@ #include #include #include -#include -#include -#include +#if defined(_WIN32) + #include + #include + #include + #include + #ifndef PATH_MAX + #define PATH_MAX MAX_PATH + #endif +#else + #include + #include + #include +#endif namespace fs = std::filesystem; @@ -15,19 +25,35 @@ void registerOsModule(Interpreter& interpreter) { // Process m.fn("getcwd", [](std::vector, int, int) -> Value { char buf[PATH_MAX]; + #if defined(_WIN32) + if (_getcwd(buf, sizeof(buf))) return Value(std::string(buf)); + #else if (getcwd(buf, sizeof(buf))) return Value(std::string(buf)); + #endif return NONE_VALUE; }); m.fn("chdir", [](std::vector a, int, int) -> Value { if (a.size() != 1 || !a[0].isString()) return Value(false); + #if defined(_WIN32) + int rc = ::_chdir(a[0].asString().c_str()); + #else int rc = ::chdir(a[0].asString().c_str()); + #endif return Value(rc == 0); }); m.fn("getpid", [](std::vector, int, int) -> Value { + #if defined(_WIN32) + return Value(static_cast(GetCurrentProcessId())); + #else return Value(static_cast(getpid())); + #endif }); m.fn("getppid", [](std::vector, int, int) -> Value { + #if defined(_WIN32) + return NONE_VALUE; // not directly available; could use Toolhelp32Snapshot if needed + #else return Value(static_cast(getppid())); + #endif }); m.fn("name", [](std::vector, int, int) -> Value { #if defined(_WIN32) diff --git a/src/sources/builtinModules/path.cpp b/src/sources/builtinModules/path.cpp index bdb5eb9..4315ef9 100644 --- a/src/sources/builtinModules/path.cpp +++ b/src/sources/builtinModules/path.cpp @@ -1,6 +1,7 @@ #include "path_module.h" #include "Interpreter.h" #include +#include namespace fs = std::filesystem; @@ -11,6 +12,17 @@ static std::string join_impl(const std::vector& parts){ return p.generic_string(); } +static bool isabs_impl(const std::string& s) { +#if defined(_WIN32) + if (s.size() >= 2 && (s[0] == '/' || s[0] == '\\')) return true; // root-relative on current drive + if (s.rfind("\\\\", 0) == 0) return true; // UNC path + if (s.size() >= 3 && std::isalpha(static_cast(s[0])) && s[1] == ':' && (s[2] == '/' || s[2] == '\\')) return true; // C:\ or C:/ + return false; +#else + return !s.empty() && s[0] == '/'; +#endif +} + void registerPathModule(Interpreter& interpreter) { interpreter.registerModule("path", [](Interpreter::ModuleBuilder& m) { m.fn("join", [](std::vector a, int, int) -> Value { @@ -37,7 +49,7 @@ void registerPathModule(Interpreter& interpreter) { }); m.fn("isabs", [](std::vector a, int, int) -> Value { if (a.size()!=1 || !a[0].isString()) return Value(false); - return Value(fs::path(a[0].asString()).is_absolute()); + return Value(isabs_impl(a[0].asString())); }); m.fn("relpath", [](std::vector a, int, int) -> Value { if (a.size()<1 || a.size()>2 || !a[0].isString() || (a.size()==2 && !a[1].isString())) return NONE_VALUE; diff --git a/src/sources/builtinModules/sys.cpp b/src/sources/builtinModules/sys.cpp index a546ead..6d3651b 100644 --- a/src/sources/builtinModules/sys.cpp +++ b/src/sources/builtinModules/sys.cpp @@ -2,7 +2,11 @@ #include "Interpreter.h" #include "Environment.h" #include "Lexer.h" // for Token and IDENTIFIER -#include +#if defined(_WIN32) + #include +#else + #include +#endif #include #include #include diff --git a/src/sources/runtime/Evaluator.cpp b/src/sources/runtime/Evaluator.cpp index 738d8ce..4c563ab 100644 --- a/src/sources/runtime/Evaluator.cpp +++ b/src/sources/runtime/Evaluator.cpp @@ -111,8 +111,23 @@ Value Evaluator::visitBinaryExpr(const std::shared_ptr& expression) case PLUS: return left + right; case MINUS: return left - right; case STAR: return left * right; - case SLASH: return left / right; - case PERCENT: return left % right; + case SLASH: { + if (right.isNumber() && right.asNumber() == 0.0) { + // Report precise site for division by zero + interpreter->reportError(expression->oper.line, expression->oper.column, + "Runtime Error", "Division by zero", "/"); + throw std::runtime_error("Division by zero"); + } + return left / right; + } + case PERCENT: { + if (right.isNumber() && right.asNumber() == 0.0) { + interpreter->reportError(expression->oper.line, expression->oper.column, + "Runtime Error", "Modulo by zero", "%"); + throw std::runtime_error("Modulo by zero"); + } + return left % right; + } case BIN_AND: return left & right; case BIN_OR: return left | right; case BIN_XOR: return left ^ right; diff --git a/src/sources/runtime/Executor.cpp b/src/sources/runtime/Executor.cpp index 9143587..ae497a7 100644 --- a/src/sources/runtime/Executor.cpp +++ b/src/sources/runtime/Executor.cpp @@ -391,11 +391,11 @@ void Executor::visitClassStmt(const std::shared_ptr& statement, Execu } else { interpreter->registerClass(statement->name.lexeme, ""); } - // Predefine fields as none, keep initializers mapped - std::unordered_map> fieldInitializers; + // Predefine fields as none, capture this class's field initializers, and register them for inheritance evaluation + std::vector>> fieldInitializers; for (const auto& f : statement->fields) { classDict[f.name.lexeme] = NONE_VALUE; - fieldInitializers[f.name.lexeme] = f.initializer; + fieldInitializers.emplace_back(f.name.lexeme, f.initializer); } // Attach methods as functions closed over a prototype env @@ -411,6 +411,8 @@ void Executor::visitClassStmt(const std::shared_ptr& statement, Execu // Save template to interpreter so instances can include inherited fields/methods interpreter->setClassTemplate(statement->name.lexeme, classDict); + // Register field initializers for this class + interpreter->setClassFieldInitializers(statement->name.lexeme, fieldInitializers); // Define a constructor function Name(...) that builds an instance dict auto ctorName = statement->name.lexeme; @@ -422,17 +424,31 @@ void Executor::visitClassStmt(const std::shared_ptr& statement, Execu for (const auto& kv : tmpl) dictRef[kv.first] = kv.second; // Tag instance with class name for extension lookup dictRef["__class"] = Value(className); - // Evaluate field initializers with this bound - if (!fieldInitializers.empty()) { + // Evaluate field initializers across inheritance chain (parent-to-child order) + { + // Build chain from base to current + std::vector chain; + std::string cur = className; + while (!cur.empty()) { chain.push_back(cur); cur = runtime->getParentClass(cur); } + std::reverse(chain.begin(), chain.end()); auto saved = runtime->getEnvironment(); auto env = std::make_shared(saved); env->setErrorReporter(nullptr); env->define("this", instance); runtime->setEnvironment(env); - for (const auto& kv : fieldInitializers) { - if (kv.second) { - Value v = runtime->evaluate(kv.second); - dictRef[kv.first] = v; + for (const auto& cls : chain) { + std::vector>> inits; + if (runtime->getClassFieldInitializers(cls, inits)) { + for (const auto& kv : inits) { + const std::string& fieldName = kv.first; + const auto& expr = kv.second; + if (expr) { + Value v = runtime->evaluate(expr); + dictRef[fieldName] = v; + // Expose field names as locals for subsequent initializers + env->define(fieldName, v); + } + } } } runtime->setEnvironment(saved); @@ -445,6 +461,10 @@ void Executor::visitClassStmt(const std::shared_ptr& statement, Execu std::shared_ptr newEnv = std::make_shared(fn->closure); newEnv->setErrorReporter(nullptr); newEnv->define("this", instance); + // Seed current class for proper super resolution within init + if (fn && !fn->ownerClass.empty()) { + newEnv->define("__currentClass", Value(fn->ownerClass)); + } // Bind params size_t n = std::min(fn->params.size(), args.size()); for (size_t i = 0; i < n; ++i) { diff --git a/src/sources/runtime/Interpreter.cpp b/src/sources/runtime/Interpreter.cpp index 2fc44fe..e0a2a1f 100644 --- a/src/sources/runtime/Interpreter.cpp +++ b/src/sources/runtime/Interpreter.cpp @@ -8,7 +8,11 @@ #include "Expression.h" #include "Parser.h" #include -#include +#if defined(_WIN32) + #include +#else + #include +#endif #include #include