void wrenDebugPrintStackTrace(ObjFiber* fiber) { if (IS_STRING(fiber->error)) { fprintf(stderr, "%s\n", AS_CSTRING(fiber->error)); } else { // TODO: Print something a little useful here. Maybe the name of the error's // class? fprintf(stderr, "[error object]\n"); } for (int i = fiber->numFrames - 1; i >= 0; i--) { CallFrame* frame = &fiber->frames[i]; ObjFn* fn = wrenGetFrameFunction(frame); // Built-in libraries and method call stubs have no source path and are // explicitly omitted from stack traces since we don't want to highlight to // a user the implementation detail of what part of a core library is // implemented in C and what is in Wren. if (fn->debug->sourcePath == NULL || fn->debug->sourcePath->length == 0) { continue; } // -1 because IP has advanced past the instruction that it just executed. int line = fn->debug->sourceLines[frame->ip - fn->bytecode - 1]; fprintf(stderr, "[%s line %d] in %s\n", fn->debug->sourcePath->value, line, fn->debug->name); } }
const char* wrenGetArgumentString(WrenVM* vm, int index) { ASSERT(vm->foreignCallSlot != NULL, "Must be in foreign call."); ASSERT(index >= 0, "index cannot be negative."); ASSERT(index < vm->foreignCallNumArgs, "Not that many arguments."); // TODO: Check actual value type first. return AS_CSTRING(*(vm->foreignCallSlot + index)); }
void wrenDebugPrintStackTrace(WrenVM* vm) { // Bail if the host doesn't enable printing errors. if (vm->config.errorFn == NULL) return; ObjFiber* fiber = vm->fiber; if (IS_STRING(fiber->error)) { vm->config.errorFn(vm, WREN_ERROR_RUNTIME, NULL, -1, AS_CSTRING(fiber->error)); } else { // TODO: Print something a little useful here. Maybe the name of the error's // class? vm->config.errorFn(vm, WREN_ERROR_RUNTIME, NULL, -1, "[error object]"); } for (int i = fiber->numFrames - 1; i >= 0; i--) { CallFrame* frame = &fiber->frames[i]; ObjFn* fn = frame->closure->fn; // Skip over stub functions for calling methods from the C API. if (fn->module == NULL) continue; // The built-in core module has no name. We explicitly omit it from stack // traces since we don't want to highlight to a user the implementation // detail of what part of the core module is written in C and what is Wren. if (fn->module->name == NULL) continue; // -1 because IP has advanced past the instruction that it just executed. int line = fn->debug->sourceLines.data[frame->ip - fn->code.data - 1]; vm->config.errorFn(vm, WREN_ERROR_STACK_TRACE, fn->module->name->value, line, fn->debug->name); } }