diff --git a/CHANGELOG.md b/CHANGELOG.md index 850ae1e3..f1033662 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. ## Unreleased - ??? - Silence warnings in some compilers. +- Allow passing a second argument to `disasm`. +- Add `cancel`. Resumes a fiber but makes it immediately error at the yield point. +- Allow multi-line paste into built in repl. +- Add `(curenv)`. - Change `net/read`, `net/chunk`, and `net/write` to raise errors in the case of failures. - Add `janet_continue_signal` to C API. This indirectly enables C functions that yield to the event loop to raise errors or other signals. @@ -16,7 +20,7 @@ All notable changes to this project will be documented in this file. - Expose `janet_cryptorand` in C API. - Properly initialize PRF in default janet program - Add `index-of` to core library. -- Add `-fPIC` back to core CFLAGS (non-optional when compiling default client with Makefile) +- Add `-fPIC` back to core CFLAGS (non-optional when compiling default client with Makefile) - Fix defaults on Windows for ARM - Fix defaults on NetBSD. diff --git a/src/boot/boot.janet b/src/boot/boot.janet index 74d8ba73..f814e8f5 100644 --- a/src/boot/boot.janet +++ b/src/boot/boot.janet @@ -2069,6 +2069,14 @@ (if ec "\e[0m" ""))) (eflush)) +(defn curenv + "Get the current environment table. Same as (fiber/getenv (fiber/current)). If n + is provided, gets the nth prototype of the environment table." + [&opt n] + (var e (fiber/getenv (fiber/current))) + (if n (repeat n (if (= nil e) (break)) (set e (table/getproto e)))) + e) + (defn run-context "Run a context. This evaluates expressions in an environment, and is encapsulates the parsing, compilation, and evaluation. diff --git a/src/conf/janetconf.h b/src/conf/janetconf.h index 62a68d7d..a4d8f40f 100644 --- a/src/conf/janetconf.h +++ b/src/conf/janetconf.h @@ -58,6 +58,7 @@ /* #define JANET_NO_UMASK */ /* Other settings */ +/* #define JANET_DEBUG */ /* #define JANET_PRF */ /* #define JANET_NO_UTC_MKTIME */ /* #define JANET_OUT_OF_MEMORY do { printf("janet out of memory\n"); exit(1); } while (0) */ diff --git a/src/core/asm.c b/src/core/asm.c index 961b671d..d9516c32 100644 --- a/src/core/asm.c +++ b/src/core/asm.c @@ -73,6 +73,7 @@ static const JanetInstructionDef janet_ops[] = { {"call", JOP_CALL}, {"clo", JOP_CLOSURE}, {"cmp", JOP_COMPARE}, + {"cncl", JOP_CANCEL}, {"div", JOP_DIVIDE}, {"divim", JOP_DIVIDE_IMMEDIATE}, {"eq", JOP_EQUALS}, @@ -840,85 +841,110 @@ Janet janet_asm_decode_instruction(uint32_t instr) { return janet_wrap_nil(); } -Janet janet_disasm(JanetFuncDef *def) { - int32_t i; +/* + * Disasm sections + */ + +static Janet janet_disasm_arity(JanetFuncDef *def) { + return janet_wrap_integer(def->arity); +} + +static Janet janet_disasm_min_arity(JanetFuncDef *def) { + return janet_wrap_integer(def->min_arity); +} + +static Janet janet_disasm_max_arity(JanetFuncDef *def) { + return janet_wrap_integer(def->max_arity); +} + +static Janet janet_disasm_slotcount(JanetFuncDef *def) { + return janet_wrap_integer(def->slotcount); +} + +static Janet janet_disasm_bytecode(JanetFuncDef *def) { JanetArray *bcode = janet_array(def->bytecode_length); - JanetArray *constants; - JanetTable *ret = janet_table(10); - janet_table_put(ret, janet_ckeywordv("arity"), janet_wrap_integer(def->arity)); - janet_table_put(ret, janet_ckeywordv("min-arity"), janet_wrap_integer(def->min_arity)); - janet_table_put(ret, janet_ckeywordv("max-arity"), janet_wrap_integer(def->max_arity)); - janet_table_put(ret, janet_ckeywordv("bytecode"), janet_wrap_array(bcode)); - if (NULL != def->source) { - janet_table_put(ret, janet_ckeywordv("source"), janet_wrap_string(def->source)); - } - if (def->flags & JANET_FUNCDEF_FLAG_VARARG) { - janet_table_put(ret, janet_ckeywordv("vararg"), janet_wrap_true()); - } - if (NULL != def->name) { - janet_table_put(ret, janet_ckeywordv("name"), janet_wrap_string(def->name)); - } - - /* Add constants */ - if (def->constants_length > 0) { - constants = janet_array(def->constants_length); - janet_table_put(ret, janet_ckeywordv("constants"), janet_wrap_array(constants)); - for (i = 0; i < def->constants_length; i++) { - constants->data[i] = def->constants[i]; - } - constants->count = def->constants_length; - } - - /* Add bytecode */ - for (i = 0; i < def->bytecode_length; i++) { + for (int32_t i = 0; i < def->bytecode_length; i++) { bcode->data[i] = janet_asm_decode_instruction(def->bytecode[i]); } bcode->count = def->bytecode_length; + return janet_wrap_array(bcode); +} - /* Add source map */ - if (NULL != def->sourcemap) { - JanetArray *sourcemap = janet_array(def->bytecode_length); - for (i = 0; i < def->bytecode_length; i++) { - Janet *t = janet_tuple_begin(2); - JanetSourceMapping mapping = def->sourcemap[i]; - t[0] = janet_wrap_integer(mapping.line); - t[1] = janet_wrap_integer(mapping.column); - sourcemap->data[i] = janet_wrap_tuple(janet_tuple_end(t)); - } - sourcemap->count = def->bytecode_length; - janet_table_put(ret, janet_ckeywordv("sourcemap"), janet_wrap_array(sourcemap)); +static Janet janet_disasm_source(JanetFuncDef *def) { + if (def->source != NULL) return janet_wrap_string(def->source); + return janet_wrap_nil(); +} + +static Janet janet_disasm_name(JanetFuncDef *def) { + if (def->name != NULL) return janet_wrap_string(def->name); + return janet_wrap_nil(); +} + +static Janet janet_disasm_vararg(JanetFuncDef *def) { + return janet_wrap_boolean(def->flags & JANET_FUNCDEF_FLAG_VARARG); +} + +static Janet janet_disasm_constants(JanetFuncDef *def) { + JanetArray *constants = janet_array(def->constants_length); + for (int32_t i = 0; i < def->constants_length; i++) { + constants->data[i] = def->constants[i]; } + constants->count = def->constants_length; + return janet_wrap_array(constants); +} - /* Add environments */ - if (NULL != def->environments) { - JanetArray *envs = janet_array(def->environments_length); - for (i = 0; i < def->environments_length; i++) { - envs->data[i] = janet_wrap_integer(def->environments[i]); - } - envs->count = def->environments_length; - janet_table_put(ret, janet_ckeywordv("environments"), janet_wrap_array(envs)); +static Janet janet_disasm_sourcemap(JanetFuncDef *def) { + if (NULL == def->sourcemap) return janet_wrap_nil(); + JanetArray *sourcemap = janet_array(def->bytecode_length); + for (int32_t i = 0; i < def->bytecode_length; i++) { + Janet *t = janet_tuple_begin(2); + JanetSourceMapping mapping = def->sourcemap[i]; + t[0] = janet_wrap_integer(mapping.line); + t[1] = janet_wrap_integer(mapping.column); + sourcemap->data[i] = janet_wrap_tuple(janet_tuple_end(t)); } + sourcemap->count = def->bytecode_length; + return janet_wrap_array(sourcemap); +} - /* Add closures */ - /* Funcdefs cannot be recursive */ - if (NULL != def->defs) { - JanetArray *defs = janet_array(def->defs_length); - for (i = 0; i < def->defs_length; i++) { - defs->data[i] = janet_disasm(def->defs[i]); - } - defs->count = def->defs_length; - janet_table_put(ret, janet_ckeywordv("defs"), janet_wrap_array(defs)); +static Janet janet_disasm_environments(JanetFuncDef *def) { + JanetArray *envs = janet_array(def->environments_length); + for (int32_t i = 0; i < def->environments_length; i++) { + envs->data[i] = janet_wrap_integer(def->environments[i]); } + envs->count = def->environments_length; + return janet_wrap_array(envs); +} - /* Add slotcount */ - janet_table_put(ret, janet_ckeywordv("slotcount"), janet_wrap_integer(def->slotcount)); +static Janet janet_disasm_defs(JanetFuncDef *def) { + JanetArray *defs = janet_array(def->defs_length); + for (int32_t i = 0; i < def->defs_length; i++) { + defs->data[i] = janet_disasm(def->defs[i]); + } + defs->count = def->defs_length; + return janet_wrap_array(defs); +} +Janet janet_disasm(JanetFuncDef *def) { + JanetTable *ret = janet_table(10); + janet_table_put(ret, janet_ckeywordv("arity"), janet_disasm_arity(def)); + janet_table_put(ret, janet_ckeywordv("min-arity"), janet_disasm_min_arity(def)); + janet_table_put(ret, janet_ckeywordv("max-arity"), janet_disasm_max_arity(def)); + janet_table_put(ret, janet_ckeywordv("bytecode"), janet_disasm_bytecode(def)); + janet_table_put(ret, janet_ckeywordv("source"), janet_disasm_source(def)); + janet_table_put(ret, janet_ckeywordv("vararg"), janet_disasm_vararg(def)); + janet_table_put(ret, janet_ckeywordv("name"), janet_disasm_name(def)); + janet_table_put(ret, janet_ckeywordv("slotcount"), janet_disasm_slotcount(def)); + janet_table_put(ret, janet_ckeywordv("constants"), janet_disasm_constants(def)); + janet_table_put(ret, janet_ckeywordv("sourcemap"), janet_disasm_sourcemap(def)); + janet_table_put(ret, janet_ckeywordv("environments"), janet_disasm_environments(def)); + janet_table_put(ret, janet_ckeywordv("defs"), janet_disasm_defs(def)); return janet_wrap_struct(janet_table_to_struct(ret)); } /* C Function for assembly */ static Janet cfun_asm(int32_t argc, Janet *argv) { - janet_arity(argc, 1, 1); + janet_fixarity(argc, 1); JanetAssembleResult res; res = janet_asm(argv[0], 0); if (res.status != JANET_ASSEMBLE_OK) { @@ -928,9 +954,26 @@ static Janet cfun_asm(int32_t argc, Janet *argv) { } static Janet cfun_disasm(int32_t argc, Janet *argv) { - janet_arity(argc, 1, 1); + janet_arity(argc, 1, 2); JanetFunction *f = janet_getfunction(argv, 0); - return janet_disasm(f->def); + if (argc == 2) { + JanetKeyword kw = janet_getkeyword(argv, 1); + if (!janet_cstrcmp(kw, "arity")) return janet_disasm_arity(f->def); + if (!janet_cstrcmp(kw, "min-arity")) return janet_disasm_min_arity(f->def); + if (!janet_cstrcmp(kw, "max-arity")) return janet_disasm_max_arity(f->def); + if (!janet_cstrcmp(kw, "bytecode")) return janet_disasm_bytecode(f->def); + if (!janet_cstrcmp(kw, "source")) return janet_disasm_source(f->def); + if (!janet_cstrcmp(kw, "name")) return janet_disasm_name(f->def); + if (!janet_cstrcmp(kw, "vararg")) return janet_disasm_vararg(f->def); + if (!janet_cstrcmp(kw, "slotcount")) return janet_disasm_slotcount(f->def); + if (!janet_cstrcmp(kw, "constants")) return janet_disasm_constants(f->def); + if (!janet_cstrcmp(kw, "sourcemap")) return janet_disasm_sourcemap(f->def); + if (!janet_cstrcmp(kw, "environments")) return janet_disasm_environments(f->def); + if (!janet_cstrcmp(kw, "defs")) return janet_disasm_defs(f->def); + janet_panicf("unknown disasm key %v", argv[1]); + } else { + return janet_disasm(f->def); + } } static const JanetReg asm_cfuns[] = { @@ -938,15 +981,29 @@ static const JanetReg asm_cfuns[] = { "asm", cfun_asm, JDOC("(asm assembly)\n\n" "Returns a new function that is the compiled result of the assembly.\n" - "The syntax for the assembly can be found on the Janet website. Will throw an\n" + "The syntax for the assembly can be found on the Janet website, and should correspond\n" + "to the return value of disasm. Will throw an\n" "error on invalid assembly.") }, { "disasm", cfun_disasm, - JDOC("(disasm func)\n\n" + JDOC("(disasm func &opt field)\n\n" "Returns assembly that could be used be compile the given function.\n" "func must be a function, not a c function. Will throw on error on a badly\n" - "typed argument.") + "typed argument. If given a field name, will only return that part of the function assembly.\n" + "Possible fields are:\n\n" + "\t:arity - number of required and optional arguments.\n" + "\t:min-arity - minimum number of arguments function can be called with.\n" + "\t:max-arity - maximum number of arguments function can be called with.\n" + "\t:vararg - true if function can take a variable number of arguments.\n" + "\t:bytecode - array of parsed bytecode instructions. Each instruction is a tuple.\n" + "\t:source - name of source file that this function was compiled from.\n" + "\t:name - name of function.\n" + "\t:slotcount - how many virtual registers, or slots, this function uses. Corresponds to stack space used by function.\n" + "\t:constants - an array of constants referenced by this function.\n" + "\t:sourcemap - a mapping of each bytecode instruction to a line and column in the source file.\n" + "\t:environments - an internal mapping of which enclosing functions are referenced for bindings.\n" + "\t:defs - other function definitions that this function may instantiate.\n") }, {NULL, NULL, NULL} }; diff --git a/src/core/bytecode.c b/src/core/bytecode.c index 4d2a74c3..bd07b5ef 100644 --- a/src/core/bytecode.c +++ b/src/core/bytecode.c @@ -103,6 +103,7 @@ enum JanetInstructionType janet_instructions[JOP_INSTRUCTION_COUNT] = { JINT_SSS, /* JOP_NEXT */ JINT_SSS, /* JOP_NOT_EQUALS, */ JINT_SSI, /* JOP_NOT_EQUALS_IMMEDIATE, */ + JINT_SSS /* JOP_CANCEL, */ }; /* Verify some bytecode */ diff --git a/src/core/cfuns.c b/src/core/cfuns.c index 41fc18a7..3e5f9ad6 100644 --- a/src/core/cfuns.c +++ b/src/core/cfuns.c @@ -231,6 +231,9 @@ static JanetSlot do_yield(JanetFopts opts, JanetSlot *args) { static JanetSlot do_resume(JanetFopts opts, JanetSlot *args) { return opfunction(opts, args, JOP_RESUME, janet_wrap_nil()); } +static JanetSlot do_cancel(JanetFopts opts, JanetSlot *args) { + return opfunction(opts, args, JOP_CANCEL, janet_wrap_nil()); +} static JanetSlot do_apply(JanetFopts opts, JanetSlot *args) { /* Push phase */ JanetCompiler *c = opts.compiler; @@ -383,6 +386,7 @@ static const JanetFunOptimizer optimizers[] = { {fixarity2, do_modulo}, {fixarity2, do_remainder}, {fixarity2, do_cmp}, + {fixarity2, do_cancel}, }; const JanetFunOptimizer *janetc_funopt(uint32_t flags) { diff --git a/src/core/compile.h b/src/core/compile.h index 5782bbf1..20f20224 100644 --- a/src/core/compile.h +++ b/src/core/compile.h @@ -61,6 +61,7 @@ #define JANET_FUN_MODULO 29 #define JANET_FUN_REMAINDER 30 #define JANET_FUN_CMP 31 +#define JANET_FUN_CANCEL 32 /* Compiler typedefs */ typedef struct JanetCompiler JanetCompiler; diff --git a/src/core/corelib.c b/src/core/corelib.c index 157ff028..1bbace73 100644 --- a/src/core/corelib.c +++ b/src/core/corelib.c @@ -946,6 +946,10 @@ static const uint32_t resume_asm[] = { JOP_RESUME | (1 << 24), JOP_RETURN }; +static const uint32_t cancel_asm[] = { + JOP_CANCEL | (1 << 24), + JOP_RETURN +}; static const uint32_t in_asm[] = { JOP_IN | (1 << 24), JOP_LOAD_NIL | (3 << 8), @@ -1086,6 +1090,11 @@ JanetTable *janet_core_env(JanetTable *replacements) { "Yield a value to a parent fiber. When a fiber yields, its execution is paused until " "another thread resumes it. The fiber will then resume, and the last yield call will " "return the value that was passed to resume.")); + janet_quick_asm(env, JANET_FUN_CANCEL, + "cancel", 2, 2, 2, 2, cancel_asm, sizeof(cancel_asm), + JDOC("(cancel fiber err)\n\n" + "Resume a fiber but have it immediately raise an error. This lets a programmer unwind a pending fiber. " + "Returns the same result as resume.")); janet_quick_asm(env, JANET_FUN_RESUME, "resume", 2, 1, 2, 2, resume_asm, sizeof(resume_asm), JDOC("(resume fiber &opt x)\n\n" diff --git a/src/core/ev.c b/src/core/ev.c index 606c9b9c..61e9237c 100644 --- a/src/core/ev.c +++ b/src/core/ev.c @@ -804,6 +804,14 @@ static Janet cfun_ev_sleep(int32_t argc, Janet *argv) { janet_await(); } +static Janet cfun_ev_cancel(int32_t argc, Janet *argv) { + janet_fixarity(argc, 2); + JanetFiber *fiber = janet_getfiber(argv, 0); + Janet err = argv[1]; + janet_cancel(fiber, err); + return argv[0]; +} + static const JanetReg ev_cfuns[] = { { "ev/call", cfun_ev_call, @@ -867,6 +875,11 @@ static const JanetReg ev_cfuns[] = { "is not empty. Will prefer channels in a random order (random choice). " "Returns a non-empty channel.") }, + { + "ev/cancel", cfun_ev_cancel, + JDOC("(ev/cancel fiber err)\n\n" + "Cancel a suspended fiber in the event loop. Differs from cancel in that it returns the canceled fiber immediately") + }, {NULL, NULL, NULL} }; diff --git a/src/core/fiber.c b/src/core/fiber.c index e8d8b985..8ac94ff6 100644 --- a/src/core/fiber.c +++ b/src/core/fiber.c @@ -91,6 +91,22 @@ JanetFiber *janet_fiber(JanetFunction *callee, int32_t capacity, int32_t argc, c return janet_fiber_reset(fiber_alloc(capacity), callee, argc, argv); } +#ifdef JANET_DEBUG +/* Test for memory issues by reallocating fiber every time we push a stack frame */ +static void janet_fiber_refresh_memory(JanetFiber *fiber) { + int32_t n = fiber->capacity; + if (n) { + Janet *newData = malloc(sizeof(Janet) * n); + if (NULL == newData) { + JANET_OUT_OF_MEMORY; + } + memcpy(newData, fiber->data, fiber->capacity * sizeof(Janet)); + free(fiber->data); + fiber->data = newData; + } +} +#endif + /* Ensure that the fiber has enough extra capacity */ void janet_fiber_setcapacity(JanetFiber *fiber, int32_t n) { Janet *newData = realloc(fiber->data, sizeof(Janet) * n); @@ -179,6 +195,10 @@ int janet_fiber_funcframe(JanetFiber *fiber, JanetFunction *func) { if (fiber->capacity < nextstacktop) { janet_fiber_setcapacity(fiber, 2 * nextstacktop); +#ifdef JANET_DEBUG + } else { + janet_fiber_refresh_memory(fiber); +#endif } /* Nil unset stack arguments (Needed for gc correctness) */ @@ -311,6 +331,10 @@ int janet_fiber_funcframe_tail(JanetFiber *fiber, JanetFunction *func) { if (fiber->capacity < nextstacktop) { janet_fiber_setcapacity(fiber, 2 * nextstacktop); +#ifdef JANET_DEBUG + } else { + janet_fiber_refresh_memory(fiber); +#endif } Janet *stack = fiber->data + fiber->frame; @@ -373,6 +397,10 @@ void janet_fiber_cframe(JanetFiber *fiber, JanetCFunction cfun) { if (fiber->capacity < nextstacktop) { janet_fiber_setcapacity(fiber, 2 * nextstacktop); +#ifdef JANET_DEBUG + } else { + janet_fiber_refresh_memory(fiber); +#endif } /* Set the next frame */ diff --git a/src/core/net.c b/src/core/net.c index beb10341..26fa663d 100644 --- a/src/core/net.c +++ b/src/core/net.c @@ -224,8 +224,8 @@ JanetAsyncStatus net_machine_read(JanetListenerState *s, JanetAsyncEvent event) } else { sig = JANET_SIGNAL_ERROR; resume_val = (nread == -1) - ? janet_cstringv(strerror(JLASTERR)) - : janet_cstringv("could not read"); + ? janet_cstringv(strerror(JLASTERR)) + : janet_cstringv("could not read"); } } janet_schedule_signal(s->fiber, resume_val, sig); diff --git a/src/core/vm.c b/src/core/vm.c index d66e3b81..58b902ec 100644 --- a/src/core/vm.c +++ b/src/core/vm.c @@ -95,6 +95,10 @@ JANET_THREAD_LOCAL jmp_buf *janet_vm_jmp_buf = NULL; vm_commit(); \ return (sig); \ } while (0) +#define vm_return_no_restore(sig, val) do { \ + janet_vm_return_reg[0] = (val); \ + return (sig); \ +} while (0) /* Next instruction variations */ #define maybe_collect() do {\ @@ -376,7 +380,7 @@ static JanetSignal run_vm(JanetFiber *fiber, Janet in) { &&label_JOP_NEXT, &&label_JOP_NOT_EQUALS, &&label_JOP_NOT_EQUALS_IMMEDIATE, - &&label_unknown_op, + &&label_JOP_CANCEL, &&label_unknown_op, &&label_unknown_op, &&label_unknown_op, @@ -623,7 +627,7 @@ static JanetSignal run_vm(JanetFiber *fiber, Janet in) { Janet retval = stack[D]; int entrance_frame = janet_stack_frame(stack)->flags & JANET_STACKFRAME_ENTRANCE; janet_fiber_popframe(fiber); - if (entrance_frame) vm_return(JANET_SIGNAL_OK, retval); + if (entrance_frame) vm_return_no_restore(JANET_SIGNAL_OK, retval); vm_restore(); stack[A] = retval; vm_checkgc_pcnext(); @@ -633,7 +637,7 @@ static JanetSignal run_vm(JanetFiber *fiber, Janet in) { Janet retval = janet_wrap_nil(); int entrance_frame = janet_stack_frame(stack)->flags & JANET_STACKFRAME_ENTRANCE; janet_fiber_popframe(fiber); - if (entrance_frame) vm_return(JANET_SIGNAL_OK, retval); + if (entrance_frame) vm_return_no_restore(JANET_SIGNAL_OK, retval); vm_restore(); stack[A] = retval; vm_checkgc_pcnext(); @@ -1011,8 +1015,9 @@ static JanetSignal run_vm(JanetFiber *fiber, Janet in) { retreg = call_nonfn(fiber, callee); } janet_fiber_popframe(fiber); - if (entrance_frame) - vm_return(JANET_SIGNAL_OK, retreg); + if (entrance_frame) { + vm_return_no_restore(JANET_SIGNAL_OK, retreg); + } vm_restore(); stack[A] = retreg; vm_checkgc_pcnext(); @@ -1059,6 +1064,25 @@ static JanetSignal run_vm(JanetFiber *fiber, Janet in) { vm_return((int) sub_status, stack[B]); } + VM_OP(JOP_CANCEL) { + Janet retreg; + vm_assert_type(stack[B], JANET_FIBER); + JanetFiber *child = janet_unwrap_fiber(stack[B]); + if (janet_check_can_resume(child, &retreg)) { + vm_commit(); + janet_panicv(retreg); + } + fiber->child = child; + JanetSignal sig = janet_continue_signal(child, stack[C], &retreg, JANET_SIGNAL_ERROR); + if (sig != JANET_SIGNAL_OK && !(child->flags & (1 << sig))) { + vm_return(sig, retreg); + } + fiber->child = NULL; + stack = fiber->data + fiber->frame; + stack[A] = retreg; + vm_checkgc_pcnext(); + } + VM_OP(JOP_PUT) vm_commit(); fiber->flags |= JANET_FIBER_RESUME_NO_USEVAL; diff --git a/src/include/janet.h b/src/include/janet.h index 7f592a60..65a4ca69 100644 --- a/src/include/janet.h +++ b/src/include/janet.h @@ -1195,6 +1195,7 @@ enum JanetOpCode { JOP_NEXT, JOP_NOT_EQUALS, JOP_NOT_EQUALS_IMMEDIATE, + JOP_CANCEL, JOP_INSTRUCTION_COUNT }; diff --git a/src/mainclient/shell.c b/src/mainclient/shell.c index 5ff7591f..2d1d92d9 100644 --- a/src/mainclient/shell.c +++ b/src/mainclient/shell.c @@ -180,7 +180,7 @@ static int rawmode(void) { t.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG); t.c_cc[VMIN] = 1; t.c_cc[VTIME] = 0; - if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &t) < 0) goto fatal; + if (tcsetattr(STDIN_FILENO, TCSADRAIN, &t) < 0) goto fatal; gbl_israwmode = 1; return 0; fatal: @@ -193,7 +193,7 @@ fatal: /* Disable raw mode */ static void norawmode(void) { - if (gbl_israwmode && tcsetattr(STDIN_FILENO, TCSAFLUSH, &gbl_termios_start) != -1) + if (gbl_israwmode && tcsetattr(STDIN_FILENO, TCSADRAIN, &gbl_termios_start) != -1) gbl_israwmode = 0; #ifndef JANET_SINGLE_THREADED pthread_mutex_unlock(&gbl_lock); diff --git a/test/suite0010.janet b/test/suite0010.janet index 0b51aa31..1205d192 100644 --- a/test/suite0010.janet +++ b/test/suite0010.janet @@ -44,4 +44,17 @@ (assert (= :brackets (tuple/type (1 (macex1 '~[1 2 3 4])))) "macex1 qq bracket tuple") (assert (deep= (macex1 '~@[1 2 3 4 ,blah]) '~@[1 2 3 4 ,blah]) "macex1 qq array") +# Cancel test +(def f (fiber/new (fn [&] (yield 1) (yield 2) (yield 3) 4) :yti)) +(assert (= 1 (resume f)) "cancel resume 1") +(assert (= 2 (resume f)) "cancel resume 2") +(assert (= :hi (cancel f :hi)) "cancel resume 3") +(assert (= :error (fiber/status f)) "cancel resume 4") + +# Curenv +(assert (= (curenv) (curenv 0)) "curenv 1") +(assert (= (table/getproto (curenv)) (curenv 1)) "curenv 2") +(assert (= nil (curenv 1000000)) "curenv 3") +(assert (= root-env (curenv 1)) "curenv 4") + (end-suite)