diff --git a/Makefile b/Makefile index 2d5e4c8b..9dbb6d05 100644 --- a/Makefile +++ b/Makefile @@ -32,7 +32,7 @@ BINDIR=$(PREFIX)/bin # TODO - when api is finalized, only export public symbols instead of using rdynamic # which exports all symbols. Saves a few KB in binary. -CFLAGS=-std=c99 -Wall -Wextra -Isrc/include -fpic -Os -s +CFLAGS=-std=c99 -Wall -Wextra -Isrc/include -fpic -O2 CLIBS=-lm -ldl PREFIX=/usr/local DST_TARGET=dst diff --git a/src/core/array.c b/src/core/array.c index d60a15e9..8338dc9a 100644 --- a/src/core/array.c +++ b/src/core/array.c @@ -183,7 +183,7 @@ static int cfun_slice(DstArgs args) { int32_t start, end; DST_MINARITY(args, 1); DST_MAXARITY(args, 3); - if (!dst_seq_view(args.v[0], &vals, &len)) + if (!dst_indexed_view(args.v[0], &vals, &len)) DST_THROW(args, "expected array|tuple"); /* Get start */ if (args.n < 2) { @@ -231,7 +231,7 @@ static int cfun_concat(DstArgs args) { { int32_t j, len; const Dst *vals; - dst_seq_view(args.v[i], &vals, &len); + dst_indexed_view(args.v[i], &vals, &len); for (j = 0; j < len; j++) dst_array_push(array, vals[j]); } diff --git a/src/core/asm.c b/src/core/asm.c index 95cd90a9..1a732666 100644 --- a/src/core/asm.c +++ b/src/core/asm.c @@ -554,7 +554,7 @@ static DstAssembleResult dst_asm1(DstAssembler *parent, Dst source, int flags) { /* Create slot aliases */ x = dst_get(s, dst_csymbolv("slots")); - if (dst_seq_view(x, &arr, &count)) { + if (dst_indexed_view(x, &arr, &count)) { for (i = 0; i < count; i++) { Dst v = arr[i]; if (dst_checktype(v, DST_TUPLE)) { @@ -575,7 +575,7 @@ static DstAssembleResult dst_asm1(DstAssembler *parent, Dst source, int flags) { /* Parse constants */ x = dst_get(s, dst_csymbolv("constants")); - if (dst_seq_view(x, &arr, &count)) { + if (dst_indexed_view(x, &arr, &count)) { def->constants_length = count; def->constants = malloc(sizeof(Dst) * count); if (NULL == def->constants) { @@ -610,7 +610,7 @@ static DstAssembleResult dst_asm1(DstAssembler *parent, Dst source, int flags) { /* Parse sub funcdefs */ x = dst_get(s, dst_csymbolv("closures")); - if (dst_seq_view(x, &arr, &count)) { + if (dst_indexed_view(x, &arr, &count)) { int32_t i; for (i = 0; i < count; i++) { DstAssembleResult subres; @@ -640,7 +640,7 @@ static DstAssembleResult dst_asm1(DstAssembler *parent, Dst source, int flags) { /* Parse bytecode and labels */ x = dst_get(s, dst_csymbolv("bytecode")); - if (dst_seq_view(x, &arr, &count)) { + if (dst_indexed_view(x, &arr, &count)) { /* Do labels and find length */ int32_t blength = 0; for (i = 0; i < count; ++i) { @@ -696,7 +696,7 @@ static DstAssembleResult dst_asm1(DstAssembler *parent, Dst source, int flags) { /* Check for source mapping */ x = dst_get(s, dst_csymbolv("sourcemap")); - if (dst_seq_view(x, &arr, &count)) { + if (dst_indexed_view(x, &arr, &count)) { dst_asm_assert(&a, count == def->bytecode_length, "sourcemap must have the same length as the bytecode"); def->sourcemap = malloc(sizeof(DstSourceMapping) * count); for (i = 0; i < count; i++) { diff --git a/src/core/compile.c b/src/core/compile.c index 00a3e7cb..3c42b694 100644 --- a/src/core/compile.c +++ b/src/core/compile.c @@ -48,24 +48,6 @@ void dstc_cerror(DstCompiler *c, const char *m) { dstc_error(c, dst_cstring(m)); } -/* Check error */ -int dstc_iserr(DstFopts *opts) { - return (opts->compiler->result.status == DST_COMPILE_ERROR); -} - -/* Get the next key in an associative data structure. Used for iterating through an - * associative data structure. */ -const DstKV *dstc_next(Dst ds, const DstKV *kv) { - switch(dst_type(ds)) { - default: - return NULL; - case DST_TABLE: - return (const DstKV *) dst_table_next(dst_unwrap_table(ds), kv); - case DST_STRUCT: - return dst_struct_next(dst_unwrap_struct(ds), kv); - } -} - /* Free a slot */ void dstc_freeslot(DstCompiler *c, DstSlot s) { if (s.flags & (DST_SLOT_CONSTANT | DST_SLOT_REF | DST_SLOT_NAMED)) return; @@ -318,11 +300,14 @@ DstSlot *dstc_toslots(DstCompiler *c, const Dst *vals, int32_t len) { /* Get a bunch of slots for function arguments */ DstSlot *dstc_toslotskv(DstCompiler *c, Dst ds) { DstSlot *ret = NULL; - const DstKV *kv = NULL; DstFopts subopts = dstc_fopts_default(c); - while ((kv = dstc_next(ds, kv))) { - dst_v_push(ret, dstc_value(subopts, kv->key)); - dst_v_push(ret, dstc_value(subopts, kv->value)); + const DstKV *kvs = NULL; + int32_t cap, i, len; + dst_dictionary_view(ds, &kvs, &len, &cap); + for (i = 0; i < cap; i++) { + if (dst_checktype(kvs[i].key, DST_NIL)) continue; + dst_v_push(ret, dstc_value(subopts, kvs[i].key)); + dst_v_push(ret, dstc_value(subopts, kvs[i].value)); } return ret; } @@ -500,7 +485,7 @@ DstSlot dstc_value(DstFopts opts, Dst x) { c->recursion_guard--; /* Guard against previous errors and unbounded recursion */ - if (dstc_iserr(&opts)) return dstc_cslot(dst_wrap_nil()); + if (c->result.status == DST_COMPILE_ERROR) return dstc_cslot(dst_wrap_nil()); if (c->recursion_guard <= 0) { dstc_cerror(c, "recursed too deeply"); return dstc_cslot(dst_wrap_nil()); @@ -509,8 +494,10 @@ DstSlot dstc_value(DstFopts opts, Dst x) { /* Macro expand. Also gets possible special form and * refines source mapping cursor if possible. */ const DstSpecial *spec = NULL; - int macroi = DST_RECURSION_GUARD; - while (macroi && !dstc_iserr(&opts) && macroexpand1(c, x, &x, &spec)) + int macroi = DST_MAX_MACRO_EXPAND; + while (macroi && + c->result.status != DST_COMPILE_ERROR && + macroexpand1(c, x, &x, &spec)) macroi--; if (macroi == 0) { dstc_cerror(c, "recursed too deeply in macro expansion"); @@ -559,13 +546,11 @@ DstSlot dstc_value(DstFopts opts, Dst x) { } } - if (dstc_iserr(&opts)) { + if (c->result.status == DST_COMPILE_ERROR) return dstc_cslot(dst_wrap_nil()); - } c->current_mapping = last_mapping; - if (opts.flags & DST_FOPTS_TAIL) { + if (opts.flags & DST_FOPTS_TAIL) ret = dstc_return(opts.compiler, ret); - } if (opts.flags & DST_FOPTS_HINT) { dstc_copy(opts.compiler, opts.hint, ret); ret = opts.hint; diff --git a/src/core/compile.h b/src/core/compile.h index 44cc1cd7..6cbff2af 100644 --- a/src/core/compile.h +++ b/src/core/compile.h @@ -175,12 +175,6 @@ const DstFunOptimizer *dstc_funopt(uint32_t flags); /* Get a special. Return NULL if none exists */ const DstSpecial *dstc_special(const uint8_t *name); -/* Check error */ -int dstc_iserr(DstFopts *opts); - -/* Helper for iterating tables and structs */ -const DstKV *dstc_next(Dst ds, const DstKV *kv); - void dstc_freeslot(DstCompiler *c, DstSlot s); void dstc_nameslot(DstCompiler *c, const uint8_t *sym, DstSlot s); DstSlot dstc_farslot(DstCompiler *c); diff --git a/src/core/specials.c b/src/core/specials.c index 766cf106..55f3b49c 100644 --- a/src/core/specials.c +++ b/src/core/specials.c @@ -57,7 +57,7 @@ static int destructure(DstCompiler *c, { int32_t i, len; const Dst *values; - dst_seq_view(left, &values, &len); + dst_indexed_view(left, &values, &len); for (i = 0; i < len; i++) { DstSlot nextright = dstc_farslot(c); Dst subval = values[i]; @@ -75,12 +75,15 @@ static int destructure(DstCompiler *c, case DST_TABLE: case DST_STRUCT: { - const DstKV *kv = NULL; - while ((kv = dstc_next(left, kv))) { + const DstKV *kvs = NULL; + int32_t i, cap, len; + dst_dictionary_view(left, &kvs, &len, &cap); + for (i = 0; i < cap; i++) { + if (dst_checktype(kvs[i].key, DST_NIL)) continue; DstSlot nextright = dstc_farslot(c); - DstSlot k = dstc_value(dstc_fopts_default(c), kv->key); + DstSlot k = dstc_value(dstc_fopts_default(c), kvs[i].key); dstc_emit_sss(c, DOP_GET, nextright, right, k, 1); - if (destructure(c, kv->value, nextright, leaf, attr)) + if (destructure(c, kvs[i].value, nextright, leaf, attr)) dstc_freeslot(c, nextright); } } @@ -190,7 +193,8 @@ DstSlot dstc_var(DstFopts opts, int32_t argn, const Dst *argv) { DstCompiler *c = opts.compiler; Dst head; DstSlot ret = dohead(c, opts, &head, argn, argv); - if (dstc_iserr(&opts)) return dstc_cslot(dst_wrap_nil()); + if (c->result.status == DST_COMPILE_ERROR) + return dstc_cslot(dst_wrap_nil()); if (destructure(c, argv[0], ret, varleaf, handleattr(c, argn, argv))) dstc_freeslot(c, ret); return dstc_cslot(dst_wrap_nil()); @@ -223,7 +227,8 @@ DstSlot dstc_def(DstFopts opts, int32_t argn, const Dst *argv) { Dst head; opts.flags &= ~DST_FOPTS_HINT; DstSlot ret = dohead(c, opts, &head, argn, argv); - if (dstc_iserr(&opts)) return dstc_cslot(dst_wrap_nil()); + if (c->result.status == DST_COMPILE_ERROR) + return dstc_cslot(dst_wrap_nil()); if (destructure(c, argv[0], ret, defleaf, handleattr(c, argn, argv))) dstc_freeslot(c, ret); return dstc_cslot(dst_wrap_nil()); @@ -454,7 +459,7 @@ DstSlot dstc_fn(DstFopts opts, int32_t argn, const Dst *argv) { goto error; } paramv = argv[parami]; - if (dst_seq_view(paramv, ¶ms, ¶mcount)) { + if (dst_indexed_view(paramv, ¶ms, ¶mcount)) { int32_t i; for (i = 0; i < paramcount; i++) { Dst param = params[i]; @@ -494,7 +499,7 @@ DstSlot dstc_fn(DstFopts opts, int32_t argn, const Dst *argv) { } else for (argi = parami + 1; argi < argn; argi++) { subopts.flags = (argi == (argn - 1)) ? DST_FOPTS_TAIL : DST_FOPTS_DROP; dstc_value(subopts, argv[argi]); - if (dstc_iserr(&opts)) + if (c->result.status == DST_COMPILE_ERROR) goto error2; } diff --git a/src/core/string.c b/src/core/string.c index 72eb597b..0d272644 100644 --- a/src/core/string.c +++ b/src/core/string.c @@ -937,7 +937,7 @@ static int cfun_join(DstArgs args) { for (i = 0; i < partslen; i++) { const uint8_t *chunk; int32_t chunklen = 0; - if (!dst_chararray_view(parts[i], &chunk, &chunklen)) { + if (!dst_bytes_view(parts[i], &chunk, &chunklen)) { DST_THROW(args, "expected string|symbol|buffer"); } if (i) finallen += joinerlen; @@ -951,7 +951,7 @@ static int cfun_join(DstArgs args) { memcpy(out, joiner, joinerlen); out += joinerlen; } - dst_chararray_view(parts[i], &chunk, &chunklen); + dst_bytes_view(parts[i], &chunk, &chunklen); memcpy(out, chunk, chunklen); out += chunklen; } diff --git a/src/core/tuple.c b/src/core/tuple.c index 400e6192..62afbb70 100644 --- a/src/core/tuple.c +++ b/src/core/tuple.c @@ -44,7 +44,7 @@ const Dst *dst_tuple_end(Dst *tuple) { } /* Build a tuple with n values */ -const Dst *dst_tuple_n(Dst *values, int32_t n) { +const Dst *dst_tuple_n(const Dst *values, int32_t n) { Dst *t = dst_tuple_begin(n); memcpy(t, values, sizeof(Dst) * n); return dst_tuple_end(t); @@ -97,7 +97,7 @@ static int cfun_slice(DstArgs args) { Dst *ret; int32_t start, end; DST_MINARITY(args, 1); - if (!dst_seq_view(args.v[0], &vals, &len)) DST_THROW(args, "expected array/tuple"); + if (!dst_indexed_view(args.v[0], &vals, &len)) DST_THROW(args, "expected array/tuple"); /* Get start */ if (args.n < 2) { start = 0; @@ -133,7 +133,7 @@ static int cfun_prepend(DstArgs args) { int32_t len; Dst *n; DST_FIXARITY(args, 2); - if (!dst_seq_view(args.v[0], &t, &len)) DST_THROW(args, "expected tuple/array"); + if (!dst_indexed_view(args.v[0], &t, &len)) DST_THROW(args, "expected tuple/array"); n = dst_tuple_begin(len + 1); memcpy(n + 1, t, sizeof(Dst) * len); n[0] = args.v[1]; @@ -145,7 +145,7 @@ static int cfun_append(DstArgs args) { int32_t len; Dst *n; DST_FIXARITY(args, 2); - if (!dst_seq_view(args.v[0], &t, &len)) DST_THROW(args, "expected tuple/array"); + if (!dst_indexed_view(args.v[0], &t, &len)) DST_THROW(args, "expected tuple/array"); n = dst_tuple_begin(len + 1); memcpy(n, t, sizeof(Dst) * len); n[len] = args.v[1]; diff --git a/src/core/util.c b/src/core/util.c index a2d5e123..9fe07737 100644 --- a/src/core/util.c +++ b/src/core/util.c @@ -202,7 +202,7 @@ DstTable *dst_env_arg(DstArgs args) { /* Read both tuples and arrays as c pointers + int32_t length. Return 1 if the * view can be constructed, 0 if an invalid type. */ -int dst_seq_view(Dst seq, const Dst **data, int32_t *len) { +int dst_indexed_view(Dst seq, const Dst **data, int32_t *len) { if (dst_checktype(seq, DST_ARRAY)) { *data = dst_unwrap_array(seq)->data; *len = dst_unwrap_array(seq)->count; @@ -217,7 +217,7 @@ int dst_seq_view(Dst seq, const Dst **data, int32_t *len) { /* Read both strings and buffer as unsigned character array + int32_t len. * Returns 1 if the view can be constructed and 0 if the type is invalid. */ -int dst_chararray_view(Dst str, const uint8_t **data, int32_t *len) { +int dst_bytes_view(Dst str, const uint8_t **data, int32_t *len) { if (dst_checktype(str, DST_STRING) || dst_checktype(str, DST_SYMBOL)) { *data = dst_unwrap_string(str); *len = dst_string_length(dst_unwrap_string(str)); @@ -233,7 +233,7 @@ int dst_chararray_view(Dst str, const uint8_t **data, int32_t *len) { /* Read both structs and tables as the entries of a hashtable with * identical structure. Returns 1 if the view can be constructed and * 0 if the type is invalid. */ -int dst_hashtable_view(Dst tab, const DstKV **data, int32_t *len, int32_t *cap) { +int dst_dictionary_view(Dst tab, const DstKV **data, int32_t *len, int32_t *cap) { if (dst_checktype(tab, DST_TABLE)) { *data = dst_unwrap_table(tab)->data; *cap = dst_unwrap_table(tab)->capacity; diff --git a/src/core/vm.c b/src/core/vm.c index 0a49455b..fbac0e2d 100644 --- a/src/core/vm.c +++ b/src/core/vm.c @@ -708,7 +708,7 @@ static void *op_lookup[255] = { { const Dst *vals; int32_t len; - if (dst_seq_view(stack[oparg(1, 0xFFFFFF)], &vals, &len)) { + if (dst_indexed_view(stack[oparg(1, 0xFFFFFF)], &vals, &len)) { dst_fiber_pushn(fiber, vals, len); } else { retreg = stack[oparg(1, 0xFFFFFF)]; diff --git a/src/include/dst/dst.h b/src/include/dst/dst.h index 754b8797..65dce48c 100644 --- a/src/include/dst/dst.h +++ b/src/include/dst/dst.h @@ -136,13 +136,21 @@ extern "C" { /* Maximum depth to follow table prototypes before giving up and returning nil. */ #define DST_MAX_PROTO_DEPTH 200 +/* Maximum depth to follow table prototypes before giving up and returning nil. */ +#define DST_MAX_MACRO_EXPAND 200 + /* Define max stack size for stacks before raising a stack overflow error. * If this is not defined, fiber stacks can grow without limit (until memory * runs out) */ #define DST_STACK_MAX 8192 -/* Use nanboxed values - uses 8 bytes per value instead of 12 or 16. */ +/* Use nanboxed values - uses 8 bytes per value instead of 12 or 16. + * To turn of nanboxing, for debugging purposes or for certain + * architectures (Nanboxing only tested on x86 and x64), comment out + * the DST_NANBOX define.*/ #define DST_NANBOX + +/* Further refines the type of nanboxing to use. */ #define DST_NANBOX_47 /* Alignment for pointers */ @@ -895,7 +903,7 @@ int dst_buffer_push_u64(DstBuffer *buffer, uint64_t x); #define dst_tuple_sm_col(t) ((dst_tuple_raw(t)[3])) Dst *dst_tuple_begin(int32_t length); const Dst *dst_tuple_end(Dst *tuple); -const Dst *dst_tuple_n(Dst *values, int32_t n); +const Dst *dst_tuple_n(const Dst *values, int32_t n); int dst_tuple_equal(const Dst *lhs, const Dst *rhs); int dst_tuple_compare(const Dst *lhs, const Dst *rhs); @@ -965,9 +973,9 @@ DstFiber *dst_fiber(DstFunction *callee, int32_t capacity); #define dst_fiber_status(f) (((f)->flags & DST_FIBER_STATUS_MASK) >> DST_FIBER_STATUS_OFFSET) /* Treat similar types through uniform interfaces for iteration */ -int dst_seq_view(Dst seq, const Dst **data, int32_t *len); -int dst_chararray_view(Dst str, const uint8_t **data, int32_t *len); -int dst_hashtable_view(Dst tab, const DstKV **data, int32_t *len, int32_t *cap); +int dst_indexed_view(Dst seq, const Dst **data, int32_t *len); +int dst_bytes_view(Dst str, const uint8_t **data, int32_t *len); +int dst_dictionary_view(Dst tab, const DstKV **data, int32_t *len, int32_t *cap); /* Abstract */ #define dst_abstract_header(u) ((DstAbstractHeader *)(u) - 1) @@ -1107,14 +1115,14 @@ int dst_lib_compile(DstArgs args); #define DST_ARG_BYTES(DESTBYTES, DESTLEN, A, N) do {\ if ((A).n <= (N)) return dst_typemany_err(A, N, DST_TFLAG_BYTES);\ - if (!dst_chararray_view((A).v[(N)], &(DESTBYTES), &(DESTLEN))) {\ + if (!dst_bytes_view((A).v[(N)], &(DESTBYTES), &(DESTLEN))) {\ return dst_typemany_err(A, N, DST_TFLAG_BYTES);\ }\ } while (0) #define DST_ARG_INDEXED(DESTVALS, DESTLEN, A, N) do {\ if ((A).n <= (N)) return dst_typemany_err(A, N, DST_TFLAG_INDEXED);\ - if (!dst_seq_view((A).v[(N)], &(DESTVALS), &(DESTLEN))) {\ + if (!dst_indexed_view((A).v[(N)], &(DESTVALS), &(DESTLEN))) {\ return dst_typemany_err(A, N, DST_TFLAG_INDEXED);\ }\ } while (0) diff --git a/test/suite1.dst b/test/suite1.dst index 9187f4f6..8ecdc21e 100644 --- a/test/suite1.dst +++ b/test/suite1.dst @@ -194,4 +194,8 @@ (assert (= 7 (case :a :b 5 :c 6 :u 10 7)), "case with default") +# Testing the loop and for macros +(def xs (apply1 tuple (for [x :range [0 10] :when (even? x)] (tuple (/ x 2) x)))) +(assert (= xs '((0 0) (1 2) (2 4) (3 6) (4 8))) "for macro 1") + (end-suite)