Code cleanup
This commit is contained in:
parent
85d3381575
commit
266cca5b42
35
src/headers/runtime/AssignmentUtils.h
Normal file
35
src/headers/runtime/AssignmentUtils.h
Normal file
@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
|
||||
#include "Value.h"
|
||||
#include "Lexer.h"
|
||||
|
||||
// Utility to compute the result of a compound assignment (e.g., +=, -=, etc.)
|
||||
// Leaves error reporting to callers; throws std::runtime_error on unknown operator
|
||||
inline Value computeCompoundAssignment(const Value& currentValue, TokenType opType, const Value& rhs) {
|
||||
switch (opType) {
|
||||
case PLUS_EQUAL:
|
||||
return currentValue + rhs;
|
||||
case MINUS_EQUAL:
|
||||
return currentValue - rhs;
|
||||
case STAR_EQUAL:
|
||||
return currentValue * rhs;
|
||||
case SLASH_EQUAL:
|
||||
return currentValue / rhs;
|
||||
case PERCENT_EQUAL:
|
||||
return currentValue % rhs;
|
||||
case BIN_AND_EQUAL:
|
||||
return currentValue & rhs;
|
||||
case BIN_OR_EQUAL:
|
||||
return currentValue | rhs;
|
||||
case BIN_XOR_EQUAL:
|
||||
return currentValue ^ rhs;
|
||||
case BIN_SLEFT_EQUAL:
|
||||
return currentValue << rhs;
|
||||
case BIN_SRIGHT_EQUAL:
|
||||
return currentValue >> rhs;
|
||||
default:
|
||||
throw std::runtime_error("Unknown compound assignment operator");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -41,19 +41,11 @@ public:
|
||||
// Enhanced get with error reporting
|
||||
Value get(const Token& name);
|
||||
|
||||
// Get by string name with error reporting
|
||||
Value get(const std::string& name);
|
||||
|
||||
// Prune heavy containers in a snapshot to avoid capture cycles
|
||||
void pruneForClosureCapture();
|
||||
|
||||
std::shared_ptr<Environment> getParent() const { return parent; }
|
||||
inline void clear() { variables.clear(); }
|
||||
|
||||
// Set parent environment for TCO environment reuse
|
||||
inline void setParent(std::shared_ptr<Environment> newParent) {
|
||||
parent = newParent;
|
||||
}
|
||||
|
||||
private:
|
||||
std::unordered_map<std::string, Value> variables;
|
||||
|
||||
@ -1,15 +1,4 @@
|
||||
#pragma once
|
||||
#include "Expression.h"
|
||||
#include "Statement.h"
|
||||
#include "helperFunctions/ShortHands.h"
|
||||
#include "TypeWrapper.h"
|
||||
#include "Environment.h"
|
||||
#include "Value.h"
|
||||
#include "BobStdLib.h"
|
||||
#include "ErrorReporter.h"
|
||||
#include "ExecutionContext.h"
|
||||
#include "RuntimeDiagnostics.h"
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
@ -17,6 +6,21 @@
|
||||
#include <optional>
|
||||
#include <functional>
|
||||
|
||||
#include "Value.h"
|
||||
#include "RuntimeDiagnostics.h"
|
||||
|
||||
struct Expr;
|
||||
struct Stmt;
|
||||
struct Environment;
|
||||
struct BuiltinFunction;
|
||||
struct Function;
|
||||
struct Thunk;
|
||||
class ErrorReporter;
|
||||
struct ExecutionContext;
|
||||
struct CallExpr;
|
||||
|
||||
|
||||
|
||||
// Forward declaration
|
||||
class Evaluator;
|
||||
|
||||
@ -66,9 +70,8 @@ private:
|
||||
bool inThunkExecution = false;
|
||||
|
||||
// Automatic cleanup tracking
|
||||
int functionCreationCount = 0;
|
||||
int thunkCreationCount = 0;
|
||||
static const int CLEANUP_THRESHOLD = 1000000;
|
||||
static const int CLEANUP_THRESHOLD = 10000;
|
||||
|
||||
RuntimeDiagnostics diagnostics; // Utility functions for runtime operations
|
||||
std::unique_ptr<Evaluator> evaluator;
|
||||
@ -93,25 +96,17 @@ public:
|
||||
bool isInteractiveMode() const;
|
||||
std::shared_ptr<Environment> getEnvironment();
|
||||
void setEnvironment(std::shared_ptr<Environment> env);
|
||||
void addThunk(std::shared_ptr<Thunk> thunk);
|
||||
|
||||
void addFunction(std::shared_ptr<Function> function);
|
||||
void reportError(int line, int column, const std::string& errorType, const std::string& message, const std::string& lexeme = "");
|
||||
void addBuiltinFunction(std::shared_ptr<BuiltinFunction> func);
|
||||
void cleanupUnusedFunctions();
|
||||
void cleanupUnusedThunks();
|
||||
void forceCleanup();
|
||||
void addStdLibFunctions();
|
||||
|
||||
// Function creation count management
|
||||
void incrementFunctionCreationCount();
|
||||
int getFunctionCreationCount() const;
|
||||
void resetFunctionCreationCount();
|
||||
int getCleanupThreshold() const;
|
||||
|
||||
// Public access for Evaluator
|
||||
bool& getInThunkExecutionRef() { return inThunkExecution; }
|
||||
|
||||
private:
|
||||
Value evaluateWithoutTrampoline(const std::shared_ptr<Expr>& expr);
|
||||
void addStdLibFunctions();
|
||||
Value runTrampoline(Value initialResult);
|
||||
};
|
||||
|
||||
@ -28,8 +28,6 @@ public:
|
||||
void cleanupUnusedFunctions(std::vector<std::shared_ptr<BuiltinFunction>>& functions);
|
||||
void cleanupUnusedFunctions(std::vector<std::shared_ptr<Function>>& functions);
|
||||
void cleanupUnusedThunks(std::vector<std::shared_ptr<Thunk>>& thunks);
|
||||
void forceCleanup(std::vector<std::shared_ptr<BuiltinFunction>>& functions,
|
||||
std::vector<std::shared_ptr<Thunk>>& thunks);
|
||||
void forceCleanup(std::vector<std::shared_ptr<BuiltinFunction>>& builtinFunctions,
|
||||
std::vector<std::shared_ptr<Function>>& functions,
|
||||
std::vector<std::shared_ptr<Thunk>>& thunks);
|
||||
|
||||
@ -10,38 +10,7 @@
|
||||
struct Stmt;
|
||||
struct Environment;
|
||||
|
||||
struct Object
|
||||
{
|
||||
virtual ~Object(){};
|
||||
};
|
||||
|
||||
struct Number : Object
|
||||
{
|
||||
double value;
|
||||
explicit Number(double value) : value(value) {}
|
||||
};
|
||||
|
||||
struct String : Object
|
||||
{
|
||||
std::string value;
|
||||
explicit String(std::string str) : value(str) {}
|
||||
~String(){
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
struct Boolean : Object
|
||||
{
|
||||
bool value;
|
||||
explicit Boolean(bool value) : value(value) {}
|
||||
};
|
||||
|
||||
struct None : public Object
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
struct Function : public Object
|
||||
struct Function
|
||||
{
|
||||
const std::string name;
|
||||
const std::vector<std::string> params;
|
||||
@ -54,7 +23,7 @@ struct Function : public Object
|
||||
: name(name), params(params), body(body), closure(closure) {}
|
||||
};
|
||||
|
||||
struct BuiltinFunction : public Object
|
||||
struct BuiltinFunction
|
||||
{
|
||||
const std::string name;
|
||||
const std::function<Value(std::vector<Value>, int, int)> func;
|
||||
|
||||
@ -423,6 +423,4 @@ struct Value {
|
||||
// Global constants for common values
|
||||
extern const Value NONE_VALUE;
|
||||
extern const Value TRUE_VALUE;
|
||||
extern const Value FALSE_VALUE;
|
||||
extern const Value ZERO_VALUE;
|
||||
extern const Value ONE_VALUE;
|
||||
extern const Value FALSE_VALUE;
|
||||
@ -22,8 +22,8 @@ void Bob::runFile(const std::string& path)
|
||||
// Load source code into error reporter for context
|
||||
errorReporter.loadSource(source, path);
|
||||
|
||||
// Connect error reporter to interpreter
|
||||
interpreter->setErrorReporter(&errorReporter);
|
||||
interpreter->addStdLibFunctions();
|
||||
|
||||
this->run(source);
|
||||
}
|
||||
@ -52,6 +52,7 @@ void Bob::runPrompt()
|
||||
|
||||
// Connect error reporter to interpreter
|
||||
interpreter->setErrorReporter(&errorReporter);
|
||||
interpreter->addStdLibFunctions();
|
||||
|
||||
this->run(line);
|
||||
}
|
||||
|
||||
@ -37,27 +37,14 @@ Value Environment::get(const Token& name) {
|
||||
throw std::runtime_error("Undefined variable '" + name.lexeme + "'");
|
||||
}
|
||||
|
||||
Value Environment::get(const std::string& name) {
|
||||
auto it = variables.find(name);
|
||||
if (it != variables.end()) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
if (parent != nullptr) {
|
||||
return parent->get(name);
|
||||
}
|
||||
|
||||
throw std::runtime_error("Undefined variable '" + name + "'");
|
||||
}
|
||||
|
||||
|
||||
void Environment::pruneForClosureCapture() {
|
||||
for (auto &entry : variables) {
|
||||
Value &v = entry.second;
|
||||
if (v.isArray()) {
|
||||
// Replace with a new empty array to avoid mutating original shared storage
|
||||
entry.second = Value(std::vector<Value>{});
|
||||
} else if (v.isDict()) {
|
||||
// Replace with a new empty dict to avoid mutating original shared storage
|
||||
entry.second = Value(std::unordered_map<std::string, Value>{});
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
#include "Evaluator.h"
|
||||
#include "Interpreter.h"
|
||||
#include "Environment.h"
|
||||
#include "AssignmentUtils.h"
|
||||
#include "helperFunctions/HelperFunctions.h"
|
||||
|
||||
Evaluator::Evaluator(Interpreter* interpreter) : interpreter(interpreter) {}
|
||||
@ -212,76 +214,26 @@ Value Evaluator::visitIncrementExpr(const std::shared_ptr<IncrementExpr>& expres
|
||||
|
||||
Value Evaluator::visitAssignExpr(const std::shared_ptr<AssignExpr>& expression) {
|
||||
Value value = interpreter->evaluate(expression->value);
|
||||
|
||||
if (expression->op.type == EQUAL) {
|
||||
try {
|
||||
// Check if the variable existed and whether it held a collection
|
||||
bool existed = false;
|
||||
bool wasCollection = false;
|
||||
try {
|
||||
Value oldValue = interpreter->getEnvironment()->get(expression->name);
|
||||
existed = true;
|
||||
wasCollection = oldValue.isArray() || oldValue.isDict();
|
||||
} catch (...) {
|
||||
existed = false;
|
||||
}
|
||||
|
||||
// Assign first to release references held by the old values
|
||||
interpreter->getEnvironment()->assign(expression->name, value);
|
||||
if (expression->op.type == EQUAL) {
|
||||
// Assign first to release references held by the old values
|
||||
interpreter->getEnvironment()->assign(expression->name, value);
|
||||
// Perform cleanup on any reassignment
|
||||
interpreter->forceCleanup();
|
||||
return value;
|
||||
}
|
||||
|
||||
// Now that the old values are released, perform cleanup on any reassignment
|
||||
interpreter->forceCleanup();
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "Error during assignment: " << e.what() << std::endl;
|
||||
throw; // Re-throw to see the full stack trace
|
||||
}
|
||||
} else {
|
||||
// Handle compound assignment operators
|
||||
Value currentValue = interpreter->getEnvironment()->get(expression->name);
|
||||
Value newValue;
|
||||
|
||||
switch (expression->op.type) {
|
||||
case PLUS_EQUAL:
|
||||
newValue = currentValue + value;
|
||||
break;
|
||||
case MINUS_EQUAL:
|
||||
newValue = currentValue - value;
|
||||
break;
|
||||
case STAR_EQUAL:
|
||||
newValue = currentValue * value;
|
||||
break;
|
||||
case SLASH_EQUAL:
|
||||
newValue = currentValue / value;
|
||||
break;
|
||||
case PERCENT_EQUAL:
|
||||
newValue = currentValue % value;
|
||||
break;
|
||||
case BIN_AND_EQUAL:
|
||||
newValue = currentValue & value;
|
||||
break;
|
||||
case BIN_OR_EQUAL:
|
||||
newValue = currentValue | value;
|
||||
break;
|
||||
case BIN_XOR_EQUAL:
|
||||
newValue = currentValue ^ value;
|
||||
break;
|
||||
case BIN_SLEFT_EQUAL:
|
||||
newValue = currentValue << value;
|
||||
break;
|
||||
case BIN_SRIGHT_EQUAL:
|
||||
newValue = currentValue >> value;
|
||||
break;
|
||||
default:
|
||||
interpreter->reportError(expression->op.line, expression->op.column, "Runtime Error",
|
||||
"Unknown assignment operator: " + expression->op.lexeme, "");
|
||||
throw std::runtime_error("Unknown assignment operator: " + expression->op.lexeme);
|
||||
}
|
||||
|
||||
// Compound assignment operators
|
||||
Value currentValue = interpreter->getEnvironment()->get(expression->name);
|
||||
try {
|
||||
Value newValue = computeCompoundAssignment(currentValue, expression->op.type, value);
|
||||
interpreter->getEnvironment()->assign(expression->name, newValue);
|
||||
return newValue;
|
||||
} catch (const std::runtime_error&) {
|
||||
interpreter->reportError(expression->op.line, expression->op.column, "Runtime Error",
|
||||
"Unknown assignment operator: " + expression->op.lexeme, "");
|
||||
throw;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
Value Evaluator::visitTernaryExpr(const std::shared_ptr<TernaryExpr>& expression) {
|
||||
@ -453,10 +405,8 @@ Value Evaluator::visitFunctionExpr(const std::shared_ptr<FunctionExpr>& expressi
|
||||
paramNames.push_back(param.lexeme);
|
||||
}
|
||||
|
||||
// Capture a snapshot of the current environment so loop vars like 'i' are frozen per iteration
|
||||
auto closureEnv = std::make_shared<Environment>(*interpreter->getEnvironment());
|
||||
closureEnv->pruneForClosureCapture();
|
||||
|
||||
auto function = std::make_shared<Function>("", paramNames, expression->body, closureEnv);
|
||||
return Value(function);
|
||||
}
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
#include "Executor.h"
|
||||
#include "Evaluator.h"
|
||||
#include "Interpreter.h"
|
||||
#include "Environment.h"
|
||||
#include "AssignmentUtils.h"
|
||||
#include <iostream>
|
||||
|
||||
Executor::Executor(Interpreter* interpreter, Evaluator* evaluator)
|
||||
@ -194,66 +196,24 @@ void Executor::visitContinueStmt(const std::shared_ptr<ContinueStmt>& statement,
|
||||
}
|
||||
|
||||
void Executor::visitAssignStmt(const std::shared_ptr<AssignStmt>& statement, ExecutionContext* context) {
|
||||
try {
|
||||
Value value = statement->value->accept(evaluator);
|
||||
|
||||
if (statement->op.type == EQUAL) {
|
||||
try {
|
||||
// Assign first to release references held by the old value
|
||||
interpreter->getEnvironment()->assign(statement->name, value);
|
||||
|
||||
// Clean up on any reassignment, regardless of old/new type
|
||||
interpreter->forceCleanup();
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "Error during assignment: " << e.what() << std::endl;
|
||||
throw; // Re-throw to see the full stack trace
|
||||
}
|
||||
} else {
|
||||
// Handle compound assignment operators
|
||||
Value currentValue = interpreter->getEnvironment()->get(statement->name);
|
||||
Value newValue;
|
||||
|
||||
switch (statement->op.type) {
|
||||
case PLUS_EQUAL:
|
||||
newValue = currentValue + value;
|
||||
break;
|
||||
case MINUS_EQUAL:
|
||||
newValue = currentValue - value;
|
||||
break;
|
||||
case STAR_EQUAL:
|
||||
newValue = currentValue * value;
|
||||
break;
|
||||
case SLASH_EQUAL:
|
||||
newValue = currentValue / value;
|
||||
break;
|
||||
case PERCENT_EQUAL:
|
||||
newValue = currentValue % value;
|
||||
break;
|
||||
case BIN_AND_EQUAL:
|
||||
newValue = currentValue & value;
|
||||
break;
|
||||
case BIN_OR_EQUAL:
|
||||
newValue = currentValue | value;
|
||||
break;
|
||||
case BIN_XOR_EQUAL:
|
||||
newValue = currentValue ^ value;
|
||||
break;
|
||||
case BIN_SLEFT_EQUAL:
|
||||
newValue = currentValue << value;
|
||||
break;
|
||||
case BIN_SRIGHT_EQUAL:
|
||||
newValue = currentValue >> value;
|
||||
break;
|
||||
default:
|
||||
interpreter->reportError(statement->op.line, statement->op.column, "Runtime Error",
|
||||
"Unknown assignment operator: " + statement->op.lexeme, "");
|
||||
throw std::runtime_error("Unknown assignment operator: " + statement->op.lexeme);
|
||||
}
|
||||
|
||||
interpreter->getEnvironment()->assign(statement->name, newValue);
|
||||
Value value = statement->value->accept(evaluator);
|
||||
|
||||
if (statement->op.type == EQUAL) {
|
||||
// Assign first to release references held by the old value
|
||||
interpreter->getEnvironment()->assign(statement->name, value);
|
||||
// Clean up on any reassignment
|
||||
interpreter->forceCleanup();
|
||||
return;
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "Error in visitAssignStmt: " << e.what() << std::endl;
|
||||
throw; // Re-throw to see the full stack trace
|
||||
|
||||
// Compound assignment operators
|
||||
Value currentValue = interpreter->getEnvironment()->get(statement->name);
|
||||
try {
|
||||
Value newValue = computeCompoundAssignment(currentValue, statement->op.type, value);
|
||||
interpreter->getEnvironment()->assign(statement->name, newValue);
|
||||
} catch (const std::runtime_error&) {
|
||||
interpreter->reportError(statement->op.line, statement->op.column, "Runtime Error",
|
||||
"Unknown assignment operator: " + statement->op.lexeme, "");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,6 +2,8 @@
|
||||
#include "Evaluator.h"
|
||||
#include "Executor.h"
|
||||
#include "BobStdLib.h"
|
||||
#include "ErrorReporter.h"
|
||||
#include "Environment.h"
|
||||
#include <iostream>
|
||||
|
||||
Interpreter::Interpreter(bool isInteractive)
|
||||
@ -61,9 +63,7 @@ void Interpreter::addBuiltinFunction(std::shared_ptr<BuiltinFunction> func) {
|
||||
builtinFunctions.push_back(func);
|
||||
}
|
||||
|
||||
void Interpreter::addThunk(std::shared_ptr<Thunk> thunk) {
|
||||
thunks.push_back(thunk);
|
||||
}
|
||||
|
||||
|
||||
void Interpreter::addFunction(std::shared_ptr<Function> function) {
|
||||
functions.push_back(function);
|
||||
@ -74,7 +74,6 @@ void Interpreter::setErrorReporter(ErrorReporter* reporter) {
|
||||
if (environment) {
|
||||
environment->setErrorReporter(reporter);
|
||||
}
|
||||
addStdLibFunctions();
|
||||
}
|
||||
|
||||
bool Interpreter::isInteractiveMode() const {
|
||||
@ -121,7 +120,6 @@ Value Interpreter::evaluateCallExprInline(const std::shared_ptr<CallExpr>& expre
|
||||
}
|
||||
|
||||
if (!callee.isFunction()) {
|
||||
// Provide better error message with type information (like original)
|
||||
std::string errorMsg = "Can only call functions, got " + callee.getType();
|
||||
if (errorReporter) {
|
||||
errorReporter->reportError(expression->paren.line, expression->paren.column, "Runtime Error",
|
||||
@ -150,9 +148,8 @@ Value Interpreter::evaluateCallExprInline(const std::shared_ptr<CallExpr>& expre
|
||||
|
||||
// Check if this is a tail call for inline TCO
|
||||
if (expression->isTailCall) {
|
||||
// Create a thunk for tail call optimization - original inline version
|
||||
|
||||
auto thunk = std::make_shared<Thunk>([this, function, arguments]() -> Value {
|
||||
// Use RAII to manage environment (exactly like original)
|
||||
ScopedEnv _env(environment);
|
||||
environment = std::make_shared<Environment>(function->closure);
|
||||
environment->setErrorReporter(errorReporter);
|
||||
@ -164,12 +161,10 @@ Value Interpreter::evaluateCallExprInline(const std::shared_ptr<CallExpr>& expre
|
||||
ExecutionContext context;
|
||||
context.isFunctionBody = true;
|
||||
|
||||
// Use RAII to manage thunk execution flag
|
||||
ScopedThunkFlag _inThunk(inThunkExecution);
|
||||
|
||||
// Execute function body (inline like original - direct accept for performance)
|
||||
for (const auto& stmt : function->body) {
|
||||
stmt->accept(executor.get(), &context); // Direct call like original
|
||||
stmt->accept(executor.get(), &context);
|
||||
if (context.hasReturn) {
|
||||
return context.returnValue;
|
||||
}
|
||||
@ -178,10 +173,8 @@ Value Interpreter::evaluateCallExprInline(const std::shared_ptr<CallExpr>& expre
|
||||
return context.returnValue;
|
||||
});
|
||||
|
||||
// Store the thunk to keep it alive and return as Value (exactly like original)
|
||||
thunks.push_back(thunk);
|
||||
|
||||
// Automatic cleanup check
|
||||
thunkCreationCount++;
|
||||
if (thunkCreationCount >= CLEANUP_THRESHOLD) {
|
||||
cleanupUnusedThunks();
|
||||
@ -190,7 +183,6 @@ Value Interpreter::evaluateCallExprInline(const std::shared_ptr<CallExpr>& expre
|
||||
|
||||
return Value(thunk);
|
||||
} else {
|
||||
// Normal function call - create new environment (exactly like original)
|
||||
ScopedEnv _env(environment);
|
||||
environment = std::make_shared<Environment>(function->closure);
|
||||
environment->setErrorReporter(errorReporter);
|
||||
@ -202,9 +194,8 @@ Value Interpreter::evaluateCallExprInline(const std::shared_ptr<CallExpr>& expre
|
||||
ExecutionContext context;
|
||||
context.isFunctionBody = true;
|
||||
|
||||
// Execute function body (exactly like original - direct accept for performance)
|
||||
for (const auto& stmt : function->body) {
|
||||
stmt->accept(executor.get(), &context); // Direct call like original
|
||||
stmt->accept(executor.get(), &context);
|
||||
if (context.hasReturn) {
|
||||
return context.returnValue;
|
||||
}
|
||||
@ -213,20 +204,4 @@ Value Interpreter::evaluateCallExprInline(const std::shared_ptr<CallExpr>& expre
|
||||
return context.returnValue;
|
||||
}
|
||||
}
|
||||
|
||||
// Function creation count management
|
||||
void Interpreter::incrementFunctionCreationCount() {
|
||||
functionCreationCount++;
|
||||
}
|
||||
|
||||
int Interpreter::getFunctionCreationCount() const {
|
||||
return functionCreationCount;
|
||||
}
|
||||
|
||||
void Interpreter::resetFunctionCreationCount() {
|
||||
functionCreationCount = 0;
|
||||
}
|
||||
|
||||
int Interpreter::getCleanupThreshold() const {
|
||||
return 1000000; // Same as CLEANUP_THRESHOLD used for thunks
|
||||
}
|
||||
|
||||
|
||||
@ -13,122 +13,19 @@
|
||||
#include <algorithm>
|
||||
|
||||
|
||||
bool RuntimeDiagnostics::isTruthy(Value object) {
|
||||
if(object.isBoolean()) {
|
||||
return object.asBoolean();
|
||||
}
|
||||
|
||||
if(object.isNone()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(object.isNumber()) {
|
||||
return object.asNumber() != 0;
|
||||
}
|
||||
|
||||
if(object.isString()) {
|
||||
return object.asString().length() > 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
bool RuntimeDiagnostics::isTruthy(Value object) { return object.isTruthy(); }
|
||||
|
||||
bool RuntimeDiagnostics::isEqual(Value a, Value b) {
|
||||
// Handle none comparisons first
|
||||
if (a.isNone() || b.isNone()) {
|
||||
return a.isNone() && b.isNone();
|
||||
}
|
||||
|
||||
// Handle same type comparisons
|
||||
if (a.isNumber() && b.isNumber()) {
|
||||
return a.asNumber() == b.asNumber();
|
||||
}
|
||||
|
||||
if (a.isBoolean() && b.isBoolean()) {
|
||||
return a.asBoolean() == b.asBoolean();
|
||||
}
|
||||
|
||||
if (a.isString() && b.isString()) {
|
||||
return a.asString() == b.asString();
|
||||
}
|
||||
|
||||
if (a.isArray() && b.isArray()) {
|
||||
const std::vector<Value>& arrA = a.asArray();
|
||||
const std::vector<Value>& arrB = b.asArray();
|
||||
|
||||
if (arrA.size() != arrB.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < arrA.size(); i++) {
|
||||
if (!isEqual(arrA[i], arrB[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (a.isFunction() && b.isFunction()) {
|
||||
// Functions are equal only if they are the same object
|
||||
return a.asFunction() == b.asFunction();
|
||||
}
|
||||
|
||||
if (a.isBuiltinFunction() && b.isBuiltinFunction()) {
|
||||
// Builtin functions are equal only if they are the same object
|
||||
return a.asBuiltinFunction() == b.asBuiltinFunction();
|
||||
}
|
||||
|
||||
// Cross-type comparisons that make sense
|
||||
if (a.isNumber() && b.isBoolean()) {
|
||||
// Numbers and booleans: 0 and false are equal, non-zero and true are equal
|
||||
if (b.asBoolean()) {
|
||||
return a.asNumber() != 0.0;
|
||||
} else {
|
||||
return a.asNumber() == 0.0;
|
||||
}
|
||||
return b.asBoolean() ? (a.asNumber() != 0.0) : (a.asNumber() == 0.0);
|
||||
}
|
||||
|
||||
if (a.isBoolean() && b.isNumber()) {
|
||||
// Same as above, but reversed
|
||||
if (a.asBoolean()) {
|
||||
return b.asNumber() != 0.0;
|
||||
} else {
|
||||
return b.asNumber() == 0.0;
|
||||
}
|
||||
return a.asBoolean() ? (b.asNumber() != 0.0) : (b.asNumber() == 0.0);
|
||||
}
|
||||
|
||||
// For all other type combinations, return false
|
||||
return false;
|
||||
return a.equals(b);
|
||||
}
|
||||
|
||||
std::string RuntimeDiagnostics::stringify(Value object) {
|
||||
if(object.isNone()) {
|
||||
return "none";
|
||||
}
|
||||
else if(object.isNumber()) {
|
||||
return formatNumber(object.asNumber());
|
||||
}
|
||||
else if(object.isString()) {
|
||||
return object.asString();
|
||||
}
|
||||
else if(object.isBoolean()) {
|
||||
return object.asBoolean() == 1 ? "true" : "false";
|
||||
}
|
||||
else if(object.isFunction()) {
|
||||
return "<function " + object.asFunction()->name + ">";
|
||||
}
|
||||
else if(object.isBuiltinFunction()) {
|
||||
return "<builtin_function " + object.asBuiltinFunction()->name + ">";
|
||||
}
|
||||
else if(object.isArray()) {
|
||||
return formatArray(object.asArray());
|
||||
}
|
||||
else if(object.isDict()) {
|
||||
return formatDict(object.asDict());
|
||||
}
|
||||
|
||||
throw std::runtime_error("Could not convert object to string");
|
||||
}
|
||||
std::string RuntimeDiagnostics::stringify(Value object) { return object.toString(); }
|
||||
|
||||
std::string RuntimeDiagnostics::formatNumber(double value) {
|
||||
double integral = value;
|
||||
@ -150,31 +47,9 @@ std::string RuntimeDiagnostics::formatNumber(double value) {
|
||||
}
|
||||
}
|
||||
|
||||
std::string RuntimeDiagnostics::formatArray(const std::vector<Value>& arr) {
|
||||
std::string result = "[";
|
||||
|
||||
for (size_t i = 0; i < arr.size(); i++) {
|
||||
if (i > 0) result += ", ";
|
||||
result += stringify(arr[i]);
|
||||
}
|
||||
|
||||
result += "]";
|
||||
return result;
|
||||
}
|
||||
std::string RuntimeDiagnostics::formatArray(const std::vector<Value>& arr) { return Value(arr).toString(); }
|
||||
|
||||
std::string RuntimeDiagnostics::formatDict(const std::unordered_map<std::string, Value>& dict) {
|
||||
std::string result = "{";
|
||||
|
||||
bool first = true;
|
||||
for (const auto& pair : dict) {
|
||||
if (!first) result += ", ";
|
||||
result += "\"" + pair.first + "\": " + stringify(pair.second);
|
||||
first = false;
|
||||
}
|
||||
|
||||
result += "}";
|
||||
return result;
|
||||
}
|
||||
std::string RuntimeDiagnostics::formatDict(const std::unordered_map<std::string, Value>& dict) { return Value(dict).toString(); }
|
||||
|
||||
void RuntimeDiagnostics::cleanupUnusedFunctions(std::vector<std::shared_ptr<BuiltinFunction>>& functions) {
|
||||
// Only remove functions that are definitely not referenced anywhere (use_count == 1)
|
||||
@ -212,25 +87,7 @@ void RuntimeDiagnostics::cleanupUnusedThunks(std::vector<std::shared_ptr<Thunk>>
|
||||
);
|
||||
}
|
||||
|
||||
void RuntimeDiagnostics::forceCleanup(std::vector<std::shared_ptr<BuiltinFunction>>& functions,
|
||||
std::vector<std::shared_ptr<Thunk>>& thunks) {
|
||||
// More aggressive cleanup when breaking array references
|
||||
functions.erase(
|
||||
std::remove_if(functions.begin(), functions.end(),
|
||||
[](const std::shared_ptr<BuiltinFunction>& func) {
|
||||
return func.use_count() <= 2; // More aggressive than == 1
|
||||
}),
|
||||
functions.end()
|
||||
);
|
||||
|
||||
thunks.erase(
|
||||
std::remove_if(thunks.begin(), thunks.end(),
|
||||
[](const std::shared_ptr<Thunk>& thunk) {
|
||||
return thunk.use_count() <= 2; // More aggressive than == 1
|
||||
}),
|
||||
thunks.end()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
void RuntimeDiagnostics::forceCleanup(std::vector<std::shared_ptr<BuiltinFunction>>& builtinFunctions,
|
||||
std::vector<std::shared_ptr<Function>>& functions,
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
|
||||
#include "TypeWrapper.h"
|
||||
#include "TypeWrapper.h"
|
||||
#include <iostream>
|
||||
|
||||
|
||||
@ -4,5 +4,4 @@
|
||||
const Value NONE_VALUE = Value();
|
||||
const Value TRUE_VALUE = Value(true);
|
||||
const Value FALSE_VALUE = Value(false);
|
||||
const Value ZERO_VALUE = Value(0.0);
|
||||
const Value ONE_VALUE = Value(1.0);
|
||||
|
||||
@ -42,7 +42,7 @@ if (len(a[3692]) > 0) {
|
||||
if (a[3693]["func"]) {
|
||||
a[3693]["func"](); // Nested dict function
|
||||
}
|
||||
print(a);
|
||||
//print(a);
|
||||
//writeFile("array_contents.txt", toString(a));
|
||||
print("Array contents written to array_contents.txt");
|
||||
print("Memory before cleanup: " + memoryUsage() + " MB");
|
||||
|
||||
Loading…
Reference in New Issue
Block a user