mirror of
https://github.com/janet-lang/janet
synced 2024-11-28 11:09:54 +00:00
Merge branch 'master' into ev
This commit is contained in:
commit
86e00e865e
@ -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)
|
||||||
|
Loading…
Reference in New Issue
Block a user