1
0
mirror of https://github.com/janet-lang/janet synced 2024-11-28 11:09:54 +00:00

Allow dynamically setting output for printers

Some functions like print and debug/stacktrace print
to a file, usually stdout. This file can now be optionally set
via a dynamic variable.
This commit is contained in:
Calvin Rose 2019-04-16 21:44:19 -04:00
parent 513d551df6
commit 7918add47d
6 changed files with 32 additions and 20 deletions

View File

@ -1699,7 +1699,7 @@
:export ep} (table ;args)) :export ep} (table ;args))
(def newenv (require path ;args)) (def newenv (require path ;args))
(def prefix (or (and as (string as "/")) prefix (string path "/"))) (def prefix (or (and as (string as "/")) prefix (string path "/")))
(loop [[k v] :pairs newenv :when (not (v :private))] (loop [[k v] :pairs newenv :when (symbol? k) :when (not (v :private))]
(def newv (table/setproto @{:private (not ep)} v)) (def newv (table/setproto @{:private (not ep)} v))
(put env (symbol prefix k) newv))) (put env (symbol prefix k) newv)))

View File

@ -206,6 +206,7 @@ JanetRange janet_getslice(int32_t argc, const Janet *argv) {
} }
Janet janet_dyn(const char *name) { Janet janet_dyn(const char *name) {
if (!janet_vm_fiber) return janet_wrap_nil();
if (janet_vm_fiber->env) { if (janet_vm_fiber->env) {
return janet_table_get(janet_vm_fiber->env, janet_ckeywordv(name)); return janet_table_get(janet_vm_fiber->env, janet_ckeywordv(name));
} else { } else {
@ -214,6 +215,7 @@ Janet janet_dyn(const char *name) {
} }
void janet_setdyn(const char *name, Janet value) { void janet_setdyn(const char *name, Janet value) {
if (!janet_vm_fiber) return;
if (!janet_vm_fiber->env) { if (!janet_vm_fiber->env) {
janet_vm_fiber->env = janet_table(1); janet_vm_fiber->env = janet_table(1);
} }

View File

@ -95,6 +95,7 @@ void janet_debug_find(
* consitency with the top level code it is defined once. */ * consitency with the top level code it is defined once. */
void janet_stacktrace(JanetFiber *fiber, Janet err) { void janet_stacktrace(JanetFiber *fiber, Janet err) {
int32_t fi; int32_t fi;
FILE *out = janet_dynfile("err", stderr);
const char *errstr = (const char *)janet_to_string(err); const char *errstr = (const char *)janet_to_string(err);
JanetFiber **fibers = NULL; JanetFiber **fibers = NULL;
int wrote_error = 0; int wrote_error = 0;
@ -116,43 +117,43 @@ void janet_stacktrace(JanetFiber *fiber, Janet err) {
if (!wrote_error) { if (!wrote_error) {
JanetFiberStatus status = janet_fiber_status(fiber); JanetFiberStatus status = janet_fiber_status(fiber);
const char *prefix = status == JANET_STATUS_ERROR ? "" : "status "; const char *prefix = status == JANET_STATUS_ERROR ? "" : "status ";
fprintf(stderr, "%s%s: %s\n", fprintf(out, "%s%s: %s\n",
prefix, prefix,
janet_status_names[status], janet_status_names[status],
errstr); errstr);
wrote_error = 1; wrote_error = 1;
} }
fprintf(stderr, " in"); fprintf(out, " in");
if (frame->func) { if (frame->func) {
def = frame->func->def; def = frame->func->def;
fprintf(stderr, " %s", def->name ? (const char *)def->name : "<anonymous>"); fprintf(out, " %s", def->name ? (const char *)def->name : "<anonymous>");
if (def->source) { if (def->source) {
fprintf(stderr, " [%s]", (const char *)def->source); fprintf(out, " [%s]", (const char *)def->source);
} }
} else { } else {
JanetCFunction cfun = (JanetCFunction)(frame->pc); JanetCFunction cfun = (JanetCFunction)(frame->pc);
if (cfun) { if (cfun) {
Janet name = janet_table_get(janet_vm_registry, janet_wrap_cfunction(cfun)); Janet name = janet_table_get(janet_vm_registry, janet_wrap_cfunction(cfun));
if (!janet_checktype(name, JANET_NIL)) if (!janet_checktype(name, JANET_NIL))
fprintf(stderr, " %s", (const char *)janet_to_string(name)); fprintf(out, " %s", (const char *)janet_to_string(name));
else else
fprintf(stderr, " <cfunction>"); fprintf(out, " <cfunction>");
} }
} }
if (frame->flags & JANET_STACKFRAME_TAILCALL) if (frame->flags & JANET_STACKFRAME_TAILCALL)
fprintf(stderr, " (tailcall)"); fprintf(out, " (tailcall)");
if (frame->func && frame->pc) { if (frame->func && frame->pc) {
int32_t off = (int32_t)(frame->pc - def->bytecode); int32_t off = (int32_t)(frame->pc - def->bytecode);
if (def->sourcemap) { if (def->sourcemap) {
JanetSourceMapping mapping = def->sourcemap[off]; JanetSourceMapping mapping = def->sourcemap[off];
fprintf(stderr, " at (%d:%d)", mapping.start, mapping.end); fprintf(out, " at (%d:%d)", mapping.start, mapping.end);
} else { } else {
fprintf(stderr, " pc=%d", off); fprintf(out, " pc=%d", off);
} }
} }
fprintf(stderr, "\n"); fprintf(out, "\n");
} }
} }

View File

@ -333,17 +333,17 @@ static Janet io_file_get(void *p, Janet key) {
return janet_getmethod(janet_unwrap_keyword(key), io_file_methods); return janet_getmethod(janet_unwrap_keyword(key), io_file_methods);
} }
static IOFile *io_isfile(Janet x) { FILE *janet_dynfile(const char *name, FILE *def) {
if (!janet_checktype(x, JANET_ABSTRACT)) return NULL; Janet x = janet_dyn(name);
if (!janet_checktype(x, JANET_ABSTRACT)) return def;
void *abstract = janet_unwrap_abstract(x); void *abstract = janet_unwrap_abstract(x);
if (janet_abstract_type(abstract) != &cfun_io_filetype) return NULL; if (janet_abstract_type(abstract) != &cfun_io_filetype) return def;
return (IOFile *)abstract; IOFile *iofile = abstract;
return iofile->file;
} }
static Janet cfun_io_print(int32_t argc, Janet *argv) { static Janet cfun_io_print(int32_t argc, Janet *argv) {
/* Get output stream */ FILE *f = janet_dynfile("out", stdout);
IOFile *outf = io_isfile(janet_dyn("out"));
FILE *f = outf ? outf->file : stdout;
for (int32_t i = 0; i < argc; ++i) { for (int32_t i = 0; i < argc; ++i) {
int32_t j, len; int32_t j, len;
const uint8_t *vstr = janet_to_string(argv[i]); const uint8_t *vstr = janet_to_string(argv[i]);

View File

@ -1279,11 +1279,12 @@ JANET_API JanetRange janet_getslice(int32_t argc, const Janet *argv);
JANET_API int32_t janet_gethalfrange(const Janet *argv, int32_t n, int32_t length, const char *which); JANET_API int32_t janet_gethalfrange(const Janet *argv, int32_t n, int32_t length, const char *which);
JANET_API int32_t janet_getargindex(const Janet *argv, int32_t n, int32_t length, const char *which); JANET_API int32_t janet_getargindex(const Janet *argv, int32_t n, int32_t length, const char *which);
JANET_API FILE *janet_getfile(const Janet *argv, int32_t n, int *flags);
JANET_API Janet janet_dyn(const char *name); JANET_API Janet janet_dyn(const char *name);
JANET_API void janet_setdyn(const char *name, Janet value); JANET_API void janet_setdyn(const char *name, Janet value);
JANET_API FILE *janet_getfile(const Janet *argv, int32_t n, int *flags);
JANET_API FILE *janet_dynfile(const char *name, FILE *def);
/* Marshal API */ /* Marshal API */
#define janet_marshal_size(ctx, x) janet_marshal_int64((ctx), (int64_t) (x)) #define janet_marshal_size(ctx, x) janet_marshal_int64((ctx), (int64_t) (x))
JANET_API void janet_marshal_int(JanetMarshalContext *ctx, int32_t value); JANET_API void janet_marshal_int(JanetMarshalContext *ctx, int32_t value);

View File

@ -88,4 +88,12 @@
)) ))
"int64 typed arrays") "int64 typed arrays")
# Dynamic bindings
(setdyn :a 10)
(assert (= 40 (with-dyns [:a 25 :b 15] (+ (dyn :a) (dyn :b)))) "dyn usage 1")
(assert (= 10 (dyn :a)) "dyn usage 2")
(assert (= nil (dyn :b)) "dyn usage 3")
(setdyn :a 100)
(assert (= 100 (dyn :a)) "dyn usage 4")
(end-suite) (end-suite)