diff --git a/Makefile b/Makefile index a00c886b..5fe8aaa7 100644 --- a/Makefile +++ b/Makefile @@ -31,7 +31,7 @@ CLIBS=-lm -ldl PREFIX=/usr/local DST_TARGET=dst DEBUGGER=lldb -DST_INTERNAL_HEADERS=$(addprefix core/,symcache.h opcodes.h compile.h gc.h sourcemap.h util.h) +DST_INTERNAL_HEADERS=$(addprefix core/,symcache.h opcodes.h compile.h gc.h util.h) DST_HEADERS=$(addprefix include/dst/,dst.h dstconfig.h dsttypes.h dststate.h dststl.h) DST_C_LIBS=$(addprefix libs/,testlib.so) @@ -48,8 +48,8 @@ all: $(DST_TARGET) ################################### DST_CORE_SOURCES=$(addprefix core/,\ - abstract.c array.c asm.c buffer.c compile.c compile_specials.c\ - fiber.c gc.c io.c math.c native.c parse.c sourcemap.c string.c\ + abstract.c array.c asm.c ast.c buffer.c compile.c compile_specials.c\ + context.c fiber.c gc.c io.c math.c native.c parse.c string.c\ stl.c strtod.c struct.c symcache.c table.c tuple.c util.c\ value.c vm.c wrap.c) diff --git a/client/main.c b/client/main.c index efc0966c..0e57a4b8 100644 --- a/client/main.c +++ b/client/main.c @@ -117,7 +117,6 @@ static int repl() { { opts.source = res.value; opts.flags = 0; - opts.sourcemap = res.map; opts.env = env; cres = dst_compile(opts); if (cres.status == DST_COMPILE_OK) { @@ -167,7 +166,6 @@ static void runfile(const uint8_t *src, int32_t len) { { opts.source = res.value; opts.flags = 0; - opts.sourcemap = res.map; opts.env = env; cres = dst_compile(opts); if (cres.status == DST_COMPILE_OK) { @@ -290,7 +288,9 @@ int main(int argc, char **argv) { /* Run a repl if nothing else happened, or the flag is set */ if (!fileRead || (flags & DST_CLIENT_REPL)) { - status = repl(); + DstContext ctxt; + dst_context_repl(&ctxt, env); + status = dst_context_run(&ctxt); } dst_deinit(); diff --git a/core/asm.c b/core/asm.c index e1ef713f..1896f67a 100644 --- a/core/asm.c +++ b/core/asm.c @@ -25,7 +25,6 @@ #include #include "opcodes.h" #include "gc.h" -#include "sourcemap.h" #include "util.h" /* Bytecode op argument types */ diff --git a/core/ast.c b/core/ast.c new file mode 100644 index 00000000..2dc2eb41 --- /dev/null +++ b/core/ast.c @@ -0,0 +1,186 @@ +/* +* Copyright (c) 2017 Calvin Rose +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to +* deal in the Software without restriction, including without limitation the +* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +* sell copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +* IN THE SOFTWARE. +*/ + +#include + +/* Mark an ast node */ +static int dst_ast_gcmark(void *p, size_t size) { + DstAst *ast = (DstAst *)p; + (void) size; + dst_mark(ast->value); + return 0; +} + +/* AST type */ +static DstAbstractType dst_ast_type = { + "ast", + NULL, + dst_ast_gcmark +}; + +/* Create an ast type */ +Dst dst_ast_wrap(Dst x, int32_t start, int32_t end) { + DstAst *ast = dst_abstract(&dst_ast_type, sizeof(DstAst)); + ast->value = x; + ast->source_start = start; + ast->source_end = end; + ast->flags = 1 << dst_type(x); + return dst_wrap_abstract(ast); +} + +/* Get the node associated with a value */ +DstAst *dst_ast_node(Dst x) { + if (dst_checktype(x, DST_ABSTRACT) && + dst_abstract_type(dst_unwrap_abstract(x)) == &dst_ast_type) { + DstAst *ast = (DstAst *)dst_unwrap_abstract(x); + return ast; + } + return NULL; +} + +/* Unwrap an ast value one level deep */ +Dst dst_ast_unwrap1(Dst x) { + if (dst_checktype(x, DST_ABSTRACT) && + dst_abstract_type(dst_unwrap_abstract(x)) == &dst_ast_type) { + DstAst *ast = (DstAst *)dst_unwrap_abstract(x); + return ast->value; + } + return x; +} + +Dst dst_ast_unwrap(Dst x); + +static Dst astunwrap_array(DstArray *other) { + DstArray *array; + Dst diffval; + int32_t i, prescan; + for (prescan = 0; prescan < other->count; prescan++) { + diffval = dst_ast_unwrap(other->data[prescan]); + if (!dst_equals(diffval, other->data[prescan])) break; + } + if (prescan == other->count) return dst_wrap_array(other); + array = dst_array(other->count); + for (i = 0; i < prescan; i++) { + array->data[i] = other->data[i]; + } + array->data[prescan] = diffval; + for (i = prescan + 1; i < other->count; i++) { + array->data[i] = dst_ast_unwrap(other->data[i]); + } + array->count = other->count; + return dst_wrap_array(array); +} + +static Dst astunwrap_tuple(const Dst *other) { + Dst *tuple; + int32_t i, prescan; + Dst diffval; + for (prescan = 0; prescan < dst_tuple_length(other); prescan++) { + diffval = dst_ast_unwrap(other[prescan]); + if (!dst_equals(diffval, other[prescan])) break; + } + if (prescan == dst_tuple_length(other)) return dst_wrap_tuple(other); + tuple = dst_tuple_begin(dst_tuple_length(other)); + for (i = 0; i < prescan; i++) { + tuple[i] = other[i]; + } + tuple[prescan] = diffval; + for (i = prescan + 1; i < dst_tuple_length(other); i++) { + tuple[i] = dst_ast_unwrap(other[i]); + } + return dst_wrap_tuple(dst_tuple_end(tuple)); +} + +static Dst astunwrap_struct(const DstKV *other) { + DstKV *st; + const DstKV *prescan, *iter; + Dst diffval, diffkey; + prescan = NULL; + while ((prescan = dst_struct_next(other, prescan))) { + diffkey = dst_ast_unwrap(prescan->key); + diffval = dst_ast_unwrap(prescan->value); + if (!dst_equals(diffkey, prescan->key) || + !dst_equals(diffval, prescan->value)) + break; + } + if (!prescan) return dst_wrap_struct(other); + st = dst_struct_begin(dst_struct_length(other)); + iter = NULL; + while ((iter = dst_struct_next(other, iter))) { + if (iter == prescan) break; + dst_struct_put(st, iter->key, iter->value); + } + dst_struct_put(st, diffkey, diffval); + while ((iter = dst_struct_next(other, iter))) { + dst_struct_put(st, + dst_ast_unwrap(iter->key), + dst_ast_unwrap(iter->value)); + } + return dst_wrap_struct(dst_struct_end(st)); +} + +static Dst astunwrap_table(DstTable *other) { + DstTable *table; + const DstKV *prescan, *iter; + Dst diffval, diffkey; + prescan = NULL; + while ((prescan = dst_table_next(other, prescan))) { + diffkey = dst_ast_unwrap(prescan->key); + diffval = dst_ast_unwrap(prescan->value); + if (!dst_equals(diffkey, prescan->key) || + !dst_equals(diffval, prescan->value)) + break; + } + if (!prescan) return dst_wrap_table(other); + table = dst_table(other->capacity); + iter = NULL; + while ((iter = dst_table_next(other, iter))) { + if (iter == prescan) break; + dst_table_put(table, iter->key, iter->value); + } + dst_table_put(table, diffkey, diffval); + while ((iter = dst_table_next(other, iter))) { + dst_table_put(table, + dst_ast_unwrap(iter->key), + dst_ast_unwrap(iter->value)); + } + return dst_wrap_table(table); +} + +/* Unwrap an ast value recursively. Preserve as much structure as possible + * to avoid unecessary allocation. */ +Dst dst_ast_unwrap(Dst x) { + x = dst_ast_unwrap1(x); + switch (dst_type(x)) { + default: + return x; + case DST_ARRAY: + return astunwrap_array(dst_unwrap_array(x)); + case DST_TUPLE: + return astunwrap_tuple(dst_unwrap_tuple(x)); + case DST_STRUCT: + return astunwrap_struct(dst_unwrap_struct(x)); + case DST_TABLE: + return astunwrap_table(dst_unwrap_table(x)); + } +} + diff --git a/core/compile.c b/core/compile.c index 1d15d004..2ef43761 100644 --- a/core/compile.c +++ b/core/compile.c @@ -24,18 +24,25 @@ #include #include "compile.h" #include "gc.h" -#include "sourcemap.h" #include "util.h" +DstFopts dstc_fopts_default(DstCompiler *c) { + DstFopts ret; + ret.compiler = c; + ret.flags = 0; + ret.hint = dstc_cslot(dst_wrap_nil()); + return ret; +} + /* Throw an error with a dst string. */ -void dstc_error(DstCompiler *c, const Dst *sourcemap, const uint8_t *m) { +void dstc_error(DstCompiler *c, DstAst *ast, const uint8_t *m) { /* Don't override first error */ if (c->result.status == DST_COMPILE_ERROR) { return; } - if (NULL != sourcemap) { - c->result.error_start = dst_unwrap_integer(sourcemap[0]); - c->result.error_end = dst_unwrap_integer(sourcemap[1]); + if (NULL != ast) { + c->result.error_start = ast->source_start; + c->result.error_end = ast->source_end; } else { c->result.error_start = -1; c->result.error_end = -1; @@ -45,38 +52,8 @@ void dstc_error(DstCompiler *c, const Dst *sourcemap, const uint8_t *m) { } /* Throw an error with a message in a cstring */ -void dstc_cerror(DstCompiler *c, const Dst *sourcemap, const char *m) { - dstc_error(c, sourcemap, dst_cstring(m)); -} - -/* Use these to get sub options. They will traverse the source map so - * compiler errors make sense. Then modify the returned options. */ -DstFopts dstc_getindex(DstFopts opts, int32_t index) { - const Dst *sourcemap = dst_sourcemap_index(opts.sourcemap, index); - Dst nextval = dst_getindex(opts.x, index); - opts.x = nextval; - opts.flags = 0; - opts.sourcemap = sourcemap; - return opts; -} - -/* Index into the key of a table or struct */ -DstFopts dstc_getkey(DstFopts opts, Dst key) { - const Dst *sourcemap = dst_sourcemap_key(opts.sourcemap, key); - opts.x = key; - opts.sourcemap = sourcemap; - opts.flags = 0; - return opts; -} - -/* Index into the value of a table or struct */ -DstFopts dstc_getvalue(DstFopts opts, Dst key) { - const Dst *sourcemap = dst_sourcemap_value(opts.sourcemap, key); - Dst nextval = dst_get(opts.x, key); - opts.x = nextval; - opts.sourcemap = sourcemap; - opts.flags = 0; - return opts; +void dstc_cerror(DstCompiler *c, DstAst *ast, const char *m) { + dstc_error(c, ast, dst_cstring(m)); } /* Check error */ @@ -229,7 +206,7 @@ DstSlot dstc_cslot(Dst x) { /* Allow searching for symbols. Return information about the symbol */ DstSlot dstc_resolve( DstCompiler *c, - const Dst *sourcemap, + DstAst *ast, const uint8_t *sym) { DstSlot ret = dstc_cslot(dst_wrap_nil()); @@ -261,7 +238,7 @@ DstSlot dstc_resolve( Dst check = dst_get(c->env, dst_wrap_symbol(sym)); Dst ref; if (!(dst_checktype(check, DST_STRUCT) || dst_checktype(check, DST_TABLE))) { - dstc_error(c, sourcemap, dst_formatc("unknown symbol %q", sym)); + dstc_error(c, ast, dst_formatc("unknown symbol %q", sym)); return dstc_cslot(dst_wrap_nil()); } ref = dst_get(check, dst_csymbolv("ref")); @@ -331,11 +308,11 @@ DstSlot dstc_resolve( } /* Emit a raw instruction with source mapping. */ -void dstc_emit(DstCompiler *c, const Dst *sourcemap, uint32_t instr) { +void dstc_emit(DstCompiler *c, DstAst *ast, uint32_t instr) { dst_v_push(c->buffer, instr); - if (NULL != sourcemap) { - dst_v_push(c->mapbuffer, dst_unwrap_integer(sourcemap[0])); - dst_v_push(c->mapbuffer, dst_unwrap_integer(sourcemap[1])); + if (NULL != ast) { + dst_v_push(c->mapbuffer, ast->source_start); + dst_v_push(c->mapbuffer, ast->source_end); } else { dst_v_push(c->mapbuffer, -1); dst_v_push(c->mapbuffer, -1); @@ -343,7 +320,7 @@ void dstc_emit(DstCompiler *c, const Dst *sourcemap, uint32_t instr) { } /* Add a constant to the current scope. Return the index of the constant. */ -static int32_t dstc_const(DstCompiler *c, const Dst *sourcemap, Dst x) { +static int32_t dstc_const(DstCompiler *c, DstAst *ast, Dst x) { DstScope *scope = &dst_v_last(c->scopes); int32_t i, len; /* Get the topmost function scope */ @@ -360,7 +337,7 @@ static int32_t dstc_const(DstCompiler *c, const Dst *sourcemap, Dst x) { } /* Ensure not too many constsants. */ if (len >= 0xFFFF) { - dstc_cerror(c, sourcemap, "too many constants"); + dstc_cerror(c, ast, "too many constants"); return 0; } dst_v_push(scope->consts, x); @@ -368,22 +345,22 @@ static int32_t dstc_const(DstCompiler *c, const Dst *sourcemap, Dst x) { } /* Load a constant into a local slot */ -static void dstc_loadconst(DstCompiler *c, const Dst *sourcemap, Dst k, int32_t dest) { +static void dstc_loadconst(DstCompiler *c, DstAst *ast, Dst k, int32_t dest) { switch (dst_type(k)) { case DST_NIL: - dstc_emit(c, sourcemap, (dest << 8) | DOP_LOAD_NIL); + dstc_emit(c, ast, (dest << 8) | DOP_LOAD_NIL); break; case DST_TRUE: - dstc_emit(c, sourcemap, (dest << 8) | DOP_LOAD_TRUE); + dstc_emit(c, ast, (dest << 8) | DOP_LOAD_TRUE); break; case DST_FALSE: - dstc_emit(c, sourcemap, (dest << 8) | DOP_LOAD_FALSE); + dstc_emit(c, ast, (dest << 8) | DOP_LOAD_FALSE); break; case DST_INTEGER: { int32_t i = dst_unwrap_integer(k); if (i <= INT16_MAX && i >= INT16_MIN) { - dstc_emit(c, sourcemap, + dstc_emit(c, ast, (i << 16) | (dest << 8) | DOP_LOAD_INTEGER); @@ -393,8 +370,8 @@ static void dstc_loadconst(DstCompiler *c, const Dst *sourcemap, Dst k, int32_t } default: { - int32_t cindex = dstc_const(c, sourcemap, k); - dstc_emit(c, sourcemap, + int32_t cindex = dstc_const(c, ast, k); + dstc_emit(c, ast, (cindex << 16) | (dest << 8) | DOP_LOAD_CONSTANT); @@ -407,7 +384,7 @@ static void dstc_loadconst(DstCompiler *c, const Dst *sourcemap, Dst k, int32_t * that can be used in an instruction. */ int32_t dstc_preread( DstCompiler *c, - const Dst *sourcemap, + DstAst *ast, int32_t max, int nth, DstSlot s) { @@ -419,24 +396,24 @@ int32_t dstc_preread( if (s.flags & (DST_SLOT_CONSTANT | DST_SLOT_REF)) { ret = dstc_lslotn(c, 0xFF, nth); - dstc_loadconst(c, sourcemap, s.constant, ret); + dstc_loadconst(c, ast, s.constant, ret); /* If we also are a reference, deref the one element array */ if (s.flags & DST_SLOT_REF) { - dstc_emit(c, sourcemap, + dstc_emit(c, ast, (ret << 16) | (ret << 8) | DOP_GET_INDEX); } } else if (s.envindex > 0 || s.index > max) { ret = dstc_lslotn(c, max, nth); - dstc_emit(c, sourcemap, + dstc_emit(c, ast, ((uint32_t)(s.index) << 24) | ((uint32_t)(s.envindex) << 16) | ((uint32_t)(ret) << 8) | DOP_LOAD_UPVALUE); } else if (s.index > max) { ret = dstc_lslotn(c, max, nth); - dstc_emit(c, sourcemap, + dstc_emit(c, ast, ((uint32_t)(s.index) << 16) | ((uint32_t)(ret) << 8) | DOP_MOVE_NEAR); @@ -473,7 +450,7 @@ int dstc_sequal(DstSlot lhs, DstSlot rhs) { * be writeable (not a literal). */ void dstc_copy( DstCompiler *c, - const Dst *sourcemap, + DstAst *ast, DstSlot dest, DstSlot src) { int writeback = 0; @@ -483,7 +460,7 @@ void dstc_copy( /* Can't write to constants */ if (dest.flags & DST_SLOT_CONSTANT) { - dstc_cerror(c, sourcemap, "cannot write to constant"); + dstc_cerror(c, ast, "cannot write to constant"); return; } @@ -506,21 +483,21 @@ void dstc_copy( /* If dest is a near index, do some optimization */ if (dest.envindex == 0 && dest.index >= 0 && dest.index <= 0xFF) { if (src.flags & DST_SLOT_CONSTANT) { - dstc_loadconst(c, sourcemap, src.constant, dest.index); + dstc_loadconst(c, ast, src.constant, dest.index); } else if (src.flags & DST_SLOT_REF) { - dstc_loadconst(c, sourcemap, src.constant, dest.index); - dstc_emit(c, sourcemap, + dstc_loadconst(c, ast, src.constant, dest.index); + dstc_emit(c, ast, (dest.index << 16) | (dest.index << 8) | DOP_GET_INDEX); } else if (src.envindex > 0) { - dstc_emit(c, sourcemap, + dstc_emit(c, ast, (src.index << 24) | (src.envindex << 16) | (dest.index << 8) | DOP_LOAD_UPVALUE); } else { - dstc_emit(c, sourcemap, + dstc_emit(c, ast, (src.index << 16) | (dest.index << 8) | DOP_MOVE_NEAR); @@ -531,15 +508,15 @@ void dstc_copy( /* Process: src -> srclocal -> destlocal -> dest */ /* src -> srclocal */ - srclocal = dstc_preread(c, sourcemap, 0xFF, 1, src); + srclocal = dstc_preread(c, ast, 0xFF, 1, src); /* Pull down dest (find destlocal) */ if (dest.flags & DST_SLOT_REF) { writeback = 1; destlocal = srclocal; reflocal = dstc_lslotn(c, 0xFF, 2); - dstc_emit(c, sourcemap, - (dstc_const(c, sourcemap, dest.constant) << 16) | + dstc_emit(c, ast, + (dstc_const(c, ast, dest.constant) << 16) | (reflocal << 8) | DOP_LOAD_CONSTANT); } else if (dest.envindex > 0) { @@ -554,7 +531,7 @@ void dstc_copy( /* srclocal -> destlocal */ if (srclocal != destlocal) { - dstc_emit(c, sourcemap, + dstc_emit(c, ast, ((uint32_t)(srclocal) << 16) | ((uint32_t)(destlocal) << 8) | DOP_MOVE_NEAR); @@ -562,18 +539,18 @@ void dstc_copy( /* destlocal -> dest */ if (writeback == 1) { - dstc_emit(c, sourcemap, + dstc_emit(c, ast, (destlocal << 16) | (reflocal << 8) | DOP_PUT_INDEX); } else if (writeback == 2) { - dstc_emit(c, sourcemap, + dstc_emit(c, ast, ((uint32_t)(dest.index) << 24) | ((uint32_t)(dest.envindex) << 16) | ((uint32_t)(destlocal) << 8) | DOP_SET_UPVALUE); } else if (writeback == 3) { - dstc_emit(c, sourcemap, + dstc_emit(c, ast, ((uint32_t)(dest.index) << 16) | ((uint32_t)(destlocal) << 8) | DOP_MOVE_FAR); @@ -587,13 +564,13 @@ void dstc_copy( } /* Generate the return instruction for a slot. */ -DstSlot dstc_return(DstCompiler *c, const Dst *sourcemap, DstSlot s) { +DstSlot dstc_return(DstCompiler *c, DstAst *ast, DstSlot s) { if (!(s.flags & DST_SLOT_RETURNED)) { if (s.flags & DST_SLOT_CONSTANT && dst_checktype(s.constant, DST_NIL)) { - dstc_emit(c, sourcemap, DOP_RETURN_NIL); + dstc_emit(c, ast, DOP_RETURN_NIL); } else { - int32_t ls = dstc_preread(c, sourcemap, 0xFFFF, 1, s); - dstc_emit(c, sourcemap, DOP_RETURN | (ls << 8)); + int32_t ls = dstc_preread(c, ast, 0xFFFF, 1, s); + dstc_emit(c, ast, DOP_RETURN | (ls << 8)); dstc_postread(c, s, ls); } s.flags |= DST_SLOT_RETURNED; @@ -619,32 +596,30 @@ DstSlot dstc_gettarget(DstFopts opts) { } /* Get a bunch of slots for function arguments */ -DstSM *dstc_toslots(DstFopts opts, int32_t start) { - int32_t i, len; +DstSM *dstc_toslots(DstCompiler *c, const Dst *vals, int32_t len) { + int32_t i; DstSM *ret = NULL; - len = dst_length(opts.x); - for (i = start; i < len; i++) { + DstFopts subopts = dstc_fopts_default(c); + for (i = 0; i < len; i++) { DstSM sm; - DstFopts subopts = dstc_getindex(opts, i); - sm.slot = dstc_value(subopts); - sm.map = subopts.sourcemap; + sm.slot = dstc_value(subopts, vals[i]); + sm.map = dst_ast_node(vals[i]); dst_v_push(ret, sm); } return ret; } /* Get a bunch of slots for function arguments */ -DstSM *dstc_toslotskv(DstFopts opts) { +DstSM *dstc_toslotskv(DstCompiler *c, Dst ds) { DstSM *ret = NULL; const DstKV *kv = NULL; - while (NULL != (kv = dst_next(opts.x, kv))) { + DstFopts subopts = dstc_fopts_default(c); + while ((kv = dst_next(ds, kv))) { DstSM km, vm; - DstFopts kopts = dstc_getkey(opts, kv->key); - DstFopts vopts = dstc_getvalue(opts, kv->key); - km.slot = dstc_value(kopts); - km.map = kopts.sourcemap; - vm.slot = dstc_value(vopts); - vm.map = vopts.sourcemap; + km.slot = dstc_value(subopts, kv->key); + km.map = dst_ast_node(kv->key); + vm.slot = dstc_value(subopts, kv->value); + vm.map = dst_ast_node(kv->value); dst_v_push(ret, km); dst_v_push(ret, vm); } @@ -652,15 +627,13 @@ DstSM *dstc_toslotskv(DstFopts opts) { } /* Push slots load via dstc_toslots. */ -void dstc_pushslots(DstFopts opts, DstSM *sms) { - DstCompiler *c = opts.compiler; - const Dst *sm = opts.sourcemap; +void dstc_pushslots(DstCompiler *c, DstAst *ast, DstSM *sms) { int32_t i; for (i = 0; i < dst_v_count(sms) - 2; i += 3) { int32_t ls1 = dstc_preread(c, sms[i].map, 0xFF, 1, sms[i].slot); int32_t ls2 = dstc_preread(c, sms[i + 1].map, 0xFF, 2, sms[i + 1].slot); int32_t ls3 = dstc_preread(c, sms[i + 2].map, 0xFF, 3, sms[i + 2].slot); - dstc_emit(c, sm, + dstc_emit(c, ast, (ls3 << 24) | (ls2 << 16) | (ls1 << 8) | @@ -672,7 +645,7 @@ void dstc_pushslots(DstFopts opts, DstSM *sms) { if (i == dst_v_count(sms) - 2) { int32_t ls1 = dstc_preread(c, sms[i].map, 0xFF, 1, sms[i].slot); int32_t ls2 = dstc_preread(c, sms[i + 1].map, 0xFFFF, 2, sms[i + 1].slot); - dstc_emit(c, sm, + dstc_emit(c, ast, (ls2 << 16) | (ls1 << 8) | DOP_PUSH_2); @@ -680,7 +653,7 @@ void dstc_pushslots(DstFopts opts, DstSM *sms) { dstc_postread(c, sms[i + 1].slot, ls2); } else if (i == dst_v_count(sms) - 1) { int32_t ls1 = dstc_preread(c, sms[i].map, 0xFFFFFF, 1, sms[i].slot); - dstc_emit(c, sm, + dstc_emit(c, ast, (ls1 << 8) | DOP_PUSH); dstc_postread(c, sms[i].slot, ls1); @@ -688,10 +661,10 @@ void dstc_pushslots(DstFopts opts, DstSM *sms) { } /* Free slots loaded via dstc_toslots */ -void dstc_freeslots(DstFopts opts, DstSM *sms) { +void dstc_freeslots(DstCompiler *c, DstSM *sms) { int32_t i; for (i = 0; i < dst_v_count(sms); i++) { - dstc_freeslot(opts.compiler, sms[i].slot); + dstc_freeslot(c, sms[i].slot); } dst_v_free(sms); } @@ -699,108 +672,117 @@ void dstc_freeslots(DstFopts opts, DstSM *sms) { /* Compile some code that will be thrown away. Used to ensure * that dead code is well formed without including it in the final * bytecode. */ -void dstc_throwaway(DstFopts opts) { +void dstc_throwaway(DstFopts opts, Dst x) { DstCompiler *c = opts.compiler; int32_t bufstart = dst_v_count(c->buffer); + int32_t mapbufstart = dst_v_count(c->mapbuffer); dstc_scope(c, DST_SCOPE_UNUSED); - dstc_value(opts); + dstc_value(opts, x); dstc_popscope(c); if (NULL != c->buffer) { dst_v__cnt(c->buffer) = bufstart; if (NULL != c->mapbuffer) - dst_v__cnt(c->mapbuffer) = bufstart; + dst_v__cnt(c->mapbuffer) = mapbufstart; } } /* Compile a call or tailcall instruction */ -static DstSlot dstc_call(DstFopts opts, DstSM *sms, DstSlot fun) { +static DstSlot dstc_call(DstFopts opts, DstAst *ast, DstSM *sms, DstSlot fun) { DstSlot retslot; int32_t localindex; DstCompiler *c = opts.compiler; - const Dst *sm = opts.sourcemap; - dstc_pushslots(opts, sms); - dstc_freeslots(opts, sms); - localindex = dstc_preread(c, sm, 0xFF, 1, fun); + dstc_pushslots(c, ast, sms); + dstc_freeslots(c, sms); + localindex = dstc_preread(c, ast, 0xFF, 1, fun); if (opts.flags & DST_FOPTS_TAIL) { - dstc_emit(c, sm, (localindex << 8) | DOP_TAILCALL); + dstc_emit(c, ast, (localindex << 8) | DOP_TAILCALL); retslot = dstc_cslot(dst_wrap_nil()); retslot.flags = DST_SLOT_RETURNED; } else { retslot = dstc_gettarget(opts); - dstc_emit(c, sm, (localindex << 16) | (retslot.index << 8) | DOP_CALL); + dstc_emit(c, ast, (localindex << 16) | (retslot.index << 8) | DOP_CALL); } dstc_postread(c, fun, localindex); return retslot; } /* Compile a tuple */ -DstSlot dstc_tuple(DstFopts opts) { +DstSlot dstc_tuple(DstFopts opts, DstAst *ast, Dst x) { + Dst headval; DstSlot head; - DstFopts subopts; - const Dst *tup = dst_unwrap_tuple(opts.x); + DstCompiler *c = opts.compiler; + DstFopts subopts = dstc_fopts_default(c); + const Dst *tup = dst_unwrap_tuple(x); /* Empty tuple is tuple literal */ - if (dst_tuple_length(tup) == 0) return dstc_cslot(opts.x); + if (dst_tuple_length(tup) == 0) return dstc_cslot(x); /* Symbols could be specials */ - if (dst_checktype(tup[0], DST_SYMBOL)) { - const DstSpecial *s = dstc_special(dst_unwrap_symbol(tup[0])); + headval = dst_ast_unwrap1(tup[0]); + if (dst_checktype(headval, DST_SYMBOL)) { + const DstSpecial *s = dstc_special(dst_unwrap_symbol(headval)); if (NULL != s) { - return s->compile(opts, dst_tuple_length(tup) - 1, tup + 1); + return s->compile(opts, ast, dst_tuple_length(tup) - 1, tup + 1); } } /* Compile the head of the tuple */ - subopts = dstc_getindex(opts, 0); subopts.flags = DST_FUNCTION | DST_CFUNCTION; - head = dstc_value(subopts); - return dstc_call(opts, dstc_toslots(opts, 1), head); + head = dstc_value(subopts, tup[0]); + return dstc_call(opts, ast, dstc_toslots(c, tup + 1, dst_tuple_length(tup) - 1), head); } -static DstSlot dstc_array(DstFopts opts) { - return dstc_call(opts, dstc_toslots(opts, 0), dstc_cslot(dst_wrap_cfunction(dst_cfun_array))); +static DstSlot dstc_array(DstFopts opts, DstAst *ast, Dst x) { + DstCompiler *c = opts.compiler; + DstArray *a = dst_unwrap_array(x); + return dstc_call(opts, ast, + dstc_toslots(c, a->data, a->count), + dstc_cslot(dst_wrap_cfunction(dst_cfun_array))); } -static DstSlot dstc_tablector(DstFopts opts, DstCFunction cfun) { - return dstc_call(opts, dstc_toslotskv(opts), dstc_cslot(dst_wrap_cfunction(cfun))); +static DstSlot dstc_tablector(DstFopts opts, DstAst *ast, Dst x, DstCFunction cfun) { + DstCompiler *c = opts.compiler; + return dstc_call(opts, ast, dstc_toslotskv(c, x), dstc_cslot(dst_wrap_cfunction(cfun))); } /* Compile a single value */ -DstSlot dstc_value(DstFopts opts) { +DstSlot dstc_value(DstFopts opts, Dst x) { DstSlot ret; + DstAst *ast = dst_ast_node(x); + x = dst_ast_unwrap1(x); if (dstc_iserr(&opts)) { return dstc_cslot(dst_wrap_nil()); } if (opts.compiler->recursion_guard <= 0) { - dstc_cerror(opts.compiler, opts.sourcemap, "recursed too deeply"); + dstc_cerror(opts.compiler, ast, "recursed too deeply"); return dstc_cslot(dst_wrap_nil()); } opts.compiler->recursion_guard--; - switch (dst_type(opts.x)) { + switch (dst_type(x)) { default: - ret = dstc_cslot(opts.x); + ret = dstc_cslot(x); break; case DST_SYMBOL: { - const uint8_t *sym = dst_unwrap_symbol(opts.x); - ret = dstc_resolve(opts.compiler, opts.sourcemap, sym); + const uint8_t *sym = dst_unwrap_symbol(x); + ret = dstc_resolve(opts.compiler, ast, sym); break; } case DST_TUPLE: - ret = dstc_tuple(opts); + ret = dstc_tuple(opts, ast, x); break; case DST_ARRAY: - ret = dstc_array(opts); + ret = dstc_array(opts, ast, x); break; case DST_STRUCT: - ret = dstc_tablector(opts, dst_cfun_struct); + ret = dstc_tablector(opts, ast, x, dst_cfun_struct); break; case DST_TABLE: - ret = dstc_tablector(opts, dst_cfun_table); + ret = dstc_tablector(opts, ast, x, dst_cfun_table); break; } if (opts.flags & DST_FOPTS_TAIL) { - ret = dstc_return(opts.compiler, opts.sourcemap, ret); + ret = dstc_return(opts.compiler, ast, ret); } if (opts.flags & DST_FOPTS_HINT && !dstc_sequal(opts.hint, ret)) { - dstc_copy(opts.compiler, opts.sourcemap, opts.hint, ret); + dstc_copy(opts.compiler, ast, opts.hint, ret); ret = opts.hint; } opts.compiler->recursion_guard++; @@ -899,13 +881,11 @@ DstCompileResult dst_compile(DstCompileOptions opts) { /* Set initial form options */ fopts.compiler = &c; - fopts.sourcemap = opts.sourcemap; fopts.flags = DST_FOPTS_TAIL | DST_SLOTTYPE_ANY; fopts.hint = dstc_cslot(dst_wrap_nil()); - fopts.x = opts.source; /* Compile the value */ - dstc_value(fopts); + dstc_value(fopts, opts.source); if (c.result.status == DST_COMPILE_OK) { c.result.funcdef = dstc_pop_funcdef(&c); @@ -941,11 +921,8 @@ int dst_compile_cfun(DstArgs args) { DstTable *t; if (args.n < 1) return dst_throw(args, "expected at least one argument"); - if (args.n >= 3 && !dst_checktype(args.v[2], DST_TUPLE)) - return dst_throw(args, "expected source map to be tuple"); opts.source = args.v[0]; opts.env = args.n >= 2 ? args.v[1] : dst_stl_env(); - opts.sourcemap = args.n >= 3 ? dst_unwrap_tuple(args.v[2]) : NULL; opts.flags = 0; res = dst_compile(opts); if (res.status == DST_COMPILE_OK) { diff --git a/core/compile.h b/core/compile.h index 5cee3005..4553b560 100644 --- a/core/compile.h +++ b/core/compile.h @@ -56,21 +56,9 @@ struct DstSlot { /* Slot and map pairing */ typedef struct DstSM { DstSlot slot; - const Dst *map; + DstAst *map; } DstSM; -/* Special forms that need support */ -/* cond - * while (continue, break) - * quote - * fn - * def - * var - * varset - * do - * apply (overloaded with normal function) - */ - #define DST_SCOPE_FUNCTION 1 #define DST_SCOPE_ENV 2 #define DST_SCOPE_TOP 4 @@ -128,24 +116,25 @@ struct DstCompiler { /* Options for compiling a single form */ struct DstFopts { DstCompiler *compiler; - Dst x; - const Dst *sourcemap; uint32_t flags; /* bit set of accepted primitive types */ DstSlot hint; }; +/* Get the default form options */ +DstFopts dstc_fopts_default(DstCompiler *c); + /* A grouping of optimizations on a cfunction given certain conditions * on the arguments (such as all constants, or some known types). The appropriate * optimizations should be tried before compiling a normal function call. */ typedef struct DstCFunOptimizer { DstCFunction cfun; - DstSlot (*optimize)(DstFopts opts, int32_t argn, const Dst *argv); + DstSlot (*optimize)(DstFopts opts, DstAst *ast, int32_t argn, const Dst *argv); } DstCFunOptimizer; /* A grouping of a named special and the corresponding compiler fragment */ typedef struct DstSpecial { const char *name; - DstSlot (*compile)(DstFopts opts, int32_t argn, const Dst *argv); + DstSlot (*compile)(DstFopts opts, DstAst *ast, int32_t argn, const Dst *argv); } DstSpecial; /****************************************************/ @@ -180,7 +169,7 @@ void dstc_nameslot(DstCompiler *c, const uint8_t *sym, DstSlot s); * that can be used in an instruction. */ int32_t dstc_preread( DstCompiler *c, - const Dst *sourcemap, + DstAst *ast, int32_t max, int nth, DstSlot s); @@ -191,48 +180,42 @@ void dstc_postread(DstCompiler *c, DstSlot s, int32_t index); /* Move value from one slot to another. Cannot copy to constant slots. */ void dstc_copy( DstCompiler *c, - const Dst *sourcemap, + DstAst *ast, DstSlot dest, DstSlot src); /* Throw away some code after checking that it is well formed. */ -void dstc_throwaway(DstFopts opts); +void dstc_throwaway(DstFopts opts, Dst x); /* Generate the return instruction for a slot. */ -DstSlot dstc_return(DstCompiler *c, const Dst *sourcemap, DstSlot s); +DstSlot dstc_return(DstCompiler *c, DstAst *ast, DstSlot s); /* Get a target slot for emitting an instruction. Will always return * a local slot. */ DstSlot dstc_gettarget(DstFopts opts); /* Get a bunch of slots for function arguments */ -DstSM *dstc_toslots(DstFopts opts, int32_t start); +DstSM *dstc_toslots(DstCompiler *c, const Dst *vals, int32_t len); /* Get a bunch of slots for function arguments */ -DstSM *dstc_toslotskv(DstFopts opts); +DstSM *dstc_toslotskv(DstCompiler *c, Dst ds); /* Push slots load via dstc_toslots. */ -void dstc_pushslots(DstFopts opts, DstSM *sms); +void dstc_pushslots(DstCompiler *c, DstAst *ast, DstSM *sms); /* Free slots loaded via dstc_toslots */ -void dstc_freeslots(DstFopts opts, DstSM *sms); +void dstc_freeslots(DstCompiler *c, DstSM *sms); /* Store an error */ -void dstc_error(DstCompiler *c, const Dst *sourcemap, const uint8_t *m); -void dstc_cerror(DstCompiler *c, const Dst *sourcemap, const char *m); +void dstc_error(DstCompiler *c, DstAst *ast, const uint8_t *m); +void dstc_cerror(DstCompiler *c, DstAst *ast, const char *m); /* Dispatch to correct form compiler */ -DstSlot dstc_value(DstFopts opts); +DstSlot dstc_value(DstFopts opts, Dst x); /* Check if two slots are equal */ int dstc_sequal(DstSlot lhs, DstSlot rhs); -/* Use these to get sub options. They will traverse the source map so - * compiler errors make sense. Then modify the returned options. */ -DstFopts dstc_getindex(DstFopts opts, int32_t index); -DstFopts dstc_getkey(DstFopts opts, Dst key); -DstFopts dstc_getvalue(DstFopts opts, Dst key); - /* Push and pop from the scope stack */ void dstc_scope(DstCompiler *c, int newfn); void dstc_popscope(DstCompiler *c); @@ -246,9 +229,9 @@ DstSlot dstc_cslot(Dst x); void dstc_freeslot(DstCompiler *c, DstSlot slot); /* Search for a symbol */ -DstSlot dstc_resolve(DstCompiler *c, const Dst *sourcemap, const uint8_t *sym); +DstSlot dstc_resolve(DstCompiler *c, DstAst *ast, const uint8_t *sym); /* Emit instructions. */ -void dstc_emit(DstCompiler *c, const Dst *sourcemap, uint32_t instr); +void dstc_emit(DstCompiler *c, DstAst *ast, uint32_t instr); #endif diff --git a/core/compile_specials.c b/core/compile_specials.c index 75f299ec..e9ca2e11 100644 --- a/core/compile_specials.c +++ b/core/compile_specials.c @@ -24,50 +24,49 @@ #include #include "compile.h" #include "gc.h" -#include "sourcemap.h" #include "util.h" -DstSlot dstc_quote(DstFopts opts, int32_t argn, const Dst *argv) { +DstSlot dstc_quote(DstFopts opts, DstAst *ast, int32_t argn, const Dst *argv) { if (argn != 1) { - dstc_cerror(opts.compiler, opts.sourcemap, "expected 1 argument"); + dstc_cerror(opts.compiler, ast, "expected 1 argument"); return dstc_cslot(dst_wrap_nil()); } - return dstc_cslot(argv[0]); + return dstc_cslot(dst_ast_unwrap(argv[0])); } -DstSlot dstc_varset(DstFopts opts, int32_t argn, const Dst *argv) { - DstFopts subopts; +DstSlot dstc_varset(DstFopts opts, DstAst *ast, int32_t argn, const Dst *argv) { + DstFopts subopts = dstc_fopts_default(opts.compiler); DstSlot ret, dest; + Dst head; if (argn != 2) { - dstc_cerror(opts.compiler, opts.sourcemap, "expected 2 arguments"); + dstc_cerror(opts.compiler, ast, "expected 2 arguments"); return dstc_cslot(dst_wrap_nil()); } - if (!dst_checktype(argv[0], DST_SYMBOL)) { - dstc_cerror(opts.compiler, opts.sourcemap, "expected symbol"); + head = dst_ast_unwrap(argv[0]); + if (!dst_checktype(head, DST_SYMBOL)) { + dstc_cerror(opts.compiler, ast, "expected symbol"); return dstc_cslot(dst_wrap_nil()); } - dest = dstc_resolve(opts.compiler, opts.sourcemap, dst_unwrap_symbol(argv[0])); + dest = dstc_resolve(opts.compiler, ast, dst_unwrap_symbol(head)); if (!(dest.flags & DST_SLOT_MUTABLE)) { - dstc_cerror(opts.compiler, opts.sourcemap, "cannot set constant"); + dstc_cerror(opts.compiler, ast, "cannot set constant"); return dstc_cslot(dst_wrap_nil()); } - subopts = dstc_getindex(opts, 2); subopts.flags = DST_FOPTS_HINT; subopts.hint = dest; - ret = dstc_value(subopts); - dstc_copy(opts.compiler, subopts.sourcemap, dest, ret); + ret = dstc_value(subopts, argv[1]); + dstc_copy(opts.compiler, ast, dest, ret); return ret; } /* Add attributes to a global def or var table */ -static void handleattr(DstFopts opts, int32_t argn, const Dst *argv, DstTable *tab) { +static void handleattr(DstCompiler *c, int32_t argn, const Dst *argv, DstTable *tab) { int32_t i; for (i = 1; i < argn - 1; i++) { - Dst attr = argv[i]; - DstFopts subopts = dstc_getindex(opts, i + 1); + Dst attr = dst_ast_unwrap1(argv[i]); switch (dst_type(attr)) { default: - dstc_cerror(opts.compiler, subopts.sourcemap, "could not add meta data to def"); + dstc_cerror(c, dst_ast_node(argv[i]), "could not add metadata to binding"); return; case DST_SYMBOL: dst_table_put(tab, attr, dst_wrap_true()); @@ -79,45 +78,44 @@ static void handleattr(DstFopts opts, int32_t argn, const Dst *argv, DstTable *t } } -DstSlot dstc_var(DstFopts opts, int32_t argn, const Dst *argv) { +DstSlot dstc_var(DstFopts opts, DstAst *ast, int32_t argn, const Dst *argv) { DstCompiler *c = opts.compiler; - DstFopts subopts; + DstFopts subopts = dstc_fopts_default(c); + Dst head; DstSlot ret; if (argn < 2) { - dstc_cerror(opts.compiler, opts.sourcemap, "expected at least 2 arguments"); + dstc_cerror(c, ast, "expected at least 2 arguments"); return dstc_cslot(dst_wrap_nil()); } - if (!dst_checktype(argv[0], DST_SYMBOL)) { - dstc_cerror(opts.compiler, opts.sourcemap, "expected symbol"); + head = dst_ast_unwrap1(argv[0]); + if (!dst_checktype(head, DST_SYMBOL)) { + dstc_cerror(c, dst_ast_node(argv[0]), "expected symbol"); return dstc_cslot(dst_wrap_nil()); } - subopts = dstc_getindex(opts, argn); subopts.flags = opts.flags & ~DST_FOPTS_TAIL; - ret = dstc_value(subopts); + subopts.hint = opts.hint; + ret = dstc_value(subopts, argv[argn - 1]); if (dst_v_last(c->scopes).flags & DST_SCOPE_TOP) { - DstCompiler *c = opts.compiler; - const Dst *sm = opts.sourcemap; DstSlot refslot, refarrayslot; /* Global var, generate var */ DstTable *reftab = dst_table(1); DstArray *ref = dst_array(1); dst_array_push(ref, dst_wrap_nil()); dst_table_put(reftab, dst_csymbolv("ref"), dst_wrap_array(ref)); - handleattr(opts, argn, argv, reftab); - dst_put(opts.compiler->env, argv[0], dst_wrap_table(reftab)); + handleattr(c, argn, argv, reftab); + dst_put(c->env, head, dst_wrap_table(reftab)); refslot = dstc_cslot(dst_wrap_array(ref)); refarrayslot = refslot; refslot.flags |= DST_SLOT_REF | DST_SLOT_NAMED | DST_SLOT_MUTABLE; /* Generate code to set ref */ - int32_t refarrayindex = dstc_preread(c, sm, 0xFF, 1, refarrayslot); - int32_t retindex = dstc_preread(c, sm, 0xFF, 2, ret); - dstc_emit(c, sm, + int32_t refarrayindex = dstc_preread(c, ast, 0xFF, 1, refarrayslot); + int32_t retindex = dstc_preread(c, ast, 0xFF, 2, ret); + dstc_emit(c, ast, (retindex << 16) | (refarrayindex << 8) | DOP_PUT_INDEX); dstc_postread(c, refarrayslot, refarrayindex); dstc_postread(c, ret, retindex); - /*dstc_freeslot(c, refarrayslot);*/ ret = refslot; } else { /* Non root scope, bring to local slot */ @@ -132,30 +130,30 @@ DstSlot dstc_var(DstFopts opts, int32_t argn, const Dst *argv) { localslot.flags = DST_SLOT_NAMED | DST_SLOT_MUTABLE; localslot.envindex = 0; localslot.constant = dst_wrap_nil(); - dstc_copy(opts.compiler, opts.sourcemap, localslot, ret); + dstc_copy(c, ast, localslot, ret); ret = localslot; } - dstc_nameslot(c, dst_unwrap_symbol(argv[0]), ret); + dstc_nameslot(c, dst_unwrap_symbol(head), ret); } return ret; } -DstSlot dstc_def(DstFopts opts, int32_t argn, const Dst *argv) { +DstSlot dstc_def(DstFopts opts, DstAst *ast, int32_t argn, const Dst *argv) { DstCompiler *c = opts.compiler; - const Dst *sm = opts.sourcemap; - DstFopts subopts; + DstFopts subopts = dstc_fopts_default(c); DstSlot ret; + Dst head; if (argn < 2) { - dstc_cerror(opts.compiler, opts.sourcemap, "expected at least 2 arguments"); + dstc_cerror(c, ast, "expected at least 2 arguments"); return dstc_cslot(dst_wrap_nil()); } - if (!dst_checktype(argv[0], DST_SYMBOL)) { - dstc_cerror(opts.compiler, opts.sourcemap, "expected symbol"); + head = dst_ast_unwrap1(argv[0]); + if (!dst_checktype(head, DST_SYMBOL)) { + dstc_cerror(c, dst_ast_node(argv[0]), "expected symbol"); return dstc_cslot(dst_wrap_nil()); } - subopts = dstc_getindex(opts, argn); - subopts.flags &= ~DST_FOPTS_TAIL; - ret = dstc_value(subopts); + subopts.flags = opts.flags & ~DST_FOPTS_TAIL; + ret = dstc_value(subopts, argv[argn - 1]); ret.flags |= DST_SLOT_NAMED; if (dst_v_last(c->scopes).flags & DST_SCOPE_TOP) { DstTable *tab = dst_table(2); @@ -164,14 +162,14 @@ DstSlot dstc_def(DstFopts opts, int32_t argn, const Dst *argv) { DstSlot tabslot = dstc_cslot(dst_wrap_table(tab)); /* Add env entry to env */ - handleattr(opts, argn, argv, tab); - dst_put(c->env, argv[0], dst_wrap_table(tab)); + handleattr(c, argn, argv, tab); + dst_put(c->env, head, dst_wrap_table(tab)); /* Put value in table when evaulated */ - tableindex = dstc_preread(c, sm, 0xFF, 1, tabslot); - valsymindex = dstc_preread(c, sm, 0xFF, 2, valsym); - valueindex = dstc_preread(c, sm, 0xFF, 3, ret); - dstc_emit(c, sm, + tableindex = dstc_preread(c, ast, 0xFF, 1, tabslot); + valsymindex = dstc_preread(c, ast, 0xFF, 2, valsym); + valueindex = dstc_preread(c, ast, 0xFF, 3, ret); + dstc_emit(c, ast, (valueindex << 24) | (valsymindex << 16) | (tableindex << 8) | @@ -181,7 +179,7 @@ DstSlot dstc_def(DstFopts opts, int32_t argn, const Dst *argv) { dstc_postread(c, ret, valueindex); } else { /* Non root scope, simple slot alias */ - dstc_nameslot(c, dst_unwrap_symbol(argv[0]), ret); + dstc_nameslot(c, dst_unwrap_symbol(head), ret); } return ret; } @@ -197,57 +195,45 @@ DstSlot dstc_def(DstFopts opts, int32_t argn, const Dst *argv) { * ... * :done */ -DstSlot dstc_if(DstFopts opts, int32_t argn, const Dst *argv) { +DstSlot dstc_if(DstFopts opts, DstAst *ast, int32_t argn, const Dst *argv) { DstCompiler *c = opts.compiler; - const Dst *sm = opts.sourcemap; int32_t labelr, labeljr, labeld, labeljd, condlocal; - DstFopts leftopts, rightopts, condopts; + DstFopts condopts, bodyopts; DstSlot cond, left, right, target; + Dst truebody, falsebody; const int tail = opts.flags & DST_FOPTS_TAIL; const int drop = opts.flags & DST_FOPTS_DROP; (void) argv; if (argn < 2 || argn > 3) { - dstc_cerror(c, sm, "expected 2 or 3 arguments to if"); + dstc_cerror(c, ast, "expected 2 or 3 arguments to if"); return dstc_cslot(dst_wrap_nil()); } + /* Get the bodies of the if expression */ + truebody = argv[1]; + falsebody = argn > 2 ? argv[2] : dst_wrap_nil(); + /* Get options */ - condopts = dstc_getindex(opts, 1); - leftopts = dstc_getindex(opts, 2); - rightopts = dstc_getindex(opts, 3); - if (argn == 2) rightopts.sourcemap = opts.sourcemap; - if (opts.flags & DST_FOPTS_HINT) { - leftopts.flags |= DST_FOPTS_HINT; - rightopts.flags |= DST_FOPTS_HINT; - } - if (tail) { - leftopts.flags |= DST_FOPTS_TAIL; - rightopts.flags |= DST_FOPTS_TAIL; - } - if (drop) { - leftopts.flags |= DST_FOPTS_DROP; - rightopts.flags |= DST_FOPTS_DROP; - } + condopts = dstc_fopts_default(c); + bodyopts = opts; /* Compile condition */ - cond = dstc_value(condopts); + cond = dstc_value(condopts, argv[0]); /* Check constant condition. */ /* TODO: Use type info for more short circuits */ if ((cond.flags & DST_SLOT_CONSTANT) && !(cond.flags & DST_SLOT_REF)) { - DstFopts goodopts, badopts; - if (dst_truthy(cond.constant)) { - goodopts = leftopts; - badopts = rightopts; - } else { - goodopts = rightopts; - badopts = leftopts; + if (!dst_truthy(cond.constant)) { + /* Swap the true and false bodies */ + Dst temp = falsebody; + falsebody = truebody; + truebody = temp; } dstc_scope(c, 0); - target = dstc_value(goodopts); + target = dstc_value(bodyopts, truebody); dstc_popscope(c); - dstc_throwaway(badopts); + dstc_throwaway(bodyopts, falsebody); return target; } @@ -257,27 +243,27 @@ DstSlot dstc_if(DstFopts opts, int32_t argn, const Dst *argv) { : dstc_cslot(dst_wrap_nil()); /* Compile jump to right */ - condlocal = dstc_preread(c, sm, 0xFF, 1, cond); + condlocal = dstc_preread(c, ast, 0xFF, 1, cond); labeljr = dst_v_count(c->buffer); - dstc_emit(c, sm, DOP_JUMP_IF_NOT | (condlocal << 8)); + dstc_emit(c, ast, DOP_JUMP_IF_NOT | (condlocal << 8)); dstc_postread(c, cond, condlocal); dstc_freeslot(c, cond); /* Condition left body */ dstc_scope(c, 0); - left = dstc_value(leftopts); - if (!drop && !tail) dstc_copy(c, sm, target, left); + left = dstc_value(bodyopts, truebody); + if (!drop && !tail) dstc_copy(c, ast, target, left); dstc_popscope(c); /* Compile jump to done */ labeljd = dst_v_count(c->buffer); - if (!tail) dstc_emit(c, sm, DOP_JUMP); + if (!tail) dstc_emit(c, ast, DOP_JUMP); /* Compile right body */ labelr = dst_v_count(c->buffer); dstc_scope(c, 0); - right = dstc_value(rightopts); - if (!drop && !tail) dstc_copy(c, sm, target, right); + right = dstc_value(bodyopts, falsebody); + if (!drop && !tail) dstc_copy(c, ast, target, right); dstc_popscope(c); /* Write jumps - only add jump lengths if jump actually emitted */ @@ -291,44 +277,44 @@ DstSlot dstc_if(DstFopts opts, int32_t argn, const Dst *argv) { /* Compile a do form. Do forms execute their body sequentially and * evaluate to the last expression in the body. */ -DstSlot dstc_do(DstFopts opts, int32_t argn, const Dst *argv) { +DstSlot dstc_do(DstFopts opts, DstAst *ast, int32_t argn, const Dst *argv) { int32_t i; DstSlot ret; - dstc_scope(opts.compiler, 0); - (void) argv; + DstCompiler *c = opts.compiler; + DstFopts subopts = dstc_fopts_default(c); + (void) ast; + dstc_scope(c, 0); for (i = 0; i < argn; i++) { - DstFopts subopts = dstc_getindex(opts, i + 1); if (i != argn - 1) { subopts.flags = DST_FOPTS_DROP; } else if (opts.flags & DST_FOPTS_TAIL) { subopts.flags = DST_FOPTS_TAIL; } - ret = dstc_value(subopts); + ret = dstc_value(subopts, argv[i]); if (i != argn - 1) { - dstc_freeslot(opts.compiler, ret); + dstc_freeslot(c, ret); } } - dstc_popscope_keepslot(opts.compiler, ret); + dstc_popscope_keepslot(c, ret); return ret; } -DstSlot dstc_transfer(DstFopts opts, int32_t argn, const Dst *argv) { +DstSlot dstc_transfer(DstFopts opts, DstAst *ast, int32_t argn, const Dst *argv) { DstCompiler *c = opts.compiler; - const Dst *sm = opts.sourcemap; + DstFopts subopts = dstc_fopts_default(c);; DstSlot dest, fib, val; int32_t destindex, fibindex, valindex; - (void) argv; if (argn > 2) { - dstc_cerror(c, sm, "expected no more than 2 arguments"); + dstc_cerror(c, ast, "expected no more than 2 arguments"); return dstc_cslot(dst_wrap_nil()); } dest = dstc_gettarget(opts); - fib = (argn > 0) ? dstc_value(dstc_getindex(opts, 1)) : dstc_cslot(dst_wrap_nil()); - val = (argn > 1) ? dstc_value(dstc_getindex(opts, 2)) : dstc_cslot(dst_wrap_nil()); - destindex = dstc_preread(c, sm, 0xFF, 1, dest); - fibindex = dstc_preread(c, sm, 0xFF, 2, fib); - valindex = dstc_preread(c, sm, 0xFF, 3, val); - dstc_emit(c, sm, + fib = (argn > 0) ? dstc_value(subopts, argv[0]) : dstc_cslot(dst_wrap_nil()); + val = (argn > 1) ? dstc_value(subopts, argv[1]) : dstc_cslot(dst_wrap_nil()); + destindex = dstc_preread(c, ast, 0xFF, 1, dest); + fibindex = dstc_preread(c, ast, 0xFF, 2, fib); + valindex = dstc_preread(c, ast, 0xFF, 3, val); + dstc_emit(c, ast, (valindex << 24) | (fibindex << 16) | (destindex << 8) | @@ -350,23 +336,22 @@ DstSlot dstc_transfer(DstFopts opts, int32_t argn, const Dst *argv) { * jump :whiletop * :done */ -DstSlot dstc_while(DstFopts opts, int32_t argn, const Dst *argv) { +DstSlot dstc_while(DstFopts opts, DstAst *ast, int32_t argn, const Dst *argv) { DstCompiler *c = opts.compiler; - const Dst *sm = opts.sourcemap; DstSlot cond; + DstFopts subopts = dstc_fopts_default(c); int32_t condlocal, labelwt, labeld, labeljt, labelc, i; int infinite = 0; - (void) argv; if (argn < 2) { - dstc_cerror(c, sm, "expected at least 2 arguments"); + dstc_cerror(c, ast, "expected at least 2 arguments"); return dstc_cslot(dst_wrap_nil()); } labelwt = dst_v_count(c->buffer); /* Compile condition */ - cond = dstc_value(dstc_getindex(opts, 1)); + cond = dstc_value(subopts, argv[0]); /* Check for constant condition */ if (cond.flags & DST_SLOT_CONSTANT) { @@ -382,22 +367,21 @@ DstSlot dstc_while(DstFopts opts, int32_t argn, const Dst *argv) { /* Infinite loop does not need to check condition */ if (!infinite) { - condlocal = dstc_preread(c, sm, 0xFF, 1, cond); + condlocal = dstc_preread(c, ast, 0xFF, 1, cond); labelc = dst_v_count(c->buffer); - dstc_emit(c, sm, DOP_JUMP_IF_NOT | (condlocal << 8)); + dstc_emit(c, ast, DOP_JUMP_IF_NOT | (condlocal << 8)); dstc_postread(c, cond, condlocal); } /* Compile body */ for (i = 1; i < argn; i++) { - DstFopts subopts = dstc_getindex(opts, i + 1); subopts.flags = DST_FOPTS_DROP; - dstc_freeslot(c, dstc_value(subopts)); + dstc_freeslot(c, dstc_value(subopts, argv[i])); } /* Compile jump to whiletop */ labeljt = dst_v_count(c->buffer); - dstc_emit(c, sm, DOP_JUMP); + dstc_emit(c, ast, DOP_JUMP); /* Calculate jumps */ labeld = dst_v_count(c->buffer); @@ -405,7 +389,7 @@ DstSlot dstc_while(DstFopts opts, int32_t argn, const Dst *argv) { c->buffer[labeljt] |= (labelwt - labeljt) << 8; /* Pop scope and return nil slot */ - dstc_popscope(opts.compiler); + dstc_popscope(c); return dstc_cslot(dst_wrap_nil()); } @@ -423,18 +407,18 @@ static int32_t dstc_addfuncdef(DstCompiler *c, DstFuncDef *def) { return dst_v_count(scope->defs) - 1; } -DstSlot dstc_fn(DstFopts opts, int32_t argn, const Dst *argv) { +DstSlot dstc_fn(DstFopts opts, DstAst *ast, int32_t argn, const Dst *argv) { DstCompiler *c = opts.compiler; - const Dst *sm = opts.sourcemap; DstFuncDef *def; DstSlot ret; + Dst head, paramv; int32_t paramcount, argi, parami, arity, localslot, defindex; + DstFopts subopts = dstc_fopts_default(c); const Dst *params; - const Dst *psm; int varargs = 0; if (argn < 2) { - dstc_cerror(c, sm, "expected at least 2 arguments to function literal"); + dstc_cerror(c, ast, "expected at least 2 arguments to function literal"); return dstc_cslot(dst_wrap_nil()); } @@ -444,22 +428,23 @@ DstSlot dstc_fn(DstFopts opts, int32_t argn, const Dst *argv) { /* Read function parameters */ parami = 0; arity = 0; - if (dst_checktype(argv[0], DST_SYMBOL)) parami = 1; + head = dst_ast_unwrap(argv[0]); + if (dst_checktype(head, DST_SYMBOL)) parami = 1; if (parami >= argn) { - dstc_cerror(c, sm, "expected function parameters"); + dstc_cerror(c, dst_ast_node(argv[0]), "expected function parameters"); return dstc_cslot(dst_wrap_nil()); } - if (dst_seq_view(argv[parami], ¶ms, ¶mcount)) { - psm = dst_sourcemap_index(sm, parami + 1); + paramv = dst_ast_unwrap(argv[parami]); + if (dst_seq_view(paramv, ¶ms, ¶mcount)) { int32_t i; for (i = 0; i < paramcount; i++) { - const Dst *psmi = dst_sourcemap_index(psm, i); - if (dst_checktype(params[i], DST_SYMBOL)) { + Dst param = dst_ast_unwrap(params[i]); + if (dst_checktype(param, DST_SYMBOL)) { DstSlot slot; /* Check for varargs */ - if (0 == dst_cstrcmp(dst_unwrap_symbol(params[i]), "&")) { + if (0 == dst_cstrcmp(dst_unwrap_symbol(param), "&")) { if (i != paramcount - 2) { - dstc_cerror(c, psmi, "variable argument symbol in unexpected location"); + dstc_cerror(c, dst_ast_node(params[i]), "variable argument symbol in unexpected location"); return dstc_cslot(dst_wrap_nil()); } varargs = 1; @@ -470,24 +455,23 @@ DstSlot dstc_fn(DstFopts opts, int32_t argn, const Dst *argv) { slot.envindex = 0; slot.constant = dst_wrap_nil(); slot.index = dstc_lsloti(c); - dstc_nameslot(c, dst_unwrap_symbol(params[i]), slot); + dstc_nameslot(c, dst_unwrap_symbol(param), slot); arity++; } else { - dstc_cerror(c, psmi, "expected symbol as function parameter"); + dstc_cerror(c, dst_ast_node(params[i]), "expected symbol as function parameter"); return dstc_cslot(dst_wrap_nil()); } } } else { - dstc_cerror(c, sm, "expected function parameters"); + dstc_cerror(c, ast, "expected function parameters"); return dstc_cslot(dst_wrap_nil()); } /* Compile function body */ for (argi = parami + 1; argi < argn; argi++) { DstSlot s; - DstFopts subopts = dstc_getindex(opts, argi + 1); subopts.flags = argi == (argn - 1) ? DST_FOPTS_TAIL : DST_FOPTS_DROP; - s = dstc_value(subopts); + s = dstc_value(subopts, argv[argi]); dstc_freeslot(c, s); } @@ -504,13 +488,13 @@ DstSlot dstc_fn(DstFopts opts, int32_t argn, const Dst *argv) { ret = dstc_gettarget(opts); localslot = ret.index > 0xF0 ? 0xF1 : ret.index; - dstc_emit(c, sm, + dstc_emit(c, ast, (defindex << 16) | (localslot << 8) | DOP_CLOSURE); if (ret.index != localslot) { - dstc_emit(c, sm, + dstc_emit(c, ast, (ret.index << 16) | (localslot << 8) | DOP_MOVE_FAR); diff --git a/core/context.c b/core/context.c new file mode 100644 index 00000000..98de628a --- /dev/null +++ b/core/context.c @@ -0,0 +1,183 @@ +/* +* Copyright (c) 2017 Calvin Rose +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to +* deal in the Software without restriction, including without limitation the +* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +* sell copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +* IN THE SOFTWARE. +*/ + +#include + +/*static void deinit_file(DstContext *c) {*/ + /*FILE *f = (FILE *) (c->user);*/ + /*fclose(f);*/ +/*}*/ + +/* Read input for a repl */ +static void replread(DstContext *c) { + if (c->buffer.count == 0) + printf("> "); + else + printf(">> "); + for (;;) { + int x = fgetc(stdin); + if (x == EOF) { + dst_buffer_push_u8(&c->buffer, '\n'); + printf("\n"); + break; + } + dst_buffer_push_u8(&c->buffer, x); + if (x == '\n') break; + } +} + +/* Output for a repl */ +static void replonvalue(DstContext *c, Dst value) { + (void) c; + dst_puts(dst_formatc("%v\n", value)); + if (dst_checktype(c->env, DST_TABLE)) + dst_module_def(dst_unwrap_table(c->env), "_", dst_wrap_nil()); +} + +/* Handle errors on repl */ +static void replerror(DstContext *c, DstContextErrorType type, Dst err, size_t start, size_t end) { + const char *errtype; + (void) c; + (void) start; + (void) end; + switch (type) { + case DST_CONTEXT_ERROR_PARSE: + errtype = "parse"; + break; + case DST_CONTEXT_ERROR_RUNTIME: + errtype = "runtime"; + break; + case DST_CONTEXT_ERROR_COMPILE: + errtype = "compile"; + break; + } + dst_puts(dst_formatc("%s error: %v\n", errtype, err)); +} + +void dst_context_repl(DstContext *c, Dst env) { + dst_buffer_init(&c->buffer, 1024); + c->env = env; + dst_gcroot(env); + c->flushed_bytes = 0; + c->user = NULL; + if (dst_checktype(c->env, DST_TABLE)) + dst_module_def(dst_unwrap_table(c->env), "_", dst_wrap_nil()); + + c->read_chunk = replread; + c->on_error = replerror; + c->on_value = replonvalue; +} + +/* Remove everything in the current buffer */ +static void flushcontext(DstContext *c) { + c->flushed_bytes += c->buffer.count; + c->buffer.count = 0; +} + +/* Shift bytes in buffer down */ +/* TODO Make parser online so there is no need to + * do too much book keeping with the buffer. */ +static void bshift(DstContext *c, int32_t delta) { + c->buffer.count -= delta; + if (delta) { + memmove(c->buffer.data, c->buffer.data + delta, c->buffer.count); + } +} + +/* Start a context */ +int dst_context_run(DstContext *c) { + int done = 0; + int flags = 0; + while (!done) { + DstCompileResult cres; + DstCompileOptions opts; + DstParseResult res = dst_parse(c->buffer.data, c->buffer.count); + switch (res.status) { + case DST_PARSE_NODATA: + flushcontext(c); + case DST_PARSE_UNEXPECTED_EOS: + { + int32_t countbefore = c->buffer.count; + c->read_chunk(c); + /* If the last chunk was empty, finish */ + if (c->buffer.count == countbefore) { + done = 1; + flags |= 1 << DST_CONTEXT_ERROR_PARSE; + if (c->on_error) { + c->on_error(c, DST_CONTEXT_ERROR_PARSE, + dst_wrap_string(res.error), + c->flushed_bytes + res.bytes_read, + c->flushed_bytes + res.bytes_read); + } + } + break; + } + case DST_PARSE_ERROR: + if (c->on_error) { + flags |= 1 << DST_CONTEXT_ERROR_PARSE; + c->on_error(c, DST_CONTEXT_ERROR_PARSE, + dst_wrap_string(res.error), + c->flushed_bytes + res.bytes_read, + c->flushed_bytes + res.bytes_read); + } + bshift(c, res.bytes_read); + break; + case DST_PARSE_OK: + { + opts.source = res.value; + opts.flags = 0; + opts.env = c->env; + cres = dst_compile(opts); + if (cres.status == DST_COMPILE_OK) { + DstFunction *f = dst_compile_func(cres); + Dst ret; + if (dst_run(dst_wrap_function(f), &ret)) { + /* Get location from stacktrace */ + if (c->on_error) { + flags |= 1 << DST_CONTEXT_ERROR_RUNTIME; + c->on_error(c, DST_CONTEXT_ERROR_RUNTIME, ret, -1, -1); + } + } else { + if (c->on_value) { + c->on_value(c, ret); + } + } + } else { + if (c->on_error) { + flags |= 1 << DST_CONTEXT_ERROR_COMPILE; + c->on_error(c, DST_CONTEXT_ERROR_COMPILE, + dst_wrap_string(cres.error), + c->flushed_bytes + cres.error_start, + c->flushed_bytes + cres.error_end); + } + } + bshift(c, res.bytes_read); + } + break; + } + } + dst_buffer_deinit(&c->buffer); + if (c->deinit) c->deinit(c); + dst_gcunroot(c->env); + + return flags; +} diff --git a/core/gc.c b/core/gc.c index d6b83f20..94911c20 100644 --- a/core/gc.c +++ b/core/gc.c @@ -73,7 +73,12 @@ static void dst_mark_buffer(DstBuffer *buffer) { } static void dst_mark_abstract(void *adata) { + if (dst_gc_reachable(dst_abstract_header(adata))) + return; dst_gc_mark(dst_abstract_header(adata)); + if (dst_abstract_header(adata)->type->gcmark) { + dst_abstract_header(adata)->type->gcmark(adata, dst_abstract_size(adata)); + } } /* Mark a bunch of items in memory */ diff --git a/core/io.c b/core/io.c index ea9ce39d..2ba4d613 100644 --- a/core/io.c +++ b/core/io.c @@ -41,7 +41,8 @@ static int dst_io_gc(void *p, size_t len); DstAbstractType dst_io_filetype = { "io.file", - dst_io_gc + dst_io_gc, + NULL }; /* Check argupments to fopen */ diff --git a/core/parse.c b/core/parse.c index cc827f88..bac5cfa2 100644 --- a/core/parse.c +++ b/core/parse.c @@ -155,40 +155,15 @@ static int to_hex(uint8_t c) { } } -/* Make source mapping for atom (non recursive structure) */ -static Dst atom_map(int32_t start, int32_t end) { - Dst *t = dst_tuple_begin(2); - t[0] = dst_wrap_integer(start); - t[1] = dst_wrap_integer(end); - return dst_wrap_tuple(dst_tuple_end(t)); -} - -/* Create mappingd for recursive data structure */ -static Dst ds_map(int32_t start, int32_t end, Dst submap) { - Dst *t = dst_tuple_begin(3); - t[0] = dst_wrap_integer(start); - t[1] = dst_wrap_integer(end); - t[2] = submap; - return dst_wrap_tuple(dst_tuple_end(t)); -} - -/* Create a sourcemapping for a key value pair */ -static Dst kv_map(Dst k, Dst v) { - Dst *t = dst_tuple_begin(2); - t[0] = k; - t[1] = v; - return dst_wrap_tuple(dst_tuple_end(t)); -} - typedef struct { DstArray stack; - DstArray mapstack; const uint8_t *srcstart; const uint8_t *end; const char *errmsg; DstParseStatus status; } ParseArgs; + /* Entry point of the recursive descent parser */ static const uint8_t *parse_recur( ParseArgs *args, @@ -199,7 +174,6 @@ static const uint8_t *parse_recur( const uint8_t *mapstart; int32_t qcount = 0; Dst ret; - Dst submapping; /* Prevent stack overflow */ if (recur == 0) goto too_much_recur; @@ -226,7 +200,6 @@ static const uint8_t *parse_recur( /* Open mapping */ mapstart = src; - submapping = dst_wrap_nil(); /* Detect token type based on first character */ switch (*src) { @@ -372,27 +345,20 @@ static const uint8_t *parse_recur( case ')': { Dst *tup = dst_tuple_begin(n); - Dst *subtup = dst_tuple_begin(n); for (i = n; i > 0; i--) { tup[i - 1] = dst_array_pop(&args->stack); - subtup[i - 1] = dst_array_pop(&args->mapstack); } ret = dst_wrap_tuple(dst_tuple_end(tup)); - submapping = dst_wrap_tuple(dst_tuple_end(subtup)); break; } case ']': { DstArray *arr = dst_array(n); - DstArray *subarr = dst_array(n); for (i = n; i > 0; i--) { arr->data[i - 1] = dst_array_pop(&args->stack); - subarr->data[i - 1] = dst_array_pop(&args->mapstack); } arr->count = n; - subarr->count = n; ret = dst_wrap_array(arr); - submapping = dst_wrap_array(subarr); break; } case '}': @@ -404,32 +370,20 @@ static const uint8_t *parse_recur( } if (istable) { DstTable *t = dst_table(n); - DstTable *subt = dst_table(n); for (i = n; i > 0; i -= 2) { Dst val = dst_array_pop(&args->stack); Dst key = dst_array_pop(&args->stack); - Dst subval = dst_array_pop(&args->mapstack); - Dst subkey = dst_array_pop(&args->mapstack); - dst_table_put(t, key, val); - dst_table_put(subt, key, kv_map(subkey, subval)); } ret = dst_wrap_table(t); - submapping = dst_wrap_table(subt); } else { DstKV *st = dst_struct_begin(n >> 1); - DstKV *subst = dst_struct_begin(n >> 1); for (i = n; i > 0; i -= 2) { Dst val = dst_array_pop(&args->stack); Dst key = dst_array_pop(&args->stack); - Dst subval = dst_array_pop(&args->mapstack); - Dst subkey = dst_array_pop(&args->mapstack); - dst_struct_put(st, key, val); - dst_struct_put(subst, key, kv_map(subkey, subval)); } ret = dst_wrap_struct(dst_struct_end(st)); - submapping = dst_wrap_struct(dst_struct_end(subst)); } break; } @@ -438,35 +392,15 @@ static const uint8_t *parse_recur( } } - /* Push source mapping */ - if (dst_checktype(submapping, DST_NIL)) { - /* We just parsed an atom */ - dst_array_push(&args->mapstack, atom_map( - mapstart - args->srcstart, - src - args->srcstart)); - } else { - /* We just parsed a recursive data structure */ - dst_array_push(&args->mapstack, ds_map( - mapstart - args->srcstart, - src - args->srcstart, - submapping)); - } - /* Quote the returned value qcount times */ while (qcount--) { - int32_t start = mapstart - args->srcstart; - int32_t end = src - args->srcstart; - Dst sourcemap = dst_array_pop(&args->mapstack); - Dst* tup = dst_tuple_begin(2); - tup[0] = atom_map(start, end); - tup[1] = sourcemap; + ret = dst_ast_wrap(ret, mapstart - args->srcstart, src - args->srcstart); ret = quote(ret); - dst_array_push(&args->mapstack, ds_map( - start, - end, - dst_wrap_tuple(dst_tuple_end(tup)))); } + /* Ast wrap */ + ret = dst_ast_wrap(ret, mapstart - args->srcstart, src - args->srcstart); + /* Push the result to the stack */ dst_array_push(&args->stack, ret); @@ -537,8 +471,6 @@ DstParseResult dst_parse(const uint8_t *src, int32_t len) { args.end = src + len; args.errmsg = NULL; - dst_array_init(&args.mapstack, 10); - newsrc = parse_recur(&args, src, DST_RECURSION_GUARD); res.status = args.status; res.bytes_read = (int32_t) (newsrc - src); @@ -546,15 +478,12 @@ DstParseResult dst_parse(const uint8_t *src, int32_t len) { if (args.errmsg) { res.error = dst_cstring(args.errmsg); res.value = dst_wrap_nil(); - res.map = NULL; } else { res.value = dst_array_pop(&args.stack); res.error = NULL; - res.map = dst_unwrap_tuple(dst_array_pop(&args.mapstack)); } dst_array_deinit(&args.stack); - dst_array_deinit(&args.mapstack); return res; } @@ -592,7 +521,6 @@ int dst_parse_cfun(DstArgs args) { break; } dst_table_put(t, dst_cstringv("status"), dst_cstringv(status_string)); - if (res.status == DST_PARSE_OK) dst_table_put(t, dst_cstringv("map"), dst_wrap_tuple(res.map)); if (res.status == DST_PARSE_OK) dst_table_put(t, dst_cstringv("value"), res.value); if (res.status == DST_PARSE_ERROR) dst_table_put(t, dst_cstringv("error"), dst_wrap_string(res.error)); dst_table_put(t, dst_cstringv("bytes-read"), dst_wrap_integer(res.bytes_read)); diff --git a/core/sourcemap.c b/core/sourcemap.c deleted file mode 100644 index 1e77929a..00000000 --- a/core/sourcemap.c +++ /dev/null @@ -1,77 +0,0 @@ -/* -* Copyright (c) 2017 Calvin Rose -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to -* deal in the Software without restriction, including without limitation the -* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -* sell copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in -* all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -* IN THE SOFTWARE. -*/ - -#include -#include "sourcemap.h" - -/* Get the sub source map by indexing a value. Used to traverse - * into arrays and tuples */ -const Dst *dst_sourcemap_index(const Dst *map, int32_t index) { - if (NULL != map && dst_tuple_length(map) >= 3) { - const Dst *seq; - int32_t len; - if (dst_seq_view(map[2], &seq, &len)) { - if (index >= 0 && index < len) { - if (dst_checktype(seq[index], DST_TUPLE)) { - const Dst *ret = dst_unwrap_tuple(seq[index]); - if (dst_tuple_length(ret) >= 2 && - dst_checktype(ret[0], DST_INTEGER) && - dst_checktype(ret[1], DST_INTEGER)) { - return ret; - } - } - } - } - } - return NULL; -} - -/* Traverse into tables and structs */ -static const Dst *dst_sourcemap_kv(const Dst *map, Dst key, int kv) { - if (NULL != map && dst_tuple_length(map) >= 3) { - Dst kvpair = dst_get(map[2], key); - if (dst_checktype(kvpair, DST_TUPLE)) { - const Dst *kvtup = dst_unwrap_tuple(kvpair); - if (dst_tuple_length(kvtup) >= 2) { - if (dst_checktype(kvtup[kv], DST_TUPLE)) { - const Dst *ret = dst_unwrap_tuple(kvtup[kv]); - if (dst_tuple_length(ret) >= 2 && - dst_checktype(ret[0], DST_INTEGER) && - dst_checktype(ret[1], DST_INTEGER)) { - return ret; - } - } - } - } - } - return NULL; -} - -/* Traverse into a key of a table or struct */ -const Dst *dst_sourcemap_key(const Dst *map, Dst key) { - return dst_sourcemap_kv(map, key, 0); -} - -/* Traverse into a value of a table or struct */ -const Dst *dst_sourcemap_value(const Dst *map, Dst key) { - return dst_sourcemap_kv(map, key, 1); -} diff --git a/core/sourcemap.h b/core/sourcemap.h deleted file mode 100644 index 17b91e6c..00000000 --- a/core/sourcemap.h +++ /dev/null @@ -1,44 +0,0 @@ -/* -* Copyright (c) 2017 Calvin Rose -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to -* deal in the Software without restriction, including without limitation the -* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -* sell copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in -* all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -* IN THE SOFTWARE. -*/ - -#ifndef DST_SOURCEMAP_H_defined -#define DST_SOURCEMAP_H_defined - -#include - -/* Get the sub source map by indexing a value. Used to traverse - * into arrays and tuples */ -const Dst *dst_sourcemap_index(const Dst *map, int32_t index); - -/* Traverse into a key of a table or struct */ -const Dst *dst_sourcemap_key(const Dst *map, Dst key); - -/* Traverse into a value of a table or struct */ -const Dst *dst_sourcemap_value(const Dst *map, Dst key); - -/* Try to rebuild a source map from given another map */ -const Dst *dst_sourcemap_remap( - const Dst *oldmap, - Dst oldsource, - Dst newsource); - -#endif diff --git a/include/dst/dst.h b/include/dst/dst.h index 6207e5b7..13119363 100644 --- a/include/dst/dst.h +++ b/include/dst/dst.h @@ -170,6 +170,12 @@ int32_t dst_capacity(Dst x); Dst dst_getindex(Dst ds, int32_t index); void dst_setindex(Dst ds, Dst value, int32_t index); +/* AST */ +Dst dst_ast_wrap(Dst x, int32_t start, int32_t end); +DstAst *dst_ast_node(Dst x); +Dst dst_ast_unwrap1(Dst x); +Dst dst_ast_unwrap(Dst x); + /* Parsing */ DstParseResult dst_parse(const uint8_t *src, int32_t len); DstParseResult dst_parsec(const char *src); @@ -194,6 +200,10 @@ DstTable *dst_get_module(DstArgs args); void dst_module_def(DstTable *module, const char *name, Dst val); void dst_module_var(DstTable *module, const char *name, Dst val); +/* Context functions */ +void dst_context_repl(DstContext *c, Dst env); +int dst_context_run(DstContext *c); + /* C Function helpers */ #define dst_throw(a, e) (*((a).ret) = dst_cstringv(e), 1) #define dst_throwv(a, v) (*((a).ret) = (v), 1) diff --git a/include/dst/dsttypes.h b/include/dst/dsttypes.h index cfcb7114..a760ec04 100644 --- a/include/dst/dsttypes.h +++ b/include/dst/dsttypes.h @@ -47,6 +47,8 @@ typedef struct DstKV DstKV; typedef struct DstStackFrame DstStackFrame; typedef struct DstAbstractType DstAbstractType; typedef struct DstArgs DstArgs; +typedef struct DstAst DstAst; +typedef struct DstContext DstContext; typedef int (*DstCFunction)(DstArgs args); typedef enum DstAssembleStatus DstAssembleStatus; @@ -413,6 +415,7 @@ struct DstFunction { struct DstAbstractType { const char *name; int (*gc)(void *data, size_t len); + int (*gcmark)(void *data, size_t len); }; /* Contains information about userdata */ @@ -454,11 +457,19 @@ struct DstCompileResult { struct DstCompileOptions { uint32_t flags; - const Dst *sourcemap; Dst source; Dst env; }; +/* ASTs are simple wrappers around values. They contain information about sourcemapping + * and other meta data. Possibly types? They are used mainly during compilation and parsing */ +struct DstAst { + Dst value; + int32_t source_start; + int32_t source_end; + int flags; +}; + /* Parse structs */ enum DstParseStatus { DST_PARSE_OK, @@ -470,9 +481,28 @@ enum DstParseStatus { struct DstParseResult { Dst value; const uint8_t *error; - const Dst *map; int32_t bytes_read; DstParseStatus status; }; +typedef enum { + DST_CONTEXT_ERROR_PARSE, + DST_CONTEXT_ERROR_COMPILE, + DST_CONTEXT_ERROR_RUNTIME +} DstContextErrorType; + +/* Evaluation context. Encapsulates parsing and compiling for easier integration + * with client programs. */ +struct DstContext { + Dst env; + DstBuffer buffer; + size_t flushed_bytes; + void *user; + + void (*read_chunk)(DstContext *self); + void (*on_error)(DstContext *self, DstContextErrorType type, Dst err, size_t start, size_t end); + void (*on_value)(DstContext *self, Dst value); + void (*deinit)(DstContext *self); +}; + #endif /* DST_TYPES_H_defined */