windows specific changes

This commit is contained in:
Bobby Lucero 2025-08-13 00:12:54 -04:00
parent 6e3379b5b8
commit ec4b5afa9c
10 changed files with 112 additions and 21 deletions

View File

@ -3,6 +3,7 @@
#include <iostream> #include <iostream>
#include <vector> #include <vector>
#include <bitset> #include <bitset>
#include <cctype>
inline std::vector<std::string> splitString(const std::string& input, const std::string& delimiter) { inline std::vector<std::string> splitString(const std::string& input, const std::string& delimiter) {
std::vector<std::string> tokens; std::vector<std::string> tokens;
@ -56,9 +57,9 @@ inline bool isHexDigit(char c) {
return (std::isdigit(c) || (std::isxdigit(c) && std::islower(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 std::string binaryDigits = binaryString.substr(2); // Remove the '0b' prefix
u_long result = 0; unsigned long long result = 0;
for (char ch : binaryDigits) { for (char ch : binaryDigits) {
result <<= 1; result <<= 1;
result += (ch - '0'); result += (ch - '0');

View File

@ -22,7 +22,7 @@ enum TokenType{
// Increment/decrement operators // Increment/decrement operators
PLUS_PLUS, MINUS_MINUS, PLUS_PLUS, MINUS_MINUS,
IDENTIFIER, STRING, NUMBER, BOOL, IDENTIFIER, STRING, NUMBER, KW_BOOL,
AND, OR, TRUE, FALSE, IF, ELSE, FUNCTION, FOR, AND, OR, TRUE, FALSE, IF, ELSE, FUNCTION, FOR,
WHILE, DO, VAR, CLASS, EXTENDS, EXTENSION, SUPER, THIS, NONE, RETURN, BREAK, CONTINUE, 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", "PLUS_PLUS", "MINUS_MINUS",
"IDENTIFIER", "STRING", "NUMBER", "BOOL", "IDENTIFIER", "STRING", "NUMBER", "KW_BOOL",
"AND", "OR", "TRUE", "FALSE", "IF", "ELSE", "FUNCTION", "FOR", "AND", "OR", "TRUE", "FALSE", "IF", "ELSE", "FUNCTION", "FOR",
"WHILE", "DO", "VAR", "CLASS", "EXTENDS", "EXTENSION", "SUPER", "THIS", "NONE", "RETURN", "BREAK", "CONTINUE", "WHILE", "DO", "VAR", "CLASS", "EXTENDS", "EXTENSION", "SUPER", "THIS", "NONE", "RETURN", "BREAK", "CONTINUE",

View File

@ -74,6 +74,8 @@ private:
std::unordered_map<std::string, std::unordered_map<std::string, std::shared_ptr<Function>>> builtinExtensions; // keys: "string","array","dict","any" std::unordered_map<std::string, std::unordered_map<std::string, std::shared_ptr<Function>>> builtinExtensions; // keys: "string","array","dict","any"
std::unordered_map<std::string, std::string> classParents; // child -> parent std::unordered_map<std::string, std::string> classParents; // child -> parent
std::unordered_map<std::string, std::unordered_map<std::string, Value>> classTemplates; // className -> template dict std::unordered_map<std::string, std::unordered_map<std::string, Value>> classTemplates; // className -> template dict
// Field initializers per class in source order (to evaluate across inheritance chain)
std::unordered_map<std::string, std::vector<std::pair<std::string, std::shared_ptr<Expr>>>> classFieldInitializers; // className -> [(field, expr)]
ErrorReporter* errorReporter; ErrorReporter* errorReporter;
bool inThunkExecution = false; bool inThunkExecution = false;
@ -138,6 +140,12 @@ public:
void setClassTemplate(const std::string& className, const std::unordered_map<std::string, Value>& tmpl); void setClassTemplate(const std::string& className, const std::unordered_map<std::string, Value>& tmpl);
bool getClassTemplate(const std::string& className, std::unordered_map<std::string, Value>& out) const; bool getClassTemplate(const std::string& className, std::unordered_map<std::string, Value>& out) const;
std::unordered_map<std::string, Value> buildMergedTemplate(const std::string& className) const; std::unordered_map<std::string, Value> buildMergedTemplate(const std::string& className) const;
// Field initializer APIs
void setClassFieldInitializers(const std::string& className, const std::vector<std::pair<std::string, std::shared_ptr<Expr>>>& inits) { classFieldInitializers[className] = inits; }
bool getClassFieldInitializers(const std::string& className, std::vector<std::pair<std::string, std::shared_ptr<Expr>>>& out) const {
auto it = classFieldInitializers.find(className);
if (it == classFieldInitializers.end()) return false; out = it->second; return true;
}
void addStdLibFunctions(); void addStdLibFunctions();
// Module APIs // Module APIs
Value importModule(const std::string& spec, int line, int column); // returns module dict Value importModule(const std::string& spec, int line, int column); // returns module dict

View File

@ -3,6 +3,7 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include <unordered_map> #include <unordered_map>
#include <memory>
#include <utility> #include <utility>
#include <cmath> #include <cmath>
#include <stdexcept> #include <stdexcept>

View File

@ -4,9 +4,19 @@
#include <vector> #include <vector>
#include <string> #include <string>
#include <filesystem> #include <filesystem>
#include <unistd.h> #if defined(_WIN32)
#include <sys/types.h> #include <windows.h>
#include <dirent.h> #include <direct.h>
#include <limits.h>
#include <io.h>
#ifndef PATH_MAX
#define PATH_MAX MAX_PATH
#endif
#else
#include <unistd.h>
#include <sys/types.h>
#include <dirent.h>
#endif
namespace fs = std::filesystem; namespace fs = std::filesystem;
@ -15,19 +25,35 @@ void registerOsModule(Interpreter& interpreter) {
// Process // Process
m.fn("getcwd", [](std::vector<Value>, int, int) -> Value { m.fn("getcwd", [](std::vector<Value>, int, int) -> Value {
char buf[PATH_MAX]; 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)); if (getcwd(buf, sizeof(buf))) return Value(std::string(buf));
#endif
return NONE_VALUE; return NONE_VALUE;
}); });
m.fn("chdir", [](std::vector<Value> a, int, int) -> Value { m.fn("chdir", [](std::vector<Value> a, int, int) -> Value {
if (a.size() != 1 || !a[0].isString()) return Value(false); 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()); int rc = ::chdir(a[0].asString().c_str());
#endif
return Value(rc == 0); return Value(rc == 0);
}); });
m.fn("getpid", [](std::vector<Value>, int, int) -> Value { m.fn("getpid", [](std::vector<Value>, int, int) -> Value {
#if defined(_WIN32)
return Value(static_cast<double>(GetCurrentProcessId()));
#else
return Value(static_cast<double>(getpid())); return Value(static_cast<double>(getpid()));
#endif
}); });
m.fn("getppid", [](std::vector<Value>, int, int) -> Value { m.fn("getppid", [](std::vector<Value>, int, int) -> Value {
#if defined(_WIN32)
return NONE_VALUE; // not directly available; could use Toolhelp32Snapshot if needed
#else
return Value(static_cast<double>(getppid())); return Value(static_cast<double>(getppid()));
#endif
}); });
m.fn("name", [](std::vector<Value>, int, int) -> Value { m.fn("name", [](std::vector<Value>, int, int) -> Value {
#if defined(_WIN32) #if defined(_WIN32)

View File

@ -1,6 +1,7 @@
#include "path_module.h" #include "path_module.h"
#include "Interpreter.h" #include "Interpreter.h"
#include <filesystem> #include <filesystem>
#include <cctype>
namespace fs = std::filesystem; namespace fs = std::filesystem;
@ -11,6 +12,17 @@ static std::string join_impl(const std::vector<Value>& parts){
return p.generic_string(); 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<unsigned char>(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) { void registerPathModule(Interpreter& interpreter) {
interpreter.registerModule("path", [](Interpreter::ModuleBuilder& m) { interpreter.registerModule("path", [](Interpreter::ModuleBuilder& m) {
m.fn("join", [](std::vector<Value> a, int, int) -> Value { m.fn("join", [](std::vector<Value> a, int, int) -> Value {
@ -37,7 +49,7 @@ void registerPathModule(Interpreter& interpreter) {
}); });
m.fn("isabs", [](std::vector<Value> a, int, int) -> Value { m.fn("isabs", [](std::vector<Value> a, int, int) -> Value {
if (a.size()!=1 || !a[0].isString()) return Value(false); 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<Value> a, int, int) -> Value { m.fn("relpath", [](std::vector<Value> a, int, int) -> Value {
if (a.size()<1 || a.size()>2 || !a[0].isString() || (a.size()==2 && !a[1].isString())) return NONE_VALUE; if (a.size()<1 || a.size()>2 || !a[0].isString() || (a.size()==2 && !a[1].isString())) return NONE_VALUE;

View File

@ -2,7 +2,11 @@
#include "Interpreter.h" #include "Interpreter.h"
#include "Environment.h" #include "Environment.h"
#include "Lexer.h" // for Token and IDENTIFIER #include "Lexer.h" // for Token and IDENTIFIER
#include <unistd.h> #if defined(_WIN32)
#include <windows.h>
#else
#include <unistd.h>
#endif
#include <limits.h> #include <limits.h>
#include <cstdlib> #include <cstdlib>
#include <cstring> #include <cstring>

View File

@ -111,8 +111,23 @@ Value Evaluator::visitBinaryExpr(const std::shared_ptr<BinaryExpr>& expression)
case PLUS: return left + right; case PLUS: return left + right;
case MINUS: return left - right; case MINUS: return left - right;
case STAR: return left * right; case STAR: return left * right;
case SLASH: return left / right; case SLASH: {
case PERCENT: return left % right; 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_AND: return left & right;
case BIN_OR: return left | right; case BIN_OR: return left | right;
case BIN_XOR: return left ^ right; case BIN_XOR: return left ^ right;

View File

@ -391,11 +391,11 @@ void Executor::visitClassStmt(const std::shared_ptr<ClassStmt>& statement, Execu
} else { } else {
interpreter->registerClass(statement->name.lexeme, ""); interpreter->registerClass(statement->name.lexeme, "");
} }
// Predefine fields as none, keep initializers mapped // Predefine fields as none, capture this class's field initializers, and register them for inheritance evaluation
std::unordered_map<std::string, std::shared_ptr<Expr>> fieldInitializers; std::vector<std::pair<std::string, std::shared_ptr<Expr>>> fieldInitializers;
for (const auto& f : statement->fields) { for (const auto& f : statement->fields) {
classDict[f.name.lexeme] = NONE_VALUE; 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 // Attach methods as functions closed over a prototype env
@ -411,6 +411,8 @@ void Executor::visitClassStmt(const std::shared_ptr<ClassStmt>& statement, Execu
// Save template to interpreter so instances can include inherited fields/methods // Save template to interpreter so instances can include inherited fields/methods
interpreter->setClassTemplate(statement->name.lexeme, classDict); 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 // Define a constructor function Name(...) that builds an instance dict
auto ctorName = statement->name.lexeme; auto ctorName = statement->name.lexeme;
@ -422,17 +424,31 @@ void Executor::visitClassStmt(const std::shared_ptr<ClassStmt>& statement, Execu
for (const auto& kv : tmpl) dictRef[kv.first] = kv.second; for (const auto& kv : tmpl) dictRef[kv.first] = kv.second;
// Tag instance with class name for extension lookup // Tag instance with class name for extension lookup
dictRef["__class"] = Value(className); dictRef["__class"] = Value(className);
// Evaluate field initializers with this bound // Evaluate field initializers across inheritance chain (parent-to-child order)
if (!fieldInitializers.empty()) { {
// Build chain from base to current
std::vector<std::string> 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 saved = runtime->getEnvironment();
auto env = std::make_shared<Environment>(saved); auto env = std::make_shared<Environment>(saved);
env->setErrorReporter(nullptr); env->setErrorReporter(nullptr);
env->define("this", instance); env->define("this", instance);
runtime->setEnvironment(env); runtime->setEnvironment(env);
for (const auto& kv : fieldInitializers) { for (const auto& cls : chain) {
if (kv.second) { std::vector<std::pair<std::string, std::shared_ptr<Expr>>> inits;
Value v = runtime->evaluate(kv.second); if (runtime->getClassFieldInitializers(cls, inits)) {
dictRef[kv.first] = v; 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); runtime->setEnvironment(saved);
@ -445,6 +461,10 @@ void Executor::visitClassStmt(const std::shared_ptr<ClassStmt>& statement, Execu
std::shared_ptr<Environment> newEnv = std::make_shared<Environment>(fn->closure); std::shared_ptr<Environment> newEnv = std::make_shared<Environment>(fn->closure);
newEnv->setErrorReporter(nullptr); newEnv->setErrorReporter(nullptr);
newEnv->define("this", instance); 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 // Bind params
size_t n = std::min(fn->params.size(), args.size()); size_t n = std::min(fn->params.size(), args.size());
for (size_t i = 0; i < n; ++i) { for (size_t i = 0; i < n; ++i) {

View File

@ -8,7 +8,11 @@
#include "Expression.h" #include "Expression.h"
#include "Parser.h" #include "Parser.h"
#include <filesystem> #include <filesystem>
#include <unistd.h> #if defined(_WIN32)
#include <direct.h>
#else
#include <unistd.h>
#endif
#include <fstream> #include <fstream>
#include <iostream> #include <iostream>