1
0
mirror of https://github.com/janet-lang/janet synced 2024-06-27 23:53:16 +00:00

Add error reporting to repl (initial stack traces)

This commit is contained in:
Calvin Rose 2018-03-21 20:53:39 -04:00
parent e114ec0095
commit 0fd55282d8
11 changed files with 186 additions and 62 deletions

View File

@ -25,7 +25,7 @@
PREFIX?=/usr/local PREFIX?=/usr/local
BINDIR=$(PREFIX)/bin BINDIR=$(PREFIX)/bin
CFLAGS=-std=c99 -Wall -Wextra -Isrc/include -Os -s CFLAGS=-std=c99 -Wall -Wextra -Isrc/include -O3 -s
CLIBS=-lm -ldl CLIBS=-lm -ldl
PREFIX=/usr/local PREFIX=/usr/local
DST_TARGET=dst DST_TARGET=dst

View File

@ -2,7 +2,7 @@
# Copyright 2018 (C) Calvin Rose # Copyright 2018 (C) Calvin Rose
(var *env* (var *env*
"The current environment. Is dynamically bound." "The current environment."
_env) _env)
(def defn :macro (def defn :macro
@ -39,6 +39,7 @@
(apply1 tuple (array-concat (apply1 tuple (array-concat
['defn name :private] more))) ['defn name :private] more)))
# Basic predicates
(defn even? [x] (== 0 (% x 2))) (defn even? [x] (== 0 (% x 2)))
(defn odd? [x] (== 1 (% x 2))) (defn odd? [x] (== 1 (% x 2)))
(defn nil? [x] (= x nil)) (defn nil? [x] (= x nil))
@ -46,8 +47,6 @@
(defn pos? [x] (> x 0)) (defn pos? [x] (> x 0))
(defn neg? [x] (< x 0)) (defn neg? [x] (< x 0))
(defn one? [x] (== x 1)) (defn one? [x] (== x 1))
(defn inc [x] (+ x 1))
(defn dec [x] (- x 1))
(def atomic? (do (def atomic? (do
(def non-atomic-types { (def non-atomic-types {
:array true :array true
@ -57,7 +56,9 @@
}) })
(fn [x] (not (get non-atomic-types (type x)))))) (fn [x] (not (get non-atomic-types (type x))))))
# C style macros for imperative sugar # C style macros and functions for imperative sugar
(defn inc [x] (+ x 1))
(defn dec [x] (- x 1))
(defmacro ++ [x] (tuple ':= x (tuple + x 1))) (defmacro ++ [x] (tuple ':= x (tuple + x 1)))
(defmacro -- [x] (tuple ':= x (tuple - x 1))) (defmacro -- [x] (tuple ':= x (tuple - x 1)))
(defmacro += [x n] (tuple ':= x (tuple + x n))) (defmacro += [x n] (tuple ':= x (tuple + x n)))
@ -266,6 +267,10 @@ If no match is found, returns nil"
ret) ret)
}) })
(defn partial [f & more]
(if (zero? (length more)) f
(fn [& r] (apply1 f (array-concat [] more r)))))
(defmacro for [head & body] (defmacro for [head & body]
(def head (ast-unwrap1 head)) (def head (ast-unwrap1 head))
(def sym (get head 0)) (def sym (get head 0))
@ -281,6 +286,23 @@ If no match is found, returns nil"
(tuple-prepend body 'do) (tuple-prepend body 'do)
(tuple ':= sym (tuple '+ sym inc))))) (tuple ':= sym (tuple '+ sym inc)))))
(defn juxt*
[& funs]
(def len (length funs))
(fn [& args]
(def ret [])
(for [i 0 len]
(array-push ret (apply1 (get funs i) args)))
(apply1 tuple ret)))
(defmacro juxt
[& funs]
(def parts ['tuple])
(def $args (gensym))
(for [i 0 (length funs)]
(array-push parts (tuple apply1 (get funs i) $args)))
(tuple 'fn ['& $args] (apply1 tuple parts)))
(defmacro -> (defmacro ->
[x & forms] [x & forms]
(defn fop [last nextform] (defn fop [last nextform]
@ -514,11 +536,36 @@ onvalue."
(def res (resume f)) (def res (resume f))
(if good (if good
(if (= (fiber-status f) :error) (if (= (fiber-status f) :error)
(onerr "runtime" res) (onerr "runtime" res f)
(onvalue res)))) (onvalue res))))
(foreach (val-stream chunks onerr) doone) (foreach (val-stream chunks onerr) doone)
env))) env)))
(defn default-error-handler
[t x f]
(print)
(file-write stdout "error: ")
(pp x)
(when f
(def st (fiber-stack f))
(def len (length st))
(for [i 0 len]
(def {
:function func
:tail tail
:pc pc
:c c
:name name
} (get st i))
(file-write stdout " in")
(when c (file-write stdout " cfunction"))
(when name (file-write stdout (string " " name)))
(when func (file-write stdout (string " " func)))
(when pc (file-write stdout (string " (pc=" pc ")")))
(when tail (file-write stdout " (tailcall)"))
(file-write stdout "\n")))
(print))
(def require (do (def require (do
(def cache @{}) (def cache @{})
(def loading @{}) (def loading @{})
@ -534,8 +581,7 @@ onvalue."
(defn chunks [buf] (file-read f 1024 buf)) (defn chunks [buf] (file-read f 1024 buf))
(def oldenv *env*) (def oldenv *env*)
(:= *env* newenv) (:= *env* newenv)
(run-context newenv chunks identity (run-context newenv chunks identity default-error-handler)
(fn [t x] (print (string t " error: " x))))
(file-close f) (file-close f)
(:= *env* oldenv) (:= *env* oldenv)
(put loading path nil) (put loading path nil)
@ -551,7 +597,7 @@ onvalue."
(put env (symbol (if prefix prefix "") k) v))))) (put env (symbol (if prefix prefix "") k) v)))))
(defmacro import [path & args] (defmacro import [path & args]
(apply1 tuple (array-concat [import* '_env path] args))) (apply tuple import* '_env path args))
(defn repl [getchunk] (defn repl [getchunk]
(def newenv (make-env)) (def newenv (make-env))
@ -562,5 +608,5 @@ onvalue."
(defn onvalue [x] (defn onvalue [x]
(put newenv '_ @{:value x}) (put newenv '_ @{:value x})
(pp x)) (pp x))
(run-context newenv (if getchunk getchunk chunks) onvalue (run-context newenv (if getchunk getchunk chunks)
(fn [t x] (print (string t " error: " x))))) onvalue default-error-handler))

View File

@ -589,6 +589,7 @@ DstSlot dstc_fn(DstFopts opts, DstAst *ast, int32_t argn, const Dst *argv) {
def = dstc_pop_funcdef(c); def = dstc_pop_funcdef(c);
def->arity = arity; def->arity = arity;
if (varargs) def->flags |= DST_FUNCDEF_FLAG_VARARG; if (varargs) def->flags |= DST_FUNCDEF_FLAG_VARARG;
if (selfref) def->name = dst_unwrap_symbol(head);
defindex = dstc_addfuncdef(c, def); defindex = dstc_addfuncdef(c, def);
/* Ensure enough slots for vararg function. */ /* Ensure enough slots for vararg function. */

View File

@ -41,8 +41,6 @@ static const DstReg cfuns[] = {
{"array", dst_core_array}, {"array", dst_core_array},
{"tuple", dst_core_tuple}, {"tuple", dst_core_tuple},
{"struct", dst_core_struct}, {"struct", dst_core_struct},
{"fiber", dst_core_fiber},
{"fiber-status", dst_core_fiber_status},
{"buffer", dst_core_buffer}, {"buffer", dst_core_buffer},
{"gensym", dst_core_gensym}, {"gensym", dst_core_gensym},
{"get", dst_core_get}, {"get", dst_core_get},
@ -110,6 +108,7 @@ DstTable *dst_stl_env() {
dst_lib_tuple(args); dst_lib_tuple(args);
dst_lib_buffer(args); dst_lib_buffer(args);
dst_lib_table(args); dst_lib_table(args);
dst_lib_fiber(args);
dst_lib_parse(args); dst_lib_parse(args);
dst_lib_compile(args); dst_lib_compile(args);
dst_lib_asm(args); dst_lib_asm(args);

View File

@ -215,6 +215,7 @@ DstFuncDef *dst_funcdef_alloc() {
def->source = NULL; def->source = NULL;
def->sourcepath = NULL; def->sourcepath = NULL;
def->sourcemap = NULL; def->sourcemap = NULL;
def->name = NULL;
def->defs = NULL; def->defs = NULL;
def->defs_length = 0; def->defs_length = 0;
def->constants_length = 0; def->constants_length = 0;

View File

@ -134,15 +134,6 @@ int dst_core_struct(DstArgs args) {
return dst_return(args, dst_wrap_struct(dst_struct_end(st))); return dst_return(args, dst_wrap_struct(dst_struct_end(st)));
} }
int dst_core_fiber(DstArgs args) {
DstFiber *fiber;
if (args.n < 1) return dst_throw(args, "expected at least 1 argument");
if (!dst_checktype(args.v[0], DST_FUNCTION))
return dst_throw(args, "expected a function");
fiber = dst_fiber(dst_unwrap_function(args.v[0]), 64);
return dst_return(args, dst_wrap_fiber(fiber));
}
int dst_core_gensym(DstArgs args) { int dst_core_gensym(DstArgs args) {
if (args.n > 1) return dst_throw(args, "expected one argument"); if (args.n > 1) return dst_throw(args, "expected one argument");
if (args.n == 0) { if (args.n == 0) {
@ -198,33 +189,6 @@ int dst_core_setproto(DstArgs args) {
return dst_return(args, args.v[0]); return dst_return(args, args.v[0]);
} }
int dst_core_fiber_status(DstArgs args) {
const char *status = "";
if (args.n != 1) return dst_throw(args, "expected 1 argument");
if (!dst_checktype(args.v[0], DST_FIBER)) return dst_throw(args, "expected fiber");
switch(dst_unwrap_fiber(args.v[0])->status) {
case DST_FIBER_PENDING:
status = ":pending";
break;
case DST_FIBER_NEW:
status = ":new";
break;
case DST_FIBER_ALIVE:
status = ":alive";
break;
case DST_FIBER_DEAD:
status = ":dead";
break;
case DST_FIBER_ERROR:
status = ":error";
break;
case DST_FIBER_DEBUG:
status = ":debug";
break;
}
return dst_return(args, dst_csymbolv(status));
}
int dst_core_put(DstArgs args) { int dst_core_put(DstArgs args) {
Dst ds, key, value; Dst ds, key, value;
DstArgs subargs = args; DstArgs subargs = args;

View File

@ -133,6 +133,7 @@ void dst_fiber_funcframe(DstFiber *fiber, DstFunction *func) {
newframe->pc = func->def->bytecode; newframe->pc = func->def->bytecode;
newframe->func = func; newframe->func = func;
newframe->env = NULL; newframe->env = NULL;
newframe->flags = 0;
/* Check varargs */ /* Check varargs */
if (func->def->flags & DST_FUNCDEF_FLAG_VARARG) { if (func->def->flags & DST_FUNCDEF_FLAG_VARARG) {
@ -211,6 +212,7 @@ void dst_fiber_funcframe_tail(DstFiber *fiber, DstFunction *func) {
/* Set frame stuff */ /* Set frame stuff */
dst_fiber_frame(fiber)->func = func; dst_fiber_frame(fiber)->func = func;
dst_fiber_frame(fiber)->pc = func->def->bytecode; dst_fiber_frame(fiber)->pc = func->def->bytecode;
dst_fiber_frame(fiber)->flags |= DST_STACKFRAME_TAILCALL;
} }
/* Push a stack frame to a fiber for a c function */ /* Push a stack frame to a fiber for a c function */
@ -235,6 +237,7 @@ void dst_fiber_cframe(DstFiber *fiber) {
newframe->pc = NULL; newframe->pc = NULL;
newframe->func = NULL; newframe->func = NULL;
newframe->env = NULL; newframe->env = NULL;
newframe->flags = 0;
} }
/* Pop a stack frame from the fiber. Returns the new stack frame, or /* Pop a stack frame from the fiber. Returns the new stack frame, or
@ -251,3 +254,108 @@ void dst_fiber_popframe(DstFiber *fiber) {
fiber->stacktop = fiber->stackstart = fiber->frame; fiber->stacktop = fiber->stackstart = fiber->frame;
fiber->frame = frame->prevframe; fiber->frame = frame->prevframe;
} }
/* CFuns */
static int cfun_fiber(DstArgs args) {
DstFiber *fiber;
if (args.n < 1) return dst_throw(args, "expected at least 1 argument");
if (!dst_checktype(args.v[0], DST_FUNCTION))
return dst_throw(args, "expected a function");
fiber = dst_fiber(dst_unwrap_function(args.v[0]), 64);
return dst_return(args, dst_wrap_fiber(fiber));
}
static int cfun_status(DstArgs args) {
const char *status = "";
if (args.n != 1) return dst_throw(args, "expected 1 argument");
if (!dst_checktype(args.v[0], DST_FIBER)) return dst_throw(args, "expected fiber");
switch(dst_unwrap_fiber(args.v[0])->status) {
case DST_FIBER_PENDING:
status = ":pending";
break;
case DST_FIBER_NEW:
status = ":new";
break;
case DST_FIBER_ALIVE:
status = ":alive";
break;
case DST_FIBER_DEAD:
status = ":dead";
break;
case DST_FIBER_ERROR:
status = ":error";
break;
case DST_FIBER_DEBUG:
status = ":debug";
break;
}
return dst_return(args, dst_csymbolv(status));
}
/* Extract info from one stack frame */
static Dst doframe(DstStackFrame *frame) {
int32_t off;
DstTable *t = dst_table(3);
DstFuncDef *def = NULL;
if (frame->func) {
dst_table_put(t, dst_csymbolv(":function"), dst_wrap_function(frame->func));
def = frame->func->def;
if (def->name) {
dst_table_put(t, dst_csymbolv(":name"), dst_wrap_string(def->name));
}
} else {
dst_table_put(t, dst_csymbolv(":c"), dst_wrap_true());
}
if (frame->flags & DST_STACKFRAME_TAILCALL) {
dst_table_put(t, dst_csymbolv(":tail"), dst_wrap_true());
}
if (frame->pc) {
off = frame->pc - def->bytecode;
dst_table_put(t, dst_csymbolv(":pc"), dst_wrap_integer(off));
if (def->sourcemap) {
DstSourceMapping mapping = def->sourcemap[off];
dst_table_put(t, dst_csymbolv(":source-start"), dst_wrap_integer(mapping.start));
dst_table_put(t, dst_csymbolv(":source-end"), dst_wrap_integer(mapping.end));
}
if (def->source) {
dst_table_put(t, dst_csymbolv(":source"), dst_wrap_string(def->source));
} else if (def->sourcepath) {
dst_table_put(t, dst_csymbolv(":sourcepath"), dst_wrap_string(def->sourcepath));
}
}
return dst_wrap_table(t);
}
static int cfun_stack(DstArgs args) {
DstFiber *fiber;
DstArray *array;
if (args.n != 1) return dst_throw(args, "expected 1 argument");
if (!dst_checktype(args.v[0], DST_FIBER)) return dst_throw(args, "expected fiber");
fiber = dst_unwrap_fiber(args.v[0]);
array = dst_array(0);
{
int32_t i = fiber->frame;
DstStackFrame *frame;
while (i > 0) {
frame = (DstStackFrame *)(fiber->data + i - DST_FRAME_SIZE);
dst_array_push(array, doframe(frame));
i = frame->prevframe;
}
}
return dst_return(args, dst_wrap_array(array));
}
static const DstReg cfuns[] = {
{"fiber", cfun_fiber},
{"fiber-status", cfun_status},
{"fiber-stack", cfun_stack},
{NULL, NULL}
};
/* Module entry point */
int dst_lib_fiber(DstArgs args) {
DstTable *env = dst_env_arg(args);
dst_env_cfuns(env, cfuns);
return 0;
}

View File

@ -162,6 +162,8 @@ static void dst_mark_funcdef(DstFuncDef *def) {
dst_mark_string(def->source); dst_mark_string(def->source);
if (def->sourcepath) if (def->sourcepath)
dst_mark_string(def->sourcepath); dst_mark_string(def->sourcepath);
if (def->name)
dst_mark_string(def->name);
} }
static void dst_mark_function(DstFunction *func) { static void dst_mark_function(DstFunction *func) {

View File

@ -103,21 +103,21 @@ const uint8_t *dst_cstring(const char *str) {
} }
/* Temporary buffer size */ /* Temporary buffer size */
#define DST_BUFSIZE 36 #define BUFSIZE 36
static int32_t real_to_string_impl(uint8_t *buf, double x) { static int32_t real_to_string_impl(uint8_t *buf, double x) {
/* Use 16 decimal places to ignore one ulp errors for now */ /* Use 16 decimal places to ignore one ulp errors for now */
int count = snprintf((char *) buf, DST_BUFSIZE, "%.16gR", x); int count = snprintf((char *) buf, BUFSIZE, "%.16gR", x);
return (int32_t) count; return (int32_t) count;
} }
static void real_to_string_b(DstBuffer *buffer, double x) { static void real_to_string_b(DstBuffer *buffer, double x) {
dst_buffer_ensure(buffer, buffer->count + DST_BUFSIZE); dst_buffer_ensure(buffer, buffer->count + BUFSIZE);
buffer->count += real_to_string_impl(buffer->data + buffer->count, x); buffer->count += real_to_string_impl(buffer->data + buffer->count, x);
} }
static const uint8_t *real_to_string(double x) { static const uint8_t *real_to_string(double x) {
uint8_t buf[DST_BUFSIZE]; uint8_t buf[BUFSIZE];
return dst_string(buf, real_to_string_impl(buf, x)); return dst_string(buf, real_to_string_impl(buf, x));
} }
@ -152,12 +152,12 @@ static int32_t integer_to_string_impl(uint8_t *buf, int32_t x) {
} }
static void integer_to_string_b(DstBuffer *buffer, int32_t x) { static void integer_to_string_b(DstBuffer *buffer, int32_t x) {
dst_buffer_extra(buffer, DST_BUFSIZE); dst_buffer_extra(buffer, BUFSIZE);
buffer->count += integer_to_string_impl(buffer->data + buffer->count, x); buffer->count += integer_to_string_impl(buffer->data + buffer->count, x);
} }
static const uint8_t *integer_to_string(int32_t x) { static const uint8_t *integer_to_string(int32_t x) {
uint8_t buf[DST_BUFSIZE]; uint8_t buf[BUFSIZE];
return dst_string(buf, integer_to_string_impl(buf, x)); return dst_string(buf, integer_to_string_impl(buf, x));
} }
@ -191,19 +191,19 @@ static int32_t string_description_impl(uint8_t *buf, const char *title, void *po
} }
static void string_description_b(DstBuffer *buffer, const char *title, void *pointer) { static void string_description_b(DstBuffer *buffer, const char *title, void *pointer) {
dst_buffer_ensure(buffer, buffer->count + DST_BUFSIZE); dst_buffer_ensure(buffer, buffer->count + BUFSIZE);
buffer->count += string_description_impl(buffer->data + buffer->count, title, pointer); buffer->count += string_description_impl(buffer->data + buffer->count, title, pointer);
} }
/* Describes a pointer with a title (string_description("bork", myp) returns /* Describes a pointer with a title (string_description("bork", myp) returns
* a string "<bork 0x12345678>") */ * a string "<bork 0x12345678>") */
static const uint8_t *string_description(const char *title, void *pointer) { static const uint8_t *string_description(const char *title, void *pointer) {
uint8_t buf[DST_BUFSIZE]; uint8_t buf[BUFSIZE];
return dst_string(buf, string_description_impl(buf, title, pointer)); return dst_string(buf, string_description_impl(buf, title, pointer));
} }
#undef HEX #undef HEX
#undef DST_BUFSIZE #undef BUFSIZE
/* TODO - add more characters to escape. /* TODO - add more characters to escape.
* *

View File

@ -87,7 +87,6 @@ int dst_core_tuple(DstArgs args);
int dst_core_array(DstArgs args); int dst_core_array(DstArgs args);
int dst_core_table(DstArgs args); int dst_core_table(DstArgs args);
int dst_core_struct(DstArgs args); int dst_core_struct(DstArgs args);
int dst_core_fiber(DstArgs args);
int dst_core_buffer(DstArgs args); int dst_core_buffer(DstArgs args);
int dst_core_gensym(DstArgs args); int dst_core_gensym(DstArgs args);
int dst_core_length(DstArgs args); int dst_core_length(DstArgs args);
@ -95,8 +94,6 @@ int dst_core_get(DstArgs args);
int dst_core_rawget(DstArgs args); int dst_core_rawget(DstArgs args);
int dst_core_getproto(DstArgs args); int dst_core_getproto(DstArgs args);
int dst_core_setproto(DstArgs args); int dst_core_setproto(DstArgs args);
int dst_core_fiber_status(DstArgs args);
int dst_core_fiber_location(DstArgs args);
int dst_core_put(DstArgs args); int dst_core_put(DstArgs args);
int dst_core_gccollect(DstArgs args); int dst_core_gccollect(DstArgs args);
int dst_core_gcsetinterval(DstArgs args); int dst_core_gcsetinterval(DstArgs args);
@ -113,6 +110,7 @@ int dst_lib_array(DstArgs args);
int dst_lib_tuple(DstArgs args); int dst_lib_tuple(DstArgs args);
int dst_lib_buffer(DstArgs args); int dst_lib_buffer(DstArgs args);
int dst_lib_table(DstArgs args); int dst_lib_table(DstArgs args);
int dst_lib_fiber(DstArgs args);
/* Useful for compiler */ /* Useful for compiler */
Dst dst_op_add(Dst lhs, Dst rhs); Dst dst_op_add(Dst lhs, Dst rhs);

View File

@ -335,12 +335,16 @@ struct DstFiber {
} status; } status;
}; };
/* Mark if a stack frame is a tail call for debugging */
#define DST_STACKFRAME_TAILCALL 1
/* A stack frame on the fiber. Is stored along with the stack values. */ /* A stack frame on the fiber. Is stored along with the stack values. */
struct DstStackFrame { struct DstStackFrame {
DstFunction *func; DstFunction *func;
uint32_t *pc; uint32_t *pc;
int32_t prevframe;
DstFuncEnv *env; DstFuncEnv *env;
int32_t prevframe;
uint32_t flags;
}; };
/* Number of Dsts a frame takes up in the stack */ /* Number of Dsts a frame takes up in the stack */
@ -395,6 +399,7 @@ struct DstFuncDef {
DstSourceMapping *sourcemap; DstSourceMapping *sourcemap;
const uint8_t *source; const uint8_t *source;
const uint8_t *sourcepath; const uint8_t *sourcepath;
const uint8_t *name;
uint32_t flags; uint32_t flags;
int32_t slotcount; /* The amount of stack space required for the function */ int32_t slotcount; /* The amount of stack space required for the function */