mirror of
				https://github.com/janet-lang/janet
				synced 2025-10-30 07:03:02 +00:00 
			
		
		
		
	Merge branch 'master' into ev
This commit is contained in:
		| @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. | |||||||
|  |  | ||||||
| ## Unreleased - ??? | ## Unreleased - ??? | ||||||
| - Silence warnings in some compilers. | - 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. | - 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 | - Add `janet_continue_signal` to C API. This indirectly enables C functions that yield to the event loop | ||||||
|   to raise errors or other signals. |   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. | - Expose `janet_cryptorand` in C API. | ||||||
| - Properly initialize PRF in default janet program | - Properly initialize PRF in default janet program | ||||||
| - Add `index-of` to core library. | - 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 Windows for ARM | ||||||
| - Fix defaults on NetBSD. | - Fix defaults on NetBSD. | ||||||
|  |  | ||||||
|   | |||||||
| @@ -2069,6 +2069,14 @@ | |||||||
|       (if ec "\e[0m" ""))) |       (if ec "\e[0m" ""))) | ||||||
|   (eflush)) |   (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 | (defn run-context | ||||||
|   "Run a context. This evaluates expressions in an environment, |   "Run a context. This evaluates expressions in an environment, | ||||||
|   and is encapsulates the parsing, compilation, and evaluation. |   and is encapsulates the parsing, compilation, and evaluation. | ||||||
|   | |||||||
| @@ -58,6 +58,7 @@ | |||||||
| /* #define JANET_NO_UMASK */ | /* #define JANET_NO_UMASK */ | ||||||
|  |  | ||||||
| /* Other settings */ | /* Other settings */ | ||||||
|  | /* #define JANET_DEBUG */ | ||||||
| /* #define JANET_PRF */ | /* #define JANET_PRF */ | ||||||
| /* #define JANET_NO_UTC_MKTIME */ | /* #define JANET_NO_UTC_MKTIME */ | ||||||
| /* #define JANET_OUT_OF_MEMORY do { printf("janet out of memory\n"); exit(1); } while (0) */ | /* #define JANET_OUT_OF_MEMORY do { printf("janet out of memory\n"); exit(1); } while (0) */ | ||||||
|   | |||||||
							
								
								
									
										191
									
								
								src/core/asm.c
									
									
									
									
									
								
							
							
						
						
									
										191
									
								
								src/core/asm.c
									
									
									
									
									
								
							| @@ -73,6 +73,7 @@ static const JanetInstructionDef janet_ops[] = { | |||||||
|     {"call", JOP_CALL}, |     {"call", JOP_CALL}, | ||||||
|     {"clo", JOP_CLOSURE}, |     {"clo", JOP_CLOSURE}, | ||||||
|     {"cmp", JOP_COMPARE}, |     {"cmp", JOP_COMPARE}, | ||||||
|  |     {"cncl", JOP_CANCEL}, | ||||||
|     {"div", JOP_DIVIDE}, |     {"div", JOP_DIVIDE}, | ||||||
|     {"divim", JOP_DIVIDE_IMMEDIATE}, |     {"divim", JOP_DIVIDE_IMMEDIATE}, | ||||||
|     {"eq", JOP_EQUALS}, |     {"eq", JOP_EQUALS}, | ||||||
| @@ -840,85 +841,110 @@ Janet janet_asm_decode_instruction(uint32_t instr) { | |||||||
|     return janet_wrap_nil(); |     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 *bcode = janet_array(def->bytecode_length); | ||||||
|     JanetArray *constants; |     for (int32_t i = 0; i < def->bytecode_length; i++) { | ||||||
|     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++) { |  | ||||||
|         bcode->data[i] = janet_asm_decode_instruction(def->bytecode[i]); |         bcode->data[i] = janet_asm_decode_instruction(def->bytecode[i]); | ||||||
|     } |     } | ||||||
|     bcode->count = def->bytecode_length; |     bcode->count = def->bytecode_length; | ||||||
|  |     return janet_wrap_array(bcode); | ||||||
|  | } | ||||||
|  |  | ||||||
|     /* Add source map */ | static Janet janet_disasm_source(JanetFuncDef *def) { | ||||||
|     if (NULL != def->sourcemap) { |     if (def->source != NULL) return janet_wrap_string(def->source); | ||||||
|         JanetArray *sourcemap = janet_array(def->bytecode_length); |     return janet_wrap_nil(); | ||||||
|         for (i = 0; i < def->bytecode_length; i++) { | } | ||||||
|             Janet *t = janet_tuple_begin(2); |  | ||||||
|             JanetSourceMapping mapping = def->sourcemap[i]; | static Janet janet_disasm_name(JanetFuncDef *def) { | ||||||
|             t[0] = janet_wrap_integer(mapping.line); |     if (def->name != NULL) return janet_wrap_string(def->name); | ||||||
|             t[1] = janet_wrap_integer(mapping.column); |     return janet_wrap_nil(); | ||||||
|             sourcemap->data[i] = janet_wrap_tuple(janet_tuple_end(t)); | } | ||||||
|         } |  | ||||||
|         sourcemap->count = def->bytecode_length; | static Janet janet_disasm_vararg(JanetFuncDef *def) { | ||||||
|         janet_table_put(ret, janet_ckeywordv("sourcemap"), janet_wrap_array(sourcemap)); |     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 */ | static Janet janet_disasm_sourcemap(JanetFuncDef *def) { | ||||||
|     if (NULL != def->environments) { |     if (NULL == def->sourcemap) return janet_wrap_nil(); | ||||||
|         JanetArray *envs = janet_array(def->environments_length); |     JanetArray *sourcemap = janet_array(def->bytecode_length); | ||||||
|         for (i = 0; i < def->environments_length; i++) { |     for (int32_t i = 0; i < def->bytecode_length; i++) { | ||||||
|             envs->data[i] = janet_wrap_integer(def->environments[i]); |         Janet *t = janet_tuple_begin(2); | ||||||
|         } |         JanetSourceMapping mapping = def->sourcemap[i]; | ||||||
|         envs->count = def->environments_length; |         t[0] = janet_wrap_integer(mapping.line); | ||||||
|         janet_table_put(ret, janet_ckeywordv("environments"), janet_wrap_array(envs)); |         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 */ | static Janet janet_disasm_environments(JanetFuncDef *def) { | ||||||
|     /* Funcdefs cannot be recursive */ |     JanetArray *envs = janet_array(def->environments_length); | ||||||
|     if (NULL != def->defs) { |     for (int32_t i = 0; i < def->environments_length; i++) { | ||||||
|         JanetArray *defs = janet_array(def->defs_length); |         envs->data[i] = janet_wrap_integer(def->environments[i]); | ||||||
|         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)); |  | ||||||
|     } |     } | ||||||
|  |     envs->count = def->environments_length; | ||||||
|  |     return janet_wrap_array(envs); | ||||||
|  | } | ||||||
|  |  | ||||||
|     /* Add slotcount */ | static Janet janet_disasm_defs(JanetFuncDef *def) { | ||||||
|     janet_table_put(ret, janet_ckeywordv("slotcount"), janet_wrap_integer(def->slotcount)); |     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)); |     return janet_wrap_struct(janet_table_to_struct(ret)); | ||||||
| } | } | ||||||
|  |  | ||||||
| /* C Function for assembly */ | /* C Function for assembly */ | ||||||
| static Janet cfun_asm(int32_t argc, Janet *argv) { | static Janet cfun_asm(int32_t argc, Janet *argv) { | ||||||
|     janet_arity(argc, 1, 1); |     janet_fixarity(argc, 1); | ||||||
|     JanetAssembleResult res; |     JanetAssembleResult res; | ||||||
|     res = janet_asm(argv[0], 0); |     res = janet_asm(argv[0], 0); | ||||||
|     if (res.status != JANET_ASSEMBLE_OK) { |     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) { | 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); |     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[] = { | static const JanetReg asm_cfuns[] = { | ||||||
| @@ -938,15 +981,29 @@ static const JanetReg asm_cfuns[] = { | |||||||
|         "asm", cfun_asm, |         "asm", cfun_asm, | ||||||
|         JDOC("(asm assembly)\n\n" |         JDOC("(asm assembly)\n\n" | ||||||
|              "Returns a new function that is the compiled result of the assembly.\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.") |              "error on invalid assembly.") | ||||||
|     }, |     }, | ||||||
|     { |     { | ||||||
|         "disasm", cfun_disasm, |         "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" |              "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" |              "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} |     {NULL, NULL, NULL} | ||||||
| }; | }; | ||||||
|   | |||||||
| @@ -103,6 +103,7 @@ enum JanetInstructionType janet_instructions[JOP_INSTRUCTION_COUNT] = { | |||||||
|     JINT_SSS, /* JOP_NEXT */ |     JINT_SSS, /* JOP_NEXT */ | ||||||
|     JINT_SSS, /* JOP_NOT_EQUALS, */ |     JINT_SSS, /* JOP_NOT_EQUALS, */ | ||||||
|     JINT_SSI, /* JOP_NOT_EQUALS_IMMEDIATE, */ |     JINT_SSI, /* JOP_NOT_EQUALS_IMMEDIATE, */ | ||||||
|  |     JINT_SSS /* JOP_CANCEL, */ | ||||||
| }; | }; | ||||||
|  |  | ||||||
| /* Verify some bytecode */ | /* Verify some bytecode */ | ||||||
|   | |||||||
| @@ -231,6 +231,9 @@ static JanetSlot do_yield(JanetFopts opts, JanetSlot *args) { | |||||||
| static JanetSlot do_resume(JanetFopts opts, JanetSlot *args) { | static JanetSlot do_resume(JanetFopts opts, JanetSlot *args) { | ||||||
|     return opfunction(opts, args, JOP_RESUME, janet_wrap_nil()); |     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) { | static JanetSlot do_apply(JanetFopts opts, JanetSlot *args) { | ||||||
|     /* Push phase */ |     /* Push phase */ | ||||||
|     JanetCompiler *c = opts.compiler; |     JanetCompiler *c = opts.compiler; | ||||||
| @@ -383,6 +386,7 @@ static const JanetFunOptimizer optimizers[] = { | |||||||
|     {fixarity2, do_modulo}, |     {fixarity2, do_modulo}, | ||||||
|     {fixarity2, do_remainder}, |     {fixarity2, do_remainder}, | ||||||
|     {fixarity2, do_cmp}, |     {fixarity2, do_cmp}, | ||||||
|  |     {fixarity2, do_cancel}, | ||||||
| }; | }; | ||||||
|  |  | ||||||
| const JanetFunOptimizer *janetc_funopt(uint32_t flags) { | const JanetFunOptimizer *janetc_funopt(uint32_t flags) { | ||||||
|   | |||||||
| @@ -61,6 +61,7 @@ | |||||||
| #define JANET_FUN_MODULO 29 | #define JANET_FUN_MODULO 29 | ||||||
| #define JANET_FUN_REMAINDER 30 | #define JANET_FUN_REMAINDER 30 | ||||||
| #define JANET_FUN_CMP 31 | #define JANET_FUN_CMP 31 | ||||||
|  | #define JANET_FUN_CANCEL 32 | ||||||
|  |  | ||||||
| /* Compiler typedefs */ | /* Compiler typedefs */ | ||||||
| typedef struct JanetCompiler JanetCompiler; | typedef struct JanetCompiler JanetCompiler; | ||||||
|   | |||||||
| @@ -946,6 +946,10 @@ static const uint32_t resume_asm[] = { | |||||||
|     JOP_RESUME | (1 << 24), |     JOP_RESUME | (1 << 24), | ||||||
|     JOP_RETURN |     JOP_RETURN | ||||||
| }; | }; | ||||||
|  | static const uint32_t cancel_asm[] = { | ||||||
|  |     JOP_CANCEL | (1 << 24), | ||||||
|  |     JOP_RETURN | ||||||
|  | }; | ||||||
| static const uint32_t in_asm[] = { | static const uint32_t in_asm[] = { | ||||||
|     JOP_IN | (1 << 24), |     JOP_IN | (1 << 24), | ||||||
|     JOP_LOAD_NIL | (3 << 8), |     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 " |                          "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 " |                          "another thread resumes it. The fiber will then resume, and the last yield call will " | ||||||
|                          "return the value that was passed to resume.")); |                          "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, |     janet_quick_asm(env, JANET_FUN_RESUME, | ||||||
|                     "resume", 2, 1, 2, 2, resume_asm, sizeof(resume_asm), |                     "resume", 2, 1, 2, 2, resume_asm, sizeof(resume_asm), | ||||||
|                     JDOC("(resume fiber &opt x)\n\n" |                     JDOC("(resume fiber &opt x)\n\n" | ||||||
|   | |||||||
| @@ -804,6 +804,14 @@ static Janet cfun_ev_sleep(int32_t argc, Janet *argv) { | |||||||
|     janet_await(); |     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[] = { | static const JanetReg ev_cfuns[] = { | ||||||
|     { |     { | ||||||
|         "ev/call", cfun_ev_call, |         "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). " |              "is not empty. Will prefer channels in a random order (random choice). " | ||||||
|              "Returns a non-empty channel.") |              "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} |     {NULL, NULL, NULL} | ||||||
| }; | }; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -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); |     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 */ | /* Ensure that the fiber has enough extra capacity */ | ||||||
| void janet_fiber_setcapacity(JanetFiber *fiber, int32_t n) { | void janet_fiber_setcapacity(JanetFiber *fiber, int32_t n) { | ||||||
|     Janet *newData = realloc(fiber->data, sizeof(Janet) * 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) { |     if (fiber->capacity < nextstacktop) { | ||||||
|         janet_fiber_setcapacity(fiber, 2 * 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) */ |     /* 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) { |     if (fiber->capacity < nextstacktop) { | ||||||
|         janet_fiber_setcapacity(fiber, 2 * nextstacktop); |         janet_fiber_setcapacity(fiber, 2 * nextstacktop); | ||||||
|  | #ifdef JANET_DEBUG | ||||||
|  |     } else { | ||||||
|  |         janet_fiber_refresh_memory(fiber); | ||||||
|  | #endif | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     Janet *stack = fiber->data + fiber->frame; |     Janet *stack = fiber->data + fiber->frame; | ||||||
| @@ -373,6 +397,10 @@ void janet_fiber_cframe(JanetFiber *fiber, JanetCFunction cfun) { | |||||||
|  |  | ||||||
|     if (fiber->capacity < nextstacktop) { |     if (fiber->capacity < nextstacktop) { | ||||||
|         janet_fiber_setcapacity(fiber, 2 * nextstacktop); |         janet_fiber_setcapacity(fiber, 2 * nextstacktop); | ||||||
|  | #ifdef JANET_DEBUG | ||||||
|  |     } else { | ||||||
|  |         janet_fiber_refresh_memory(fiber); | ||||||
|  | #endif | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /* Set the next frame */ |     /* Set the next frame */ | ||||||
|   | |||||||
| @@ -224,8 +224,8 @@ JanetAsyncStatus net_machine_read(JanetListenerState *s, JanetAsyncEvent event) | |||||||
|                     } else { |                     } else { | ||||||
|                         sig = JANET_SIGNAL_ERROR; |                         sig = JANET_SIGNAL_ERROR; | ||||||
|                         resume_val = (nread == -1) |                         resume_val = (nread == -1) | ||||||
|                             ? janet_cstringv(strerror(JLASTERR)) |                                      ? janet_cstringv(strerror(JLASTERR)) | ||||||
|                             : janet_cstringv("could not read"); |                                      : janet_cstringv("could not read"); | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|                 janet_schedule_signal(s->fiber, resume_val, sig); |                 janet_schedule_signal(s->fiber, resume_val, sig); | ||||||
|   | |||||||
| @@ -95,6 +95,10 @@ JANET_THREAD_LOCAL jmp_buf *janet_vm_jmp_buf = NULL; | |||||||
|     vm_commit(); \ |     vm_commit(); \ | ||||||
|     return (sig); \ |     return (sig); \ | ||||||
| } while (0) | } while (0) | ||||||
|  | #define vm_return_no_restore(sig, val) do { \ | ||||||
|  |     janet_vm_return_reg[0] = (val); \ | ||||||
|  |     return (sig); \ | ||||||
|  | } while (0) | ||||||
|  |  | ||||||
| /* Next instruction variations */ | /* Next instruction variations */ | ||||||
| #define maybe_collect() do {\ | #define maybe_collect() do {\ | ||||||
| @@ -376,7 +380,7 @@ static JanetSignal run_vm(JanetFiber *fiber, Janet in) { | |||||||
|         &&label_JOP_NEXT, |         &&label_JOP_NEXT, | ||||||
|         &&label_JOP_NOT_EQUALS, |         &&label_JOP_NOT_EQUALS, | ||||||
|         &&label_JOP_NOT_EQUALS_IMMEDIATE, |         &&label_JOP_NOT_EQUALS_IMMEDIATE, | ||||||
|         &&label_unknown_op, |         &&label_JOP_CANCEL, | ||||||
|         &&label_unknown_op, |         &&label_unknown_op, | ||||||
|         &&label_unknown_op, |         &&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]; |         Janet retval = stack[D]; | ||||||
|         int entrance_frame = janet_stack_frame(stack)->flags & JANET_STACKFRAME_ENTRANCE; |         int entrance_frame = janet_stack_frame(stack)->flags & JANET_STACKFRAME_ENTRANCE; | ||||||
|         janet_fiber_popframe(fiber); |         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(); |         vm_restore(); | ||||||
|         stack[A] = retval; |         stack[A] = retval; | ||||||
|         vm_checkgc_pcnext(); |         vm_checkgc_pcnext(); | ||||||
| @@ -633,7 +637,7 @@ static JanetSignal run_vm(JanetFiber *fiber, Janet in) { | |||||||
|         Janet retval = janet_wrap_nil(); |         Janet retval = janet_wrap_nil(); | ||||||
|         int entrance_frame = janet_stack_frame(stack)->flags & JANET_STACKFRAME_ENTRANCE; |         int entrance_frame = janet_stack_frame(stack)->flags & JANET_STACKFRAME_ENTRANCE; | ||||||
|         janet_fiber_popframe(fiber); |         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(); |         vm_restore(); | ||||||
|         stack[A] = retval; |         stack[A] = retval; | ||||||
|         vm_checkgc_pcnext(); |         vm_checkgc_pcnext(); | ||||||
| @@ -1011,8 +1015,9 @@ static JanetSignal run_vm(JanetFiber *fiber, Janet in) { | |||||||
|                 retreg = call_nonfn(fiber, callee); |                 retreg = call_nonfn(fiber, callee); | ||||||
|             } |             } | ||||||
|             janet_fiber_popframe(fiber); |             janet_fiber_popframe(fiber); | ||||||
|             if (entrance_frame) |             if (entrance_frame) { | ||||||
|                 vm_return(JANET_SIGNAL_OK, retreg); |                 vm_return_no_restore(JANET_SIGNAL_OK, retreg); | ||||||
|  |             } | ||||||
|             vm_restore(); |             vm_restore(); | ||||||
|             stack[A] = retreg; |             stack[A] = retreg; | ||||||
|             vm_checkgc_pcnext(); |             vm_checkgc_pcnext(); | ||||||
| @@ -1059,6 +1064,25 @@ static JanetSignal run_vm(JanetFiber *fiber, Janet in) { | |||||||
|         vm_return((int) sub_status, stack[B]); |         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_OP(JOP_PUT) | ||||||
|     vm_commit(); |     vm_commit(); | ||||||
|     fiber->flags |= JANET_FIBER_RESUME_NO_USEVAL; |     fiber->flags |= JANET_FIBER_RESUME_NO_USEVAL; | ||||||
|   | |||||||
| @@ -1195,6 +1195,7 @@ enum JanetOpCode { | |||||||
|     JOP_NEXT, |     JOP_NEXT, | ||||||
|     JOP_NOT_EQUALS, |     JOP_NOT_EQUALS, | ||||||
|     JOP_NOT_EQUALS_IMMEDIATE, |     JOP_NOT_EQUALS_IMMEDIATE, | ||||||
|  |     JOP_CANCEL, | ||||||
|     JOP_INSTRUCTION_COUNT |     JOP_INSTRUCTION_COUNT | ||||||
| }; | }; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -180,7 +180,7 @@ static int rawmode(void) { | |||||||
|     t.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG); |     t.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG); | ||||||
|     t.c_cc[VMIN] = 1; |     t.c_cc[VMIN] = 1; | ||||||
|     t.c_cc[VTIME] = 0; |     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; |     gbl_israwmode = 1; | ||||||
|     return 0; |     return 0; | ||||||
| fatal: | fatal: | ||||||
| @@ -193,7 +193,7 @@ fatal: | |||||||
|  |  | ||||||
| /* Disable raw mode */ | /* Disable raw mode */ | ||||||
| static void norawmode(void) { | 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; |         gbl_israwmode = 0; | ||||||
| #ifndef JANET_SINGLE_THREADED | #ifndef JANET_SINGLE_THREADED | ||||||
|     pthread_mutex_unlock(&gbl_lock); |     pthread_mutex_unlock(&gbl_lock); | ||||||
|   | |||||||
| @@ -44,4 +44,17 @@ | |||||||
| (assert (= :brackets (tuple/type (1 (macex1 '~[1 2 3 4])))) "macex1 qq bracket tuple") | (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") | (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) | (end-suite) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Calvin Rose
					Calvin Rose