diff --git a/apps/bim.c b/apps/bim.c index df00fd07..9166be60 100644 --- a/apps/bim.c +++ b/apps/bim.c @@ -14,15 +14,16 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "bim-core.h" +#define ENABLE_THREADING +#include "bim.h" #ifdef __toaru__ #include #include "vm.h" #include "debug.h" #else -#include "kuroko/src/kuroko.h" -#include "kuroko/src/vm.h" -#include "kuroko/src/debug.h" +#include +#include +#include #endif global_config_t global_config = { @@ -712,24 +713,7 @@ _done: return 0; } -/** - * Close a buffer - */ -buffer_t * buffer_close(buffer_t * buf) { - int i; - - /* Locate the buffer in the buffer list */ - for (i = 0; i < buffers_len; i++) { - if (buf == buffers[i]) - break; - } - - /* This buffer doesn't exist? */ - if (i == buffers_len) { - return NULL; - } - - /* Cancel any background tasks for this env */ +void cancel_background_tasks(buffer_t * buf) { background_task_t * t = global_config.background_task; background_task_t * last = NULL; while (t) { @@ -750,6 +734,27 @@ buffer_t * buffer_close(buffer_t * buf) { t = t->next; } } +} + +/** + * Close a buffer + */ +buffer_t * buffer_close(buffer_t * buf) { + int i; + + /* Locate the buffer in the buffer list */ + for (i = 0; i < buffers_len; i++) { + if (buf == buffers[i]) + break; + } + + /* This buffer doesn't exist? */ + if (i == buffers_len) { + return NULL; + } + + /* Cancel any background tasks for this env */ + cancel_background_tasks(buf); update_biminfo(buf, 0); @@ -909,6 +914,14 @@ int syntax_space = 0; struct syntax_definition * syntaxes = NULL; void add_syntax(struct syntax_definition def) { + /* See if a name match already exists for this def. */ + for (struct syntax_definition * s = syntaxes; syntaxes && s->name; ++s) { + if (!strcmp(def.name,s->name)) { + *s = def; + return; + } + } + if (syntax_space == 0) { syntax_space = 4; syntaxes = calloc(sizeof(struct syntax_definition), syntax_space); @@ -921,6 +934,8 @@ void add_syntax(struct syntax_definition def) { syntax_count++; } +void redraw_all(void); + /** * Calculate syntax highlighting for the given line, and lines after * if their initial syntax state has changed by this recalculation. @@ -958,21 +973,15 @@ void recalculate_syntax(line_t * line, int line_no) { krk_push(OBJECT_VAL(s)); KrkValue result = krk_callSimple(OBJECT_VAL(env->syntax->krkFunc), 1, 0); krk_currentThread.stackTop = krk_currentThread.stack + before; - if (IS_NONE(result) && (krk_currentThread.flags & KRK_HAS_EXCEPTION)) { + if (IS_NONE(result) && (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION)) { render_error("Exception occurred in plugin: %s", AS_INSTANCE(krk_currentThread.currentException)->_class->name->chars); + render_commandline_message("\n"); krk_dumpTraceback(); - fprintf(stderr,"\n\nThis syntax highlighter will be disabled in this environment.\n\n"); - int key = 0; - while ((key = bim_getkey(DEFAULT_KEY_WAIT)) == KEY_TIMEOUT); - env->syntax = NULL; - return; + goto _syntaxError; } else if (!IS_NONE(result) && !IS_INTEGER(result)) { - fprintf(stderr, "Instead of an integer, got %s\n", krk_typeName(result)); - fprintf(stderr,"\n\nThis syntax highlighter will be disabled in this environment.\n\n"); - int key = 0; - while ((key = bim_getkey(DEFAULT_KEY_WAIT)) == KEY_TIMEOUT); - env->syntax = NULL; - return; + render_error("Instead of an integer, got %s", krk_typeName(result)); + render_commandline_message("\n"); + goto _syntaxError; } s->state.state = IS_NONE(result) ? -1 : AS_INTEGER(result); @@ -996,6 +1005,14 @@ void recalculate_syntax(line_t * line, int line_no) { _next: (void)0; } + +_syntaxError: + krk_resetStack(); + fprintf(stderr,"This syntax highlighter will be disabled in this environment."); + env->syntax = NULL; + cancel_background_tasks(env); + pause_for_key(); + redraw_all(); } /** @@ -3686,8 +3703,6 @@ void run_onload(buffer_t * env) { static void render_syntax_async(background_task_t * task) { buffer_t * old_env = env; env = task->env; - struct syntax_definition * old_syn = env->syntax; - env->syntax = task->_private_p; int line_no = task->_private_i; if (env->line_count && line_no < env->line_count) { @@ -3699,8 +3714,6 @@ static void render_syntax_async(background_task_t * task) { redraw_line(line_no); } } - - env->syntax = old_syn; env = old_env; } @@ -3717,7 +3730,6 @@ static void schedule_complete_recalc(void) { background_task_t * task = malloc(sizeof(background_task_t)); task->env = env; task->_private_i = i; - task->_private_p = env->syntax; task->func = render_syntax_async; task->next = NULL; if (global_config.tail_task) { @@ -5480,7 +5492,7 @@ BIM_COMMAND(theme,"theme","Set color theme") { ptrdiff_t before = krk_currentThread.stackTop - krk_currentThread.stack; KrkValue result = krk_callSimple(OBJECT_VAL(d->callable), 0, 0); krk_currentThread.stackTop = krk_currentThread.stack + before; - if (IS_NONE(result) && (krk_currentThread.flags & KRK_HAS_EXCEPTION)) { + if (IS_NONE(result) && (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION)) { render_error("Exception occurred in theme: %s", AS_INSTANCE(krk_currentThread.currentException)->_class->name->chars); krk_dumpTraceback(); int key = 0; @@ -6610,7 +6622,12 @@ void find_match_backwards(int from_line, int from_col, int * out_line, int * out void rehighlight_search(line_t * line) { if (!global_config.search) return; int j = 0; + while (j < line->actual) { + line->text[j].flags &= ~(FLAG_SEARCH); + j++; + } int ignorecase = smart_case(global_config.search); + j = 0; while (j < line->actual) { int matchlen = 0; if (subsearch_matches(line, j, global_config.search, ignorecase, &matchlen)) { @@ -9932,7 +9949,7 @@ int process_krk_command(const char * cmd, KrkValue * outVal) { * get printed by the interpreter and we can't catch it here. */ krk_currentThread.frames[0].outSlots = 1; /* Call the interpreter */ - KrkValue out = krk_interpret(cmd,0,"",""); + KrkValue out = krk_interpret(cmd,""); /* If the user typed just a command name, try to execute it. */ if (krk_isInstanceOf(out,CommandDef)) { krk_push(out); @@ -9942,7 +9959,7 @@ int process_krk_command(const char * cmd, KrkValue * outVal) { int retval = (IS_INTEGER(out)) ? AS_INTEGER(out) : 0; int hadOutput = 0; /* If we got an exception during execution, print it now */ - if (krk_currentThread.flags & KRK_HAS_EXCEPTION) { + if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) { if (krk_isInstanceOf(krk_currentThread.currentException, vm.exceptions->syntaxError)) { } set_fg_color(COLOR_RED); @@ -10028,7 +10045,7 @@ BIM_COMMAND(runkrk,"runkrk", "Run a kuroko script") { /* In case we're running in a weird context? */ int previousExitFrame = krk_currentThread.exitOnFrame; krk_currentThread.exitOnFrame = krk_currentThread.frameCount; - krk_runfile(argv[1],1,"",argv[1]); + krk_runfile(argv[1],argv[1]); krk_currentThread.exitOnFrame = previousExitFrame; redraw_all(); @@ -10175,7 +10192,7 @@ static KrkValue krk_bim_register_syntax(int argc, KrkValue argv[], int hasKw) { if (!IS_STRING(name)) return krk_runtimeError(vm.exceptions->typeError, "%s.name must be str", AS_CLASS(argv[0])->name->chars); if (!IS_TUPLE(extensions)) - return krk_runtimeError(vm.exceptions->typeError, "%s.extensions must by tuple", AS_CLASS(argv[0])->name->chars); + return krk_runtimeError(vm.exceptions->typeError, "%s.extensions must be tuple", AS_CLASS(argv[0])->name->chars); if (!IS_BOOLEAN(spaces)) return krk_runtimeError(vm.exceptions->typeError, "%s.spaces must be bool", AS_CLASS(argv[0])->name->chars); if (!IS_CLOSURE(calculate)) @@ -10528,7 +10545,7 @@ void import_directory(char * dirName) { "if '%s%s' not in kuroko.module_paths:\n" " kuroko.module_paths.insert(0,'%s%s')\n", dirpath, extra, dirpath, extra); - krk_interpret(tmp,1,"",""); + krk_interpret(tmp,""); } if (dirpath) free(dirpath); @@ -10538,7 +10555,7 @@ void import_directory(char * dirName) { char * tmp = malloc(strlen(dirName) + 1 + strlen(ent->d_name) + 1 + 7); snprintf(tmp, strlen(dirName) + 1 + strlen(ent->d_name) + 1 + 7, "import %s.%s", dirName, ent->d_name); tmp[strlen(tmp)-4] = '\0'; - krk_interpret(tmp,1,"",ent->d_name); + krk_interpret(tmp,ent->d_name); free(tmp); } ent = readdir(dirp); @@ -10576,6 +10593,33 @@ static void findBim(char * argv[]) { } /* Else, give up at this point and just don't attach it at all. */ } +BIM_COMMAND(reload,"reload","Reloads all the Kuroko stuff.") { + /* Unload everything syntax-y */ + KrkValue result = krk_interpret( + "if True:\n" + " import kuroko\n" + " for mod in kuroko.modules():\n" + " if mod.startswith('syntax.') or mod.startswith('themes.'):\n" + " kuroko.unload(mod)\n", ""); + + if (IS_NONE(result) && (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION)) { + krk_dumpTraceback(); + return 1; + } + + /* Reload everything */ + krk_resetStack(); + krk_startModule(""); + import_directory("syntax"); + krk_startModule(""); + import_directory("themes"); + krk_startModule(""); + /* Re-run the RC file */ + load_bimrc(); + krk_resetStack(); + return 0; +} + /** * Run global initialization tasks */ @@ -10614,9 +10658,7 @@ void initialize(void) { global_config.tab_indicator = strdup(">"); global_config.space_indicator = strdup("-"); - fprintf(stderr, "init vm\n"); krk_initVM(0); /* no debug flags */ - fprintf(stderr, "done\n"); KrkInstance * bimModule = krk_newInstance(vm.baseClasses->moduleClass); krk_attachNamedObject(&vm.modules, "bim", (KrkObj*)bimModule); @@ -10708,6 +10750,9 @@ void initialize(void) { load_bimrc(); krk_resetStack(); + /* Disable default traceback printing */ + vm.globalFlags |= KRK_GLOBAL_CLEAN_OUTPUT; + /* Initialize space for buffers */ buffers_avail = 4; buffers = malloc(sizeof(buffer_t *) * buffers_avail); diff --git a/apps/bim-core.h b/apps/bim.h similarity index 99% rename from apps/bim-core.h rename to apps/bim.h index 9b3d3145..13a5c942 100644 --- a/apps/bim-core.h +++ b/apps/bim.h @@ -22,6 +22,11 @@ #include #include #include +#ifdef __toaru__ +#include "vm.h" +#else +#include +#endif #ifdef __DATE__ # define BIM_BUILD_DATE " built " __DATE__ " at " __TIME__ @@ -35,7 +40,7 @@ # define TAG "-alpha" #endif -#define BIM_VERSION "3.0.0" TAG +#define BIM_VERSION "2.99.0" TAG #define BIM_COPYRIGHT "Copyright 2012-2021 K. Lange <\033[3mklange@toaruos.org\033[23m>" #define BLOCK_SIZE 4096 diff --git a/apps/kuroko.c b/apps/kuroko.c index 39360b9e..3fe97886 100644 --- a/apps/kuroko.c +++ b/apps/kuroko.c @@ -28,6 +28,7 @@ #include "vm.h" #include "memory.h" #include "scanner.h" +#include "compiler.h" #define PROMPT_MAIN ">>> " #define PROMPT_BLOCK " > " @@ -166,9 +167,10 @@ static void tab_complete_func(rline_context_t * c) { krk_push(thisValue); if (IS_CLOSURE(thisValue) || IS_BOUND_METHOD(thisValue) || (IS_NATIVE(thisValue) && ((KrkNative*)AS_OBJECT(thisValue))->isMethod != 2)) { - char * tmp = malloc(s->length + 2); - sprintf(tmp, "%s(", s->chars); - s = krk_takeString(tmp, strlen(tmp)); + size_t allocSize = s->length + 2; + char * tmp = malloc(allocSize); + size_t len = snprintf(tmp, allocSize, "%s(", s->chars); + s = krk_takeString(tmp, len); krk_pop(); krk_push(OBJECT_VAL(s)); } @@ -274,9 +276,253 @@ _cleanup: } #endif +static char * lastDebugCommand = NULL; +static int debuggerHook(KrkCallFrame * frame) { + + /* File information */ + fprintf(stderr, "At offset 0x%04lx of function '%s' from '%s' on line %lu:\n", + (unsigned long)(frame->ip - frame->closure->function->chunk.code), + frame->closure->function->name->chars, + frame->closure->function->chunk.filename->chars, + (unsigned long)krk_lineNumber(&frame->closure->function->chunk, + (unsigned long)(frame->ip - frame->closure->function->chunk.code))); + + /* Opcode trace */ + krk_disassembleInstruction( + stderr, + frame->closure->function, + (size_t)(frame->ip - frame->closure->function->chunk.code)); + + krk_debug_dumpStack(stderr, frame); + + while (1) { + char buf[4096] = {0}; +#ifndef NO_RLINE + if (enableRline) { + rline_exit_string=""; + rline_exp_set_prompts("(dbg) ", "", 6, 0); + rline_exp_set_syntax("krk-dbg"); + rline_exp_set_tab_complete_func(NULL); + if (rline(buf, 4096) == 0) goto _dbgQuit; + } else { +#endif + fprintf(stderr, "(dbg) "); + fflush(stderr); + char * out = fgets(buf, 4096, stdin); + if (!out || !strlen(buf)) { + fprintf(stdout, "^D\n"); + goto _dbgQuit; + } +#ifndef NO_RLINE + } +#endif + + char * nl = strstr(buf,"\n"); + if (nl) *nl = '\0'; + + if (!strlen(buf)) { + if (lastDebugCommand) { + strcpy(buf, lastDebugCommand); + } else { + continue; + } + } else { +#ifndef NO_RLINE + if (enableRline) rline_history_insert(strdup(buf)); +#endif + if (lastDebugCommand) free(lastDebugCommand); + lastDebugCommand = strdup(buf); + } + + /* Try to tokenize the first bit */ + char * arg = NULL; + char * sp = strstr(buf," "); + if (sp) { + *sp = '\0'; + arg = sp + 1; + } + /* Now check commands */ + if (!strcmp(buf, "c") || !strcmp(buf,"continue")) { + return KRK_DEBUGGER_CONTINUE; + } else if (!strcmp(buf, "s") || !strcmp(buf, "step")) { + return KRK_DEBUGGER_STEP; + } else if (!strcmp(buf, "abort")) { + return KRK_DEBUGGER_ABORT; + } else if (!strcmp(buf, "q") || !strcmp(buf, "quit")) { + return KRK_DEBUGGER_QUIT; + } else if (!strcmp(buf, "bt") || !strcmp(buf, "backtrace")) { + krk_debug_dumpTraceback(); + } else if (!strcmp(buf, "p") || !strcmp(buf, "print")) { + if (!arg) { + fprintf(stderr, "print requires an argument\n"); + } else { + size_t frameCount = krk_currentThread.frameCount; + /* Compile statement */ + KrkFunction * expression = krk_compile(arg,""); + if (expression) { + /* Make sure stepping is disabled first. */ + krk_debug_disableSingleStep(); + /* Turn our compiled expression into a callable. */ + krk_push(OBJECT_VAL(expression)); + krk_push(OBJECT_VAL(krk_newClosure(expression))); + /* Stack silliness, don't ask. */ + krk_push(NONE_VAL()); + krk_pop(); + /* Call the compiled expression with no args, but claim 2 method extras. */ + krk_push(krk_callSimple(krk_peek(0), 0, 2)); + fprintf(stderr, "\033[1;30m=> "); + krk_printValue(stderr, krk_peek(0)); + fprintf(stderr, "\033[0m\n"); + krk_pop(); + } + if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) { + krk_dumpTraceback(); + krk_currentThread.flags &= ~(KRK_THREAD_HAS_EXCEPTION); + } + krk_currentThread.frameCount = frameCount; + } + } else if (!strcmp(buf, "break") || !strcmp(buf, "b")) { + char * filename = arg; + if (!filename) { + fprintf(stderr, "usage: break FILE LINE [type]\n"); + continue; + } + + char * lineno = strstr(filename, " "); + if (!lineno) { + fprintf(stderr, "usage: break FILE LINE [type]\n"); + continue; + } + + /* Advance whitespace */ + *lineno = '\0'; + lineno++; + + /* collect optional type */ + int flags = KRK_BREAKPOINT_NORMAL; + char * type = strstr(lineno, " "); + if (type) { + *type = '\0'; type++; + if (!strcmp(type, "repeat") || !strcmp(type,"r")) { + flags = KRK_BREAKPOINT_REPEAT; + } else if (!strcmp(type, "once") || !strcmp(type,"o")) { + flags = KRK_BREAKPOINT_ONCE; + } else { + fprintf(stderr, "Unrecognized breakpoint type: %s\n", type); + continue; + } + } + + int lineInt = atoi(lineno); + int result = krk_debug_addBreakpointFileLine(krk_copyString(filename, strlen(filename)), lineInt, flags); + + if (result == -1) { + fprintf(stderr, "Sorry, couldn't add breakpoint.\n"); + } else { + fprintf(stderr, "Breakpoint %d enabled.\n", result); + } + + } else if (!strcmp(buf, "i") || !strcmp(buf, "info")) { + if (!arg) { + fprintf(stderr, " info breakpoints - Show breakpoints.\n"); + continue; + } + + if (!strcmp(arg,"breakpoints")) { + KrkFunction * codeObject = NULL; + size_t offset = 0; + int flags = 0; + int enabled = 0; + int breakIndex = 0; + while (1) { + int result = krk_debug_examineBreakpoint(breakIndex, &codeObject, &offset, &flags, &enabled); + if (result == -1) break; + if (result == -2) continue; + + fprintf(stderr, "%-4d in %s+%d %s %s\n", + breakIndex, + codeObject->name->chars, + (int)offset, + flags == KRK_BREAKPOINT_NORMAL ? "normal": + flags == KRK_BREAKPOINT_REPEAT ? "repeat" : + flags == KRK_BREAKPOINT_ONCE ? "once" : "?", + enabled ? "enabled" : "disabled"); + + breakIndex++; + } + } else { + fprintf(stderr, "Unrecognized info object: %s\n", arg); + } + + } else if (!strcmp(buf, "e") || !strcmp(buf, "enable")) { + if (!arg) { + fprintf(stderr, "enable requires an argument\n"); + continue; + } + + int breakIndex = atoi(arg); + + if (krk_debug_enableBreakpoint(breakIndex)) { + fprintf(stderr, "Invalid breakpoint handle.\n"); + } else { + fprintf(stderr, "Breakpoint %d enabled.\n", breakIndex); + } + } else if (!strcmp(buf, "d") || !strcmp(buf, "disable")) { + if (!arg) { + fprintf(stderr, "disable requires an argument\n"); + continue; + } + + int breakIndex = atoi(arg); + + if (krk_debug_disableBreakpoint(breakIndex)) { + fprintf(stderr, "Invalid breakpoint handle.\n"); + } else { + fprintf(stderr, "Breakpoint %d disabled.\n", breakIndex); + } + } else if (!strcmp(buf, "r") || !strcmp(buf, "remove")) { + if (!arg) { + fprintf(stderr, "remove requires an argument\n"); + continue; + } + + int breakIndex = atoi(arg); + + if (krk_debug_removeBreakpoint(breakIndex)) { + fprintf(stderr, "Invalid breakpoint handle.\n"); + } else { + fprintf(stderr, "Breakpoint %d removed.\n", breakIndex); + } + } else if (!strcmp(buf, "help")) { + fprintf(stderr, + "Kuroko Interactive Debugger\n" + " c continue - Continue until the next breakpoint.\n" + " s step - Execute this instruction and return to the debugger.\n" + " bt backtrace - Print a backtrace.\n" + " q quit - Exit the interpreter.\n" + " abort - Abort the interpreter (may create a core dump).\n" + " b break ... - Set a breakpoint.\n" + " e enable N - Enable breakpoint 'N'.\n" + " d disable N - Disable breakpoint 'N'.\n" + " r remove N - Remove breakpoint 'N'.\n" + " i info ... - See information about breakpoints.\n" + "\n" + "Empty input lines will repeat the last command.\n" + ); + } else { + fprintf(stderr, "Unrecognized command: %s\n", buf); + } + + } + + return KRK_DEBUGGER_CONTINUE; +_dbgQuit: + return KRK_DEBUGGER_QUIT; +} + static void handleSigint(int sigNum) { if (krk_currentThread.frameCount) { - krk_runtimeError(vm.exceptions->keyboardInterrupt, "Keyboard interrupt."); + krk_currentThread.flags |= KRK_THREAD_SIGNALLED; } signal(sigNum, handleSigint); @@ -287,10 +533,11 @@ static void findInterpreter(char * argv[]) { vm.binpath = strdup(_pgmptr); #else /* Try asking /proc */ - char * binpath = realpath("/proc/self/exe", NULL); + char tmp[4096]; + char * binpath = realpath("/proc/self/exe", tmp); if (!binpath || (access(binpath, X_OK) != 0)) { if (strchr(argv[0], '/')) { - binpath = realpath(argv[0], NULL); + binpath = realpath(argv[0], tmp); } else { /* Search PATH for argv[0] */ char * _path = strdup(getenv("PATH")); @@ -299,10 +546,9 @@ static void findInterpreter(char * argv[]) { char * next = strchr(path,':'); if (next) *next++ = '\0'; - char tmp[4096]; - sprintf(tmp, "%s/%s", path, argv[0]); + snprintf(tmp, 4096, "%s/%s", path, argv[0]); if (access(tmp, X_OK) == 0) { - binpath = strdup(tmp); + binpath = tmp; break; } path = next; @@ -320,13 +566,11 @@ static int runString(char * argv[], int flags, char * string) { findInterpreter(argv); krk_initVM(flags); krk_startModule("__main__"); - krk_interpret(string, 1, "",""); + krk_interpret(string, ""); krk_freeVM(); return 0; } -/* This isn't normally exposed. */ -extern KrkFunction * krk_compile(const char * src, int newScope, char * fileName); static int compileFile(char * argv[], int flags, char * fileName) { findInterpreter(argv); krk_initVM(flags); @@ -351,10 +595,10 @@ static int compileFile(char * argv[], int flags, char * fileName) { krk_startModule("__main__"); /* Call the compiler directly. */ - KrkFunction * func = krk_compile(buf, 0, fileName); + KrkFunction * func = krk_compile(buf, fileName); /* See if there was an exception. */ - if (krk_currentThread.flags & KRK_HAS_EXCEPTION) { + if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) { krk_dumpTraceback(); } @@ -378,28 +622,35 @@ static int compileFile(char * argv[], int flags, char * fileName) { #endif int main(int argc, char * argv[]) { +#ifdef _WIN32 + SetConsoleOutputCP(65001); + SetConsoleCP(65001); +#endif int flags = 0; int moduleAsMain = 0; int opt; - while ((opt = getopt(argc, argv, "+c:C:dgm:rstMV-:")) != -1) { + while ((opt = getopt(argc, argv, "+c:C:dgm:rstMSV-:")) != -1) { switch (opt) { case 'c': return runString(argv, flags, optarg); case 'd': /* Disassemble code blocks after compilation. */ - flags |= KRK_ENABLE_DISASSEMBLY; + flags |= KRK_THREAD_ENABLE_DISASSEMBLY; break; case 'g': /* Always garbage collect during an allocation. */ - flags |= KRK_ENABLE_STRESS_GC; + flags |= KRK_GLOBAL_ENABLE_STRESS_GC; break; case 's': /* Print debug information during compilation. */ - flags |= KRK_ENABLE_SCAN_TRACING; + flags |= KRK_THREAD_ENABLE_SCAN_TRACING; + break; + case 'S': + flags |= KRK_THREAD_SINGLE_STEP; break; case 't': /* Disassemble instructions as they are executed. */ - flags |= KRK_ENABLE_TRACING; + flags |= KRK_THREAD_ENABLE_TRACING; break; case 'm': moduleAsMain = 1; @@ -429,6 +680,7 @@ int main(int argc, char * argv[]) { " -t Disassemble instructions as they are exceuted.\n" " -C file Compile 'file', but do not execute it.\n" " -M Print the default module import paths.\n" + " -S Enable single-step debugging.\n" " -V Print version information.\n" "\n" " --version Print version information.\n" @@ -449,6 +701,8 @@ _finishArgs: findInterpreter(argv); krk_initVM(flags); + krk_debug_registerCallback(debuggerHook); + /* Attach kuroko.argv - argv[0] will be set to an empty string for the repl */ if (argc == optind) krk_push(OBJECT_VAL(krk_copyString("",0))); for (int arg = optind; arg < argc; ++arg) { @@ -471,17 +725,11 @@ _finishArgs: KrkValue result = INTEGER_VAL(0); if (moduleAsMain) { - /* This isn't going to do what we want for built-in modules, but I'm not sure - * what we _should_ do for them anyway... let's just leave that as a TODO; - * we do let C modules know they are the __main__ now, so non-built-in - * C modules can still act as scripts if they want... */ - KrkValue module; krk_push(OBJECT_VAL(krk_copyString("__main__",8))); - int out = !krk_loadModule( + int out = !krk_importModule( AS_STRING(AS_LIST(argList)->values[0]), - &module, AS_STRING(krk_peek(0))); - if (krk_currentThread.flags & KRK_HAS_EXCEPTION) { + if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) { krk_dumpTraceback(); krk_resetStack(); } @@ -493,18 +741,9 @@ _finishArgs: /* The repl runs in the context of a top-level module so each input * line can share a globals state with the others. */ - krk_startModule(""); + krk_startModule("__main__"); krk_attachNamedValue(&krk_currentThread.module->fields,"__doc__", NONE_VAL()); -#ifndef NO_RLINE - /* Set ^D to send EOF */ - rline_exit_string=""; - /* Enable syntax highlight for Kuroko */ - rline_exp_set_syntax("krk"); - /* Bind a callback for \t */ - rline_exp_set_tab_complete_func(tab_complete_func); -#endif - /** * Python stores version info in a built-in module called `sys`. * We are not Python, we'll use `sys` to pretend to be Python @@ -540,6 +779,12 @@ _finishArgs: #ifndef NO_RLINE /* Main prompt is >>> like in Python */ rline_exp_set_prompts(PROMPT_MAIN, "", 4, 0); + /* Set ^D to send EOF */ + rline_exit_string=""; + /* Enable syntax highlight for Kuroko */ + rline_exp_set_syntax("krk"); + /* Bind a callback for \t */ + rline_exp_set_tab_complete_func(tab_complete_func); #endif while (1) { @@ -671,7 +916,7 @@ _finishArgs: FREE_ARRAY(char *, lines, lineCapacity); if (valid) { - KrkValue result = krk_interpret(allData, 0, "",""); + KrkValue result = krk_interpret(allData, ""); if (!IS_NONE(result)) { KrkClass * type = krk_getType(result); const char * formatStr = " \033[1;30m=> %s\033[0m\n"; @@ -687,8 +932,8 @@ _finishArgs: } else { fprintf(stdout, formatStr, AS_CSTRING(result)); } - krk_resetStack(); } + krk_resetStack(); free(allData); } @@ -696,7 +941,8 @@ _finishArgs: } } else { krk_startModule("__main__"); - result = krk_runfile(argv[optind],1,"__main__",argv[optind]); + result = krk_runfile(argv[optind],argv[optind]); + if (IS_NONE(result) && krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) result = INTEGER_VAL(1); } krk_freeVM(); diff --git a/kuroko b/kuroko index 6a95c4a9..34c8d687 160000 --- a/kuroko +++ b/kuroko @@ -1 +1 @@ -Subproject commit 6a95c4a97921e9aa76fda65e1f289428dd95e4b2 +Subproject commit 34c8d68720ea5ee736b49094b8b1836a267604a9