#include "wren_inter.h" #include "../utils/stringBuilder.h" #include #include #include #include #include void writeFn(WrenVM* vm, const char* text) { StringBuilder* sb = (StringBuilder*)wrenGetUserData(vm); AppendStringBuilder(sb, text); } void errorFn(WrenVM* vm, WrenErrorType errorType, const char* module, const int line, const char* msg) { StringBuilder* sb = (StringBuilder*)wrenGetUserData(vm); switch (errorType) { case WREN_ERROR_COMPILE: AppendStringBuilder(sb, "Comptime error: "); AppendStringBuilder(sb, msg); break; case WREN_ERROR_STACK_TRACE: AppendStringBuilder(sb, "Stack trace: "); AppendStringBuilder(sb, msg); break; case WREN_ERROR_RUNTIME: AppendStringBuilder(sb, "Runtime error: "); AppendStringBuilder(sb, msg); break; } } // Obsolete char *EvaluateScript(char *script) { TraceLog(LOG_INFO, "Evaluating %s...", script); WrenVM *vm = InterpreterPrepareMachine(); if (vm == NULL) { TraceLog(LOG_ERROR, "Failed to initialize a wren vm"); return NULL; } WrenInterpretResult result = wrenInterpret(vm, "main", script); switch (result) { case WREN_RESULT_SUCCESS: break; case WREN_RESULT_COMPILE_ERROR: break; case WREN_RESULT_RUNTIME_ERROR: break; } char *outp = GetMachineOutput(vm); InterpreterFreeMachine(vm); return outp; } WrenVM *InterpreterPrepareMachine() { WrenConfiguration config; wrenInitConfiguration(&config); config.writeFn = writeFn; config.errorFn = errorFn; StringBuilder *stdout_sb = calloc(1, sizeof(StringBuilder)); config.userData = stdout_sb; return wrenNewVM(&config); } char *GetMachineOutput(WrenVM *vm) { StringBuilder* sb = (StringBuilder*)wrenGetUserData(vm); if (sb == NULL || sb->val == NULL) return NULL; return strdup(sb->val); } void InterpreterFreeMachine(WrenVM *vm) { StringBuilder* sb = (StringBuilder*)wrenGetUserData(vm); if (sb != NULL && sb->val != NULL) free(sb); wrenFreeVM(vm); } // ========== Async ========== typedef struct { // The data that you want to access in the worker void *data; // Toggle this to true when the task is finished bool is_done; } Task; bool RunWithCancellation(Task *task, void *(*runner) (void *), int timeout); #if defined(unix) || defined(__unix__) || defined(__unix) #include #include #include // Returns false if the process was aborted bool RunWithCancellation(Task *task, void *(*runner) (void *), int timeout) { pthread_t thread_id; if (pthread_create(&thread_id, NULL, runner, &task) != 0) { TraceLog(LOG_ERROR, "Failed to create a pthread"); return RESULT_INIT_ERROR; } int elapsed = 0; while (!task->is_done && elapsed < timeout) { sleep(1); elapsed += 1; } if (!task->is_done) { pthread_cancel(thread_id); pthread_join(thread_id, NULL); return false; } return true; } #endif // The task that the interpreter would need to run. Made for async reasons typedef struct { WrenVM *vm; const char *module; const char *script; WrenInterpretResult result; bool is_done; } wrenTask; // Runs the wrenTask asynchronously // FIX: Inject the cancellation parameters inside the worker thread definition void *wren_worker(void *arg) { int old_type; pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &old_type); // Task *task_raw = (Task*)arg; wrenTask *task = (wrenTask*)task_raw->data; task->result = wrenInterpret(task->vm, task->module, task->script); task_raw->is_done = true; return NULL; } enum PUZZLE_TEST_RESULT wrenInterpretLimited(WrenVM* vm, const char* module, const char* script, int sMax) { wrenTask *data = malloc(sizeof(wrenTask)); data->vm = vm; data->module = module; data->script = script; data->result = 0; Task *task = malloc(sizeof(Task)); task->is_done = false; task->data = data; if (!RunWithCancellation(task, wren_worker, sMax)) { return RESULT_TIMEOUT; } WrenInterpretResult interpret_res = data->result; free(data); free(task); switch (interpret_res) { case WREN_RESULT_COMPILE_ERROR: return RESULT_COMPTIME_ERR; case WREN_RESULT_RUNTIME_ERROR: return RESULT_RUNTIME_ERR; default: break; } return RESULT_OK; }