diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ea16f10..57d013af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,11 +4,13 @@ All notable changes to this project will be documented in this file. ## 0.5.0 - ?? - Remove `*env*`, and `*doc-width*`. - Add `fiber/getenv`, `fiber/setenv`, and `dyn`, and `setdyn`. +- Add support for dynamic bindings (via the `dyn` and `setdyn` functions). - Change signatures of some functions like `eval` which no longer takes an optional environment. - Add printf function - Make `pp` configurable with dynamic binding `:pretty-format`. - Remove the `meta` function. +- Add `with-dyns` for blocks with dynamic bindings assigned. ## 0.4.1 - 2019-04-14 - Squash some bugs diff --git a/src/boot/boot.janet b/src/boot/boot.janet index 796b0219..130087d0 100644 --- a/src/boot/boot.janet +++ b/src/boot/boot.janet @@ -852,6 +852,19 @@ (set prev ~(if-let [,sym ,prev] ,next-prev))) prev) +(defmacro with-dyns + "Run a block of code in a new fiber that has some + dynamic bindings set. The fiber will not mask errors + or signals, but the dynamic bindings will be properly + unset, as dynamic bindings are fiber local." + [bindings & body] + (with-syms [currenv env fib] + ~(let [,currenv (,fiber/getenv (,fiber/current)) + ,env (,table/setproto (,table ,;bindings) ,currenv) + ,fib (,fiber/new (fn [] ,;body) :)] + (,fiber/setenv ,fib ,env) + (,resume ,fib)))) + (defn partial "Partial function application." [f & more] diff --git a/src/core/capi.c b/src/core/capi.c index 845303f9..13482785 100644 --- a/src/core/capi.c +++ b/src/core/capi.c @@ -204,3 +204,18 @@ JanetRange janet_getslice(int32_t argc, const Janet *argv) { } return range; } + +Janet janet_dyn(const char *name) { + if (janet_vm_fiber->env) { + return janet_table_get(janet_vm_fiber->env, janet_ckeywordv(name)); + } else { + return janet_wrap_nil(); + } +} + +void janet_setdyn(const char *name, Janet value) { + if (!janet_vm_fiber->env) { + janet_vm_fiber->env = janet_table(1); + } + janet_table_put(janet_vm_fiber->env, janet_ckeywordv(name), value); +} diff --git a/src/core/corelib.c b/src/core/corelib.c index 78fc5ae5..1860cd6b 100644 --- a/src/core/corelib.c +++ b/src/core/corelib.c @@ -111,19 +111,6 @@ static Janet janet_core_native(int32_t argc, Janet *argv) { return janet_wrap_table(env); } -static Janet janet_core_print(int32_t argc, Janet *argv) { - for (int32_t i = 0; i < argc; ++i) { - int32_t j, len; - const uint8_t *vstr = janet_to_string(argv[i]); - len = janet_string_length(vstr); - for (j = 0; j < len; ++j) { - putc(vstr[j], stdout); - } - } - putc('\n', stdout); - return janet_wrap_nil(); -} - static Janet janet_core_describe(int32_t argc, Janet *argv) { JanetBuffer *b = janet_buffer(0); for (int32_t i = 0; i < argc; ++i) @@ -296,13 +283,6 @@ static const JanetReg corelib_cfuns[] = { "Returns an environment table that contains functions and other values " "from the native module.") }, - { - "print", janet_core_print, - JDOC("(print & xs)\n\n" - "Print values to the console (standard out). Value are converted " - "to strings if they are not already. After printing all values, a " - "newline character is printed. Returns nil.") - }, { "describe", janet_core_describe, JDOC("(describe x)\n\n" diff --git a/src/core/io.c b/src/core/io.c index d582a372..bb95d79b 100644 --- a/src/core/io.c +++ b/src/core/io.c @@ -333,7 +333,37 @@ static Janet io_file_get(void *p, Janet key) { return janet_getmethod(janet_unwrap_keyword(key), io_file_methods); } +static IOFile *io_isfile(Janet x) { + if (!janet_checktype(x, JANET_ABSTRACT)) return NULL; + void *abstract = janet_unwrap_abstract(x); + if (janet_abstract_type(abstract) != &cfun_io_filetype) return NULL; + return (IOFile *)abstract; +} + +static Janet cfun_io_print(int32_t argc, Janet *argv) { + /* Get output stream */ + IOFile *outf = io_isfile(janet_dyn("out")); + FILE *f = outf ? outf->file : stdout; + for (int32_t i = 0; i < argc; ++i) { + int32_t j, len; + const uint8_t *vstr = janet_to_string(argv[i]); + len = janet_string_length(vstr); + for (j = 0; j < len; ++j) { + putc(vstr[j], f); + } + } + putc('\n', f); + return janet_wrap_nil(); +} + static const JanetReg io_cfuns[] = { + { + "print", cfun_io_print, + JDOC("(print & xs)\n\n" + "Print values to the console (standard out). Value are converted " + "to strings if they are not already. After printing all values, a " + "newline character is printed. Returns nil.") + }, { "file/open", cfun_io_fopen, JDOC("(file/open path [,mode])\n\n" diff --git a/src/include/janet.h b/src/include/janet.h index 169dca0c..c3d427cf 100644 --- a/src/include/janet.h +++ b/src/include/janet.h @@ -1281,6 +1281,9 @@ JANET_API int32_t janet_getargindex(const Janet *argv, int32_t n, int32_t length JANET_API FILE *janet_getfile(const Janet *argv, int32_t n, int *flags); +JANET_API Janet janet_dyn(const char *name); +JANET_API void janet_setdyn(const char *name, Janet value); + /* Marshal API */ #define janet_marshal_size(ctx, x) janet_marshal_int64((ctx), (int64_t) (x)) JANET_API void janet_marshal_int(JanetMarshalContext *ctx, int32_t value);