windows specific changes
This commit is contained in:
parent
6e3379b5b8
commit
ec4b5afa9c
@ -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');
|
||||||
|
|||||||
@ -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",
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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) {
|
||||||
|
|||||||
@ -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>
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user