diff --git a/3 b/3 deleted file mode 100644 index 01a78d5b..00000000 --- a/3 +++ /dev/null @@ -1,230 +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_COMPILE_H -#define DST_COMPILE_H - -#include -#include - -/* Compiler typedefs */ -typedef struct DstCompiler DstCompiler; -typedef struct FormOptions FormOptions; -typedef struct SlotTracker SlotTracker; -typedef struct DstScope DstScope; -typedef struct DstCFunctionOptimizer DstCFunctionOptimizer; - -#define DST_SLOT_CONSTANT 0x10000 -#define DST_SLOT_NAMED 0x20000 -#define DST_SLOT_RETURNED 0x40000 -#define DST_SLOT_NIL 0x80000 -#define DST_SLOT_MUTABLE 0x100000 - -#define DST_SLOTTYPE_ANY 0xFFFF - -/* A stack slot */ -struct DstSlot { - int32_t index; - int32_t envindex; /* 0 is local, positive number is an upvalue */ - uint32_t flags; - DstValue constant; /* If the slot has a constant value */ -} - -/* Most forms that return a constant will not generate any bytecode */ - -/* Special forms that need support */ -/* cond - * while (continue, break) - * quote - * fn - * def - * var - * varset - * do - */ - -#define DST_OPTIMIZER_CONSTANTS 0x10000 -#define DST_OPTIMIZER_BYTECODE 0x20000 -#define DST_OPTIMIZER_PARTIAL_CONSTANTS 0x40000 -#define DST_OPTIMIZER_SYSCALL 0x80000 - -/* A grouping of optimization 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. */ -struct DstCFunctionOptimizer { - uint32_t flags; /* Indicate what kind of optimizations can be performed. */ - /*Also what kind of types can be returned*/ - int32_t syscall; -} - -#define DST_SCOPE_FUNCTION 1 -#define DST_SCOPE_LASTSLOT 2 -#define DST_SCOPE_FIRSTSLOT 4 -#define DST_SCOPE_ENV - -/* A lexical scope during compilation */ -struct DstScope { - DstArray constants; /* Constants for the funcdef */ - DstTable symbols; /* Map symbols -> Slot inidices */ - - /* Hold all slots in use. Data structures that store - * slots should link them to this datatstructure */ - DstSlot *slots; - int32_t slotcount; - int32_t slotcap; - - /* A vector of freed slots. */ - int32_t *freeslots; - int32_t freeslotcount; - int32_t freeslotcap; - - int32_t lastslot; - int32_t nextslot; - - /* Referenced closure environemts. The values at each index correspond - * to which index to get the environment from in the parent. The enironment - * that corresponds to the direct parent's stack will always have value 0. */ - int32_t *envs; - int32_t envcount; - int32_t envcap; - - int32_t buffer_offset; /* Where the bytecode for this scope begins */ - - uint32_t flags; -} - -/* Compilation state */ -struct DstCompiler { - jump_buf on_error; - int32_t scopecount; - int32_t scopecap; - DstScope *scopes; - DstBuffer buffer; - DstBuffer mapbuffer; - int32_t error_start; - int32_t error_end; - DstValue error; - int recursion_guard; -}; - -#define DST_FOPTS_TAIL 0x10000 -#define DST_FOPTS_FORCESLOT 0x20000 - -/* Compiler state */ -struct DstFormOptions { - DstCompiler *compiler; - DstValue x; - const DstValue *sourcemap; - uint32_t flags; /* bit set of accepted primitive types */ -}; - -typedef enum DstCompileStatus { - DST_COMPILE_OK, - DST_COMPILE_ERROR -} DstCompileStatus; - -/* Results of compilation */ -typedef struct DstCompileResults { - DstCompileStatus status; - DstFuncDef *funcdef; - const uint8_t *error; -} DstCompileResults; - -typedef struct DstCompileOptions { - uint32_t flags; - const DstValue *sourcemap; - DstValue src; - int32_t target; -}; - -/* Compiler handlers. Used to compile different kinds of expressions. */ -typedef DstSlot (*DstFormCompiler)(DstFormOptions opts); - -/* Dispatch to correct form compiler */ -DstSlot dst_compile_value(DstFormOptions opts); - -/* Compile basic types */ -DstSlot dst_compile_constant(DstFormOptions opts); -DstSlot dst_compile_symbol(DstFormOptions opts); -DstSlot dst_copmile_array(DstFormOptions opts); -DstSlot dst_copmile_struct(DstFormOptions opts); -DstSlot dst_copmile_table(DstFormOptions opts); - -/* Tuple compiliation will handle much of the work */ -DstSlot dst_compile_tuple(DstFormOptions opts); - -/* Compile special forms */ -DstSlot dst_compile_do(DstFormOptions opts); -DstSlot dst_compile_fn(DstFormOptions opts); -DstSlot dst_compile_cond(DstFormOptions opts); -DstSlot dst_compile_while(DstFormOptions opts); -DstSlot dst_compile_quote(DstFormOptions opts); -DstSlot dst_compile_def(DstFormOptions opts); -DstSlot dst_compile_var(DstFormOptions opts); -DstSlot dst_compile_varset(DstFormOptions opts); - -/* Compile source code into FuncDef. */ -DstCompileResults dst_compile(DstCompileOptions opts); - -/****************************************************/ - -DstSlot dst_compile_error(DstCompiler *c, const DstValue *sourcemap, const uint8_t *m); -DstSlot dst_compile_cerror(DstCompiler *c, const DstValue *sourcemap, const char *m); - -/* Use these to get sub options. They will traverse the source map so - * compiler errors make sense. Then modify the returned options. */ -DstFormOptions dst_compile_getopts_index(DstFormOptions opts, int32_t index); -DstFormOptions dst_compile_getopts_key(DstFormOptions opts, DstValue key); -DstFormOptions dst_compile_getopts_value(DstFormOptions opts, DstValue key); - -void dst_compile_scope(DstCompiler *c, int newfn); -DstSlot dst_compile_popscope(DstCompiler *c); - -int dst_compile_slotmatch(DstFormOptions opts, DstSlot slot); -DstSlot dst_compile_normalslot(DstCompiler *c, uint32_t types); -DstSlot dst_compile_constantslot(DstCompiler *c, DstValue x); -void dst_compile_freeslot(DstCompiler *c, DstSlot slot); -void dst_compile_freeslotarray(DstCompiler *c, DstArray *slots); - -/* Search for a symbol */ -DstSlot dst_compile_resolve(DstCompiler *c, const DstValue *sourcemap, const uint8_t *sym); - -/* Get a local slot that can be used as the desination for whatever is compiling. */ -DstSlot dst_compile_targetslot(DstFormOptions opts, DstSlot s); - -/* Coerce any slot into the target slot. If no target is specified, return - * the slot unaltered. Otherwise, move and load upvalues as necesarry to set the slot. */ -DstSlot dst_compile_coercetargetslot(DstFormOptions opts, DstSlot s); - -DstSlot dst_compile_realizeslot(DstCompiler *c, DstSlot s); -DstSlot dst_compile_returnslot(DstCompiler *c, DstSlot s); - -/* Emit instructions. */ - -DstSlot dst_compile_emit_movenear(DstCompiler *c, DstSlot slot); -void dst_compile_emit_movefar(DstCompiler *c, DstSlot near, DstSlot orig); - -void dst_compile_emit_ss(DstCompiler *c, DstOpCode op, DstSlot dest, DstSlot src); -void dst_compile_emit_sss(DstCompiler *c, DstOpCode op, DstSlot dest, DstSlot s1, DstSlot s2); -void dst_compile_emit_sss_src(DstCompiler *c, DstOpCode op, DstSlot s1, DstSlot s2, DstSlot s3); - -#endif diff --git a/Makefile b/Makefile index 8613d7b4..b8cfecf1 100644 --- a/Makefile +++ b/Makefile @@ -59,7 +59,8 @@ $(DST_XXD): libs/xxd.c ################################### DST_CORE_SOURCES=$(addprefix core/,\ - array.c asm.c buffer.c compile.c fiber.c func.c gc.c parse.c string.c strtod.c\ + array.c asm.c buffer.c compile.c compile_slotpool.c \ + fiber.c func.c gc.c parse.c string.c strtod.c\ struct.c symcache.c syscalls.c table.c tuple.c userdata.c util.c\ value.c vm.c wrap.c) DST_CORE_OBJECTS=$(patsubst %.c,%.o,$(DST_CORE_SOURCES)) @@ -78,7 +79,7 @@ $(DST_TARGET): $(DST_CORE_OBJECTS) CCU_FLAGS = $(CFLAGS) -DDST_UNIT_TEST DST_UNIT_BINARIES=$(addprefix unittests/,\ - asm_test.out array_test.out buffer_test.out fiber_test.out \ + asm_test.out array_test.out buffer_test.out compile_test.out fiber_test.out \ parse_test.out strtod_test.out table_test.out) %.out: %.c $(DST_CORE_OBJECTS) $(DST_ALL_HEADERS) unittests/unit.h @@ -88,6 +89,7 @@ unit: $(DST_UNIT_BINARIES) unittests/array_test.out unittests/asm_test.out unittests/buffer_test.out + unittests/compile_test.out unittests/fiber_test.out unittests/parse_test.out unittests/strtod_test.out diff --git a/core/array.c b/core/array.c index 05c57d70..638a82e4 100644 --- a/core/array.c +++ b/core/array.c @@ -24,10 +24,12 @@ /* Iniializes an array */ DstArray *dst_array_init(DstArray *array, int32_t capacity) { - if (capacity < 0) capacity = 0; - DstValue *data = (DstValue *) malloc(sizeof(DstValue) * capacity); - if (NULL == data) { - DST_OUT_OF_MEMORY; + DstValue *data = NULL; + if (capacity > 0) { + data = (DstValue *) malloc(sizeof(DstValue) * capacity); + if (NULL == data) { + DST_OUT_OF_MEMORY; + } } array->count = 0; array->capacity = capacity; diff --git a/core/asm.c b/core/asm.c index dde149d0..24a414fd 100644 --- a/core/asm.c +++ b/core/asm.c @@ -518,6 +518,9 @@ static DstAssembleResult dst_asm1(DstAssembler *parent, DstAssembleOptions opts) def->flags = 0; def->slotcount = 0; def->arity = 0; + def->source = NULL; + def->sourcepath = NULL; + def->sourcemap = NULL; def->constants_length = 0; def->bytecode_length = 0; def->environments_length = 1; @@ -544,7 +547,7 @@ static DstAssembleResult dst_asm1(DstAssembler *parent, DstAssembleOptions opts) dst_asm_deinit(&a); longjmp(a.parent->on_error, 1); } - result.result.error = a.errmessage; + result.error = a.errmessage; result.status = DST_ASSEMBLE_ERROR; if (a.errmap != NULL) { result.error_start = dst_unwrap_integer(a.errmap[0]); @@ -560,6 +563,23 @@ static DstAssembleResult dst_asm1(DstAssembler *parent, DstAssembleOptions opts) x = dst_struct_get(st, dst_csymbolv("arity")); def->arity = dst_checktype(x, DST_INTEGER) ? dst_unwrap_integer(x) : 0; + /* Check vararg */ + x = dst_struct_get(st, dst_csymbolv("vararg")); + if (dst_truthy(x)) + def->flags |= DST_FUNCDEF_FLAG_VARARG; + + /* Check source */ + x = dst_struct_get(st, dst_csymbolv("source")); + if (dst_checktype(x, DST_STRING)) { + def->source = dst_unwrap_string(x); + } + + /* Check source path */ + x = dst_struct_get(st, dst_csymbolv("sourcepath")); + if (dst_checktype(x, DST_STRING)) { + def->sourcepath = dst_unwrap_string(x); + } + /* Create slot aliases */ x = dst_struct_get(st, dst_csymbolv("slots")); if (dst_seq_view(x, &arr, &count)) { @@ -586,10 +606,10 @@ static DstAssembleResult dst_asm1(DstAssembler *parent, DstAssembleOptions opts) } /* Create environment aliases */ - x = dst_struct_get(st, dst_csymbolv("environments")); + x = dst_struct_get(st, dst_csymbolv("captures")); if (dst_seq_view(x, &arr, &count)) { const DstValue *emap = - dst_parse_submap_value(opts.sourcemap, dst_csymbolv("environments")); + dst_parse_submap_value(opts.sourcemap, dst_csymbolv("captures")); for (i = 0; i < count; i++) { const DstValue *imap = dst_parse_submap_index(emap, i); dst_asm_assert(&a, dst_checktype(arr[i], DST_SYMBOL), imap, "environment must be a symbol"); @@ -690,12 +710,38 @@ static DstAssembleResult dst_asm1(DstAssembler *parent, DstAssembleOptions opts) } else { dst_asm_error(&a, opts.sourcemap, "bytecode expected"); } + + /* Check for source mapping */ + x = dst_struct_get(st, dst_csymbolv("sourcemap")); + if (dst_seq_view(x, &arr, &count)) { + const DstValue *bmap = + dst_parse_submap_value(opts.sourcemap, dst_csymbolv("sourcemap")); + dst_asm_assert(&a, count != 2 * def->bytecode_length, bmap, "sourcemap must have twice the length of the bytecode"); + def->sourcemap = malloc(sizeof(int32_t) * 2 * count); + for (i = 0; i < count; i += 2) { + DstValue start = arr[i]; + DstValue end = arr[i + 1]; + if (!(dst_checktype(start, DST_INTEGER) || + dst_unwrap_integer(start) < 0)) { + const DstValue *submap = dst_parse_submap_index(bmap, i); + dst_asm_error(&a, submap, "expected positive integer"); + } + if (!(dst_checktype(end, DST_INTEGER) || + dst_unwrap_integer(end) < 0)) { + const DstValue *submap = dst_parse_submap_index(bmap, i + 1); + dst_asm_error(&a, submap, "expected positive integer"); + } + def->sourcemap[i] = dst_unwrap_integer(start); + def->sourcemap[i+1] = dst_unwrap_integer(end); + } + + } /* Finish everything and return funcdef */ dst_asm_deinit(&a); def->environments = realloc(def->environments, def->environments_length * sizeof(int32_t)); - result.result.def = def; + result.funcdef = def; result.status = DST_ASSEMBLE_OK; return result; } @@ -711,7 +757,154 @@ DstFunction *dst_asm_func(DstAssembleResult result) { return NULL; } DstFunction *func = dst_alloc(DST_MEMORY_FUNCTION, sizeof(DstFunction)); - func->def = result.result.def; + func->def = result.funcdef; func->envs = NULL; return func; } + +/* Disassembly */ + +/* Find the deinfintion of an instruction given the instruction word. Return + * NULL if not found. */ +static const DstInstructionDef *dst_asm_reverse_lookup(uint32_t instr) { + size_t i; + uint32_t opcode = instr & 0xFF; + for (i = 0; i < sizeof(dst_ops)/sizeof(DstInstructionDef); i++) { + const DstInstructionDef *def = dst_ops + i; + if (def->opcode == opcode) + return def; + } + return NULL; +} + +/* Create some constant sized tuples */ +static DstValue tup1(DstValue x) { + DstValue *tup = dst_tuple_begin(1); + tup[0] = x; + return dst_wrap_tuple(dst_tuple_end(tup)); +} +static DstValue tup2(DstValue x, DstValue y) { + DstValue *tup = dst_tuple_begin(2); + tup[0] = x; + tup[1] = y; + return dst_wrap_tuple(dst_tuple_end(tup)); +} +static DstValue tup3(DstValue x, DstValue y, DstValue z) { + DstValue *tup = dst_tuple_begin(3); + tup[0] = x; + tup[1] = y; + tup[2] = z; + return dst_wrap_tuple(dst_tuple_end(tup)); +} +static DstValue tup4(DstValue w, DstValue x, DstValue y, DstValue z) { + DstValue *tup = dst_tuple_begin(4); + tup[0] = w; + tup[1] = x; + tup[2] = y; + tup[3] = z; + return dst_wrap_tuple(dst_tuple_end(tup)); +} + +/* Given an argument, convert it to the appriate integer or symbol */ +static DstValue dst_asm_decode_instruction(uint32_t instr) { + const DstInstructionDef *def = dst_asm_reverse_lookup(instr); + DstValue name; + if (NULL == def) { + return dst_wrap_integer((int32_t)instr); + } + name = dst_csymbolv(def->name); +#define oparg(shift, mask) ((instr >> ((shift) << 3)) & (mask)) + switch (def->type) { + case DIT_0: + return tup1(name); + case DIT_S: + return tup2(name, dst_wrap_integer(oparg(1, 0xFFFFFF))); + case DIT_L: + return tup2(name, dst_wrap_integer((int32_t)instr >> 8)); + case DIT_SS: + case DIT_ST: + case DIT_SC: + case DIT_SU: + return tup3(name, + dst_wrap_integer(oparg(1, 0xFF)), + dst_wrap_integer(oparg(2, 0xFFFF))); + case DIT_SI: + case DIT_SL: + return tup3(name, + dst_wrap_integer(oparg(1, 0xFF)), + dst_wrap_integer((int32_t)instr >> 16)); + case DIT_SSS: + case DIT_SES: + case DIT_SSU: + return tup4(name, + dst_wrap_integer(oparg(1, 0xFF)), + dst_wrap_integer(oparg(2, 0xFF)), + dst_wrap_integer(oparg(3, 0xFF))); + case DIT_SSI: + return tup4(name, + dst_wrap_integer(oparg(1, 0xFF)), + dst_wrap_integer(oparg(2, 0xFF)), + dst_wrap_integer((int32_t)instr >> 24)); + } +#undef oparg +} + +DstValue dst_disasm(DstFuncDef *def) { + int32_t i; + DstArray *bcode = dst_array(def->bytecode_length); + DstArray *constants = dst_array(def->constants_length); + DstTable *ret = dst_table(10); + dst_table_put(ret, dst_csymbolv("arity"), dst_wrap_integer(def->arity)); + dst_table_put(ret, dst_csymbolv("bytecode"), dst_wrap_array(bcode)); + dst_table_put(ret, dst_csymbolv("constants"), dst_wrap_array(constants)); + if (def->sourcepath) { + dst_table_put(ret, dst_csymbolv("sourcepath"), dst_wrap_string(def->sourcepath)); + } + if (def->source) { + dst_table_put(ret, dst_csymbolv("source"), dst_wrap_string(def->source)); + } + if (def->flags & DST_FUNCDEF_FLAG_VARARG) { + dst_table_put(ret, dst_csymbolv("vararg"), dst_wrap_true()); + } + + /* Add constants */ + for (i = 0; i < def->constants_length; i++) { + DstValue src = def->constants[i]; + DstValue dest; + if (dst_checktype(src, DST_TUPLE)) { + dest = tup2(dst_csymbolv("quote"), src); + } else { + dest = src; + } + constants->data[i] = dest; + } + constants->count = def->constants_length; + + /* Add bytecode */ + for (i = 0; i < def->bytecode_length; i++) { + bcode->data[i] = dst_asm_decode_instruction(def->bytecode[i]); + } + bcode->count = def->bytecode_length; + + /* Add source map */ + if (def->sourcemap) { + DstArray *sourcemap = dst_array(def->bytecode_length * 2); + for (i = 0; i < def->bytecode_length * 2; i++) { + sourcemap->data[i] = dst_wrap_integer(def->sourcemap[i]); + } + sourcemap->count = def->bytecode_length * 2; + dst_table_put(ret, dst_csymbolv("sourcemap"), dst_wrap_array(sourcemap)); + } + + /* Add environments */ + if (def->environments) { + DstArray *envs = dst_array(def->environments_length); + for (i = 0; i < def->environments_length; i++) { + envs->data[i] = dst_wrap_integer(def->environments[i]); + } + envs->count = def->environments_length; + dst_table_put(ret, dst_csymbolv("environments"), dst_wrap_array(envs)); + } + + return dst_wrap_struct(dst_table_to_struct(ret)); +} diff --git a/core/compile.c b/core/compile.c index a86e5f3b..9e902745 100644 --- a/core/compile.c +++ b/core/compile.c @@ -24,29 +24,17 @@ #include "compile.h" /* Lazily sort the optimizers */ -static int optimizers_sorted = 0; +/*static int optimizers_sorted = 0;*/ /* Lookups for specials and optimizable c functions. */ -DstCFunctionOptimizer dst_compiler_optimizers[255]; -DstSpecial dst_compiler_specials[16]; - -/* Deinitialize a compiler struct */ -static void dst_compile_cleanup(DstCompiler *c) { - while (c->scopecount) - dst_compile_popscope(c); - free(c->scopes); - free(c->buffer); - free(c->mapbuffer); - c->buffer = NULL; - c->mapbuffer = NULL; - c->scopes = NULL; -} +/*DstCFunctionOptimizer dst_compiler_optimizers[255];*/ +/*DstSpecial dst_compiler_specials[16];*/ /* Throw an error with a dst string */ void dst_compile_error(DstCompiler *c, const DstValue *sourcemap, const uint8_t *m) { - c->error_start = dst_unwrap_integer(sourcemap[0]); - c->error_end = dst_unwrap_integer(sourcemap[1]); - c->error = dst_wrap_string(m); + c->results.error_start = dst_unwrap_integer(sourcemap[0]); + c->results.error_end = dst_unwrap_integer(sourcemap[1]); + c->results.error = m; longjmp(c->on_error, 1); } @@ -77,72 +65,6 @@ DstFormOptions dst_compile_getopts_value(DstFormOptions opts, DstValue key) { opts.sourcemap = sourcemap; return opts; } - -void dst_compile_slotpool_init(DstSlotPool *pool) { - pool->s = NULL; - pool->count = 0; - pool->free = 0; - pool->cap = 0; -} - -void dst_compile_slotpool_deinit(DstSlotPool *pool) { - free(pool->s); - pool->s = NULL; - pool->cap = 0; - pool->count = 0; -} - -void dst_compile_slotpool_extend(DstSlotPool *pool, int32_t extra) { - int32_t i; - int32_t newcount = pool->count + extra; - if (newcount > pool->cap) { - int32_t newcap = 2 * newcount; - pool->s = realloc(pool->s, newcap * sizeof(DstSlot)); - if (NULL == pool->s) { - DST_OUT_OF_MEMORY; - } - pool->cap = newcap; - } - /* Mark all slots as free */ - for (i = pool->count; i < newcount; i++) { - pool->s[i].flags = 0; - } - pool->count = newcount; -} - -DstSlot *dst_compile_slotpool_alloc(DstSlotPool *pool) { - int32_t oldcount = pool->count; - int32_t newcount = oldcount == 0xF0 ? 0x101 : oldcount + 1; - while (pool->free < pool->count) { - if (!(pool->s[pool->free].flags & DST_SLOT_NOTEMPTY)) { - return pool->s + pool->free; - } - pool->free++; - } - dst_compile_slotpool_extend(pool, newcount - oldcount); - pool->s[oldcount].flags = DST_SLOT_NOTEMPTY; - pool->s[oldcount].index = newcount - 1; - return pool->s + newcount - 1; -} - -void dst_compile_slotpool_freeindex(DstSlotPool *pool, int32_t index) { - if (index > 0 && index < pool->count) { - pool->s[index].flags = 0; - if (index < pool->free) - pool->free = index; - } -} - -void dst_compile_slotpool_free(DstSlotPool *pool, DstSlot *s) { - DstSlot *oldfree = pool->s + pool->free; - if (s >= pool->s && s < (pool->s + pool->count)) { - if (s < oldfree) { - pool->free = s - pool->s; - } - s->flags = 0; - } -} - /* Eneter a new scope */ void dst_compile_scope(DstCompiler *c, int newfn) { int32_t newcount, oldcount; @@ -154,7 +76,7 @@ void dst_compile_scope(DstCompiler *c, int newfn) { ? c->scopes[c->scopecount - 1].level : 0; newlevel = oldlevel + newfn; - if (newcount < c->scopecap) { + if (newcount > c->scopecap) { int32_t newcap = 2 * newcount; c->scopes = realloc(c->scopes, newcap * sizeof(DstScope)); if (NULL == c->scopes) { @@ -164,7 +86,7 @@ void dst_compile_scope(DstCompiler *c, int newfn) { } scope = c->scopes + oldcount; c->scopecount = newcount; - dst_array_init(&scope->constants, 0); + dst_array_init(&(scope->constants), 0); dst_table_init(&scope->symbols, 4); dst_table_init(&scope->constantrev, 4); @@ -206,7 +128,7 @@ DstSlot *dst_compile_constantslot(DstCompiler *c, DstValue x) { ret->flags = (1 << dst_type(x)) | DST_SLOT_CONSTANT | DST_SLOT_NOTEMPTY; ret->index = -1; ret->constant = x; - ret->envindex = scope->level; + ret->envindex = 0; return ret; } @@ -331,72 +253,13 @@ DstSlot *dst_compile_resolve( return ret; } -DstSlot *dst_compile_def(DstFormOptions opts, int32_t argn, const DstValue *argv) { - DstScope *scope; - DstSlot *rvalue; - DstFormOptions subopts; - DstValue check; - if (argn != 2) - dst_compile_cerror(opts.compiler, opts.sourcemap, "expected 2 arguments"); - if (!dst_checktype(argv[0], DST_SYMBOL)) - dst_compile_cerror(opts.compiler, opts.sourcemap, "expected symbol"); - scope = dst_compile_topscope(opts.compiler); - check = dst_table_get(&scope->symbols, argv[0]); - if (dst_checktype(check, DST_INTEGER)) { - dst_compile_cerror(opts.compiler, opts.sourcemap, "cannot redefine symbol"); - } - subopts = dst_compile_getopts_index(opts, 1); - rvalue = dst_compile_value(subopts); - dst_table_put(&scope->symbols, argv[0], dst_wrap_userdata(rvalue)); - return rvalue; -} - -/* Compile an array */ - -/* Compile a single value */ -DstSlot *dst_compile_value(DstFormOptions opts) { - DstSlot *ret; - if (opts.compiler->recursion_guard <= 0) { - dst_compile_cerror(opts.compiler, opts.sourcemap, "recursed too deeply"); - } - opts.compiler->recursion_guard--; - switch (dst_type(opts.x)) { - default: - ret = dst_compile_constantslot(opts.compiler, opts.x); - break; - case DST_SYMBOL: - { - const uint8_t *sym = dst_unwrap_symbol(opts.x); - if (dst_string_length(sym) > 0 && sym[0] != ':') - ret = dst_compile_resolve(opts.compiler, opts.sourcemap, sym); - else - ret = dst_compile_constantslot(opts.compiler, opts.x); - break; - } - /*case DST_TUPLE:*/ - /*ret = dst_compile_tuple(opts); */ - /*break;*/ - /*case DST_ARRAY:*/ - /*ret = dst_compile_array(opts); */ - /*break;*/ - /*case DST_STRUCT:*/ - /*ret = dst_compile_struct(opts); */ - /*break;*/ - /*case DST_TABLE:*/ - /*ret = dst_compile_table(opts);*/ - /*break;*/ - } - opts.compiler->recursion_guard++; - return ret; -} - /* Emit a raw instruction with source mapping. */ void dst_compile_emit(DstCompiler *c, const DstValue *sourcemap, uint32_t instr) { int32_t index = c->buffercount; int32_t newcount = index + 1; if (newcount > c->buffercap) { int32_t newcap = 2 * newcount; - c->buffer = realloc(c->buffer, newcap * sizeof(int32_t)); + c->buffer = realloc(c->buffer, newcap * sizeof(uint32_t)); c->mapbuffer = realloc(c->mapbuffer, newcap * sizeof(int32_t) * 2); if (NULL == c->buffer || NULL == c->mapbuffer) { DST_OUT_OF_MEMORY; @@ -405,8 +268,8 @@ void dst_compile_emit(DstCompiler *c, const DstValue *sourcemap, uint32_t instr) } c->buffercount = newcount; if (NULL != sourcemap) { - c->mapbuffer[index][0] = dst_unwrap_integer(sourcemap[0]); - c->mapbuffer[index][1] = dst_unwrap_integer(sourcemap[1]); + c->mapbuffer[index * 2] = dst_unwrap_integer(sourcemap[0]); + c->mapbuffer[index * 2 + 1] = dst_unwrap_integer(sourcemap[1]); } c->buffer[index] = instr; } @@ -569,30 +432,168 @@ static void dst_compile_slot_post( } } -static void dst_compile_pop_funcdef(DstCompiler *c) { - DstScope *scope = dst_compiler_topscope(c); +/* Generate the return instruction for a slot. */ +static void dst_compile_return(DstCompiler *c, const DstValue *sourcemap, DstSlot *s) { + if (s->flags & DST_SLOT_CONSTANT && dst_checktype(s->constant, DST_NIL)) { + dst_compile_emit(c, sourcemap, DOP_RETURN_NIL); + } else { + DstLocalSlot ls = dst_compile_slot_pre( + c, sourcemap, 0xFFFF, -1, + 1, 1, s); + dst_compile_emit(c, sourcemap, DOP_RETURN | (ls.index << 8)); + dst_compile_slot_post(c, sourcemap, ls); + } +} + +DstSlot *dst_compile_def(DstFormOptions opts, int32_t argn, const DstValue *argv) { + DstScope *scope; + DstSlot *rvalue; + DstFormOptions subopts; + DstValue check; + if (argn != 2) + dst_compile_cerror(opts.compiler, opts.sourcemap, "expected 2 arguments"); + if (!dst_checktype(argv[0], DST_SYMBOL)) + dst_compile_cerror(opts.compiler, opts.sourcemap, "expected symbol"); + scope = dst_compile_topscope(opts.compiler); + check = dst_table_get(&scope->symbols, argv[0]); + if (dst_checktype(check, DST_INTEGER)) { + dst_compile_cerror(opts.compiler, opts.sourcemap, "cannot redefine symbol"); + } + subopts = dst_compile_getopts_index(opts, 1); + rvalue = dst_compile_value(subopts); + dst_table_put(&scope->symbols, argv[0], dst_wrap_userdata(rvalue)); + return rvalue; +} + +/* Compile an array */ + +/* Compile a single value */ +DstSlot *dst_compile_value(DstFormOptions opts) { + DstSlot *ret; + int doreturn = opts.flags & DST_FOPTS_TAIL; + if (opts.compiler->recursion_guard <= 0) { + dst_compile_cerror(opts.compiler, opts.sourcemap, "recursed too deeply"); + } + opts.compiler->recursion_guard--; + switch (dst_type(opts.x)) { + default: + ret = dst_compile_constantslot(opts.compiler, opts.x); + break; + case DST_SYMBOL: + { + const uint8_t *sym = dst_unwrap_symbol(opts.x); + if (dst_string_length(sym) > 0 && sym[0] != ':') { + ret = dst_compile_resolve(opts.compiler, opts.sourcemap, sym); + } else { + ret = dst_compile_constantslot(opts.compiler, opts.x); + } + break; + } + /*case DST_TUPLE:*/ + /*ret = dst_compile_tuple(opts); */ + /*break;*/ + /*case DST_ARRAY:*/ + /*ret = dst_compile_array(opts); */ + /*break;*/ + /*case DST_STRUCT:*/ + /*ret = dst_compile_struct(opts); */ + /*break;*/ + /*case DST_TABLE:*/ + /*ret = dst_compile_table(opts);*/ + /*break;*/ + } + if (doreturn) { + dst_compile_return(opts.compiler, opts.sourcemap, ret); + } + opts.compiler->recursion_guard++; + return ret; +} + +/* Compile a funcdef */ +static DstFuncDef *dst_compile_pop_funcdef(DstCompiler *c) { + DstScope *scope = dst_compile_topscope(c); DstFuncDef *def; /* Initialize funcdef */ def = dst_alloc(DST_MEMORY_FUNCDEF, sizeof(DstFuncDef)); - def->environments = NULL; - def->constants = NULL; - def->bytecode = NULL; - def->flags = 0; - def->slotcount = 0; - def->arity = 0; + def->environments_length = scope->envcount; + def->environments = malloc(sizeof(int32_t) * def->environments_length); def->constants_length = 0; - def->bytecode_length = 0; - def->environments_length = 1; + def->constants = malloc(sizeof(DstValue) * scope->constants.count); + def->bytecode_length = c->buffercount - scope->bytecode_start; + def->bytecode = malloc(sizeof(uint32_t) * def->bytecode_length); + def->slotcount = scope->slots.count; + + if (NULL == def->environments || + NULL == def->constants || + NULL == def->bytecode) { + DST_OUT_OF_MEMORY; + } + + memcpy(def->environments, scope->envs, def->environments_length * sizeof(int32_t)); + memcpy(def->constants, scope->constants.data, def->constants_length * sizeof(DstValue)); + memcpy(def->bytecode, c->buffer + c->buffercount, def->bytecode_length * sizeof(uint32_t)); + + if (c->mapbuffer) { + def->sourcemap = malloc(sizeof(uint32_t) * 2 * def->bytecode_length); + if (NULL == def->sourcemap) { + DST_OUT_OF_MEMORY; + } + memcpy(def->sourcemap, c->mapbuffer + 2 * c->buffercount, def->bytecode_length * 2 * sizeof(uint32_t)); + } + + /* Reset bytecode gen */ + c->buffercount = scope->bytecode_start; + + /* Manually set arity and flags later */ + def->flags = 0; + def->arity = 0; + + /* Set some flags */ + if (scope->flags & DST_SCOPE_ENV) { + def->flags |= DST_FUNCDEF_FLAG_NEEDSENV; + } + + /* Pop the scope */ + dst_compile_popscope(c); + + return def; +} + +/* Print a slot for debugging */ +/*static void print_slot(DstSlot *s) {*/ + /*if (!(s->flags & DST_SLOT_NOTEMPTY)) {*/ + /*printf("X");*/ + /*} else if (s->flags & DST_SLOT_CONSTANT) {*/ + /*dst_puts(dst_short_description(s->constant));*/ + /*} else if (s->envindex > 0) {*/ + /*printf("UP%d[%d]", s->envindex, s->index);*/ + /*} else {*/ + /*printf("%d", s->index);*/ + /*}*/ +/*}*/ + +/* Deinitialize a compiler struct */ +static void dst_compile_cleanup(DstCompiler *c) { + while (c->scopecount) + dst_compile_popscope(c); + free(c->scopes); + free(c->buffer); + free(c->mapbuffer); + c->buffer = NULL; + c->mapbuffer = NULL; + c->scopes = NULL; } DstCompileResults dst_compile(DstCompileOptions opts) { DstCompiler c; + DstFormOptions fopts; + DstSlot *s; if (setjmp(c.on_error)) { c.results.status = DST_COMPILE_ERROR; dst_compile_cleanup(&c); - results.funcdef = NULL; + c.results.funcdef = NULL; return c.results; } @@ -602,9 +603,36 @@ DstCompileResults dst_compile(DstCompileOptions opts) { c.scopes = NULL; c.buffercap = 0; c.buffercount = 0; - c->buffer = NULL; - c->mapbuffer; - c->recursion_guard = 1024; + c.buffer = NULL; + c.mapbuffer = NULL; + c.recursion_guard = 1024; - + /* Push a function scope */ + dst_compile_scope(&c, 1); + + fopts.compiler = &c; + fopts.sourcemap = opts.sourcemap; + fopts.flags = DST_FOPTS_TAIL | DST_SLOTTYPE_ANY; + fopts.hint = 0; + fopts.x = opts.source; + + /* Compile the value */ + s = dst_compile_value(fopts); + + c.results.funcdef = dst_compile_pop_funcdef(&c); + c.results.status = DST_COMPILE_OK; + + dst_compile_cleanup(&c); + + return c.results; +} + +DstFunction *dst_compile_func(DstCompileResults res) { + if (res.status != DST_COMPILE_OK) { + return NULL; + } + DstFunction *func = dst_alloc(DST_MEMORY_FUNCTION, sizeof(DstFunction)); + func->def = res.funcdef; + func->envs = NULL; + return func; } diff --git a/core/compile.h b/core/compile.h index 4788ffdc..6c88d0a2 100644 --- a/core/compile.h +++ b/core/compile.h @@ -38,10 +38,8 @@ typedef struct DstCFunctionOptimizer DstCFunctionOptimizer; #define DST_SLOT_CONSTANT 0x10000 #define DST_SLOT_NAMED 0x20000 -#define DST_SLOT_RETURNED 0x40000 -#define DST_SLOT_NIL 0x80000 -#define DST_SLOT_MUTABLE 0x100000 -#define DST_SLOT_NOTEMPTY 0x200000 +#define DST_SLOT_MUTABLE 0x40000 +#define DST_SLOT_NOTEMPTY 0x80000 #define DST_SLOTTYPE_ANY 0xFFFF @@ -116,7 +114,7 @@ struct DstCompiler { int32_t buffercap; int32_t buffercount; uint32_t *buffer; - int32_t (*mapbuffer)[2]; + int32_t *mapbuffer; DstCompileResults results; }; @@ -130,6 +128,7 @@ struct DstFormOptions { DstValue x; const DstValue *sourcemap; uint32_t flags; /* bit set of accepted primitive types */ + int32_t hint; }; /* A grouping of optimizations on a cfunction given certain conditions diff --git a/core/compile_slotpool.c b/core/compile_slotpool.c new file mode 100644 index 00000000..6db8c37a --- /dev/null +++ b/core/compile_slotpool.c @@ -0,0 +1,92 @@ +/* +* 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 "compile.h" + +void dst_compile_slotpool_init(DstSlotPool *pool) { + pool->s = NULL; + pool->count = 0; + pool->free = 0; + pool->cap = 0; +} + +void dst_compile_slotpool_deinit(DstSlotPool *pool) { + free(pool->s); + pool->s = NULL; + pool->cap = 0; + pool->count = 0; + pool->free = 0; +} + +void dst_compile_slotpool_extend(DstSlotPool *pool, int32_t extra) { + int32_t i; + int32_t newcount = pool->count + extra; + if (newcount > pool->cap) { + int32_t newcap = 2 * newcount; + pool->s = realloc(pool->s, newcap * sizeof(DstSlot)); + if (NULL == pool->s) { + DST_OUT_OF_MEMORY; + } + pool->cap = newcap; + } + /* Mark all new slots as free */ + for (i = pool->count; i < newcount; i++) { + pool->s[i].flags = 0; + } + pool->count = newcount; +} + +DstSlot *dst_compile_slotpool_alloc(DstSlotPool *pool) { + int32_t oldcount = pool->count; + int32_t newcount = oldcount == 0xF0 ? 0x101 : oldcount + 1; + int32_t index = newcount - 1; + while (pool->free < pool->count) { + if (!(pool->s[pool->free].flags & DST_SLOT_NOTEMPTY)) { + return pool->s + pool->free; + } + pool->free++; + } + dst_compile_slotpool_extend(pool, newcount - oldcount); + pool->s[index].flags = DST_SLOT_NOTEMPTY; + pool->s[index].index = index; + return pool->s + index; +} + +void dst_compile_slotpool_freeindex(DstSlotPool *pool, int32_t index) { + if (index > 0 && index < pool->count) { + pool->s[index].flags = 0; + if (index < pool->free) + pool->free = index; + } +} + +void dst_compile_slotpool_free(DstSlotPool *pool, DstSlot *s) { + DstSlot *oldfree = pool->s + pool->free; + if (s >= pool->s && s < (pool->s + pool->count)) { + if (s < oldfree) { + pool->free = s - pool->s; + } + s->flags = 0; + } +} + diff --git a/core/gc.c b/core/gc.c index 4201948e..fb043efe 100644 --- a/core/gc.c +++ b/core/gc.c @@ -179,6 +179,10 @@ static void dst_mark_funcdef(DstFuncDef *def) { } } } + if (def->source) + dst_mark_string(def->source); + if (def->sourcepath) + dst_mark_string(def->sourcepath); } static void dst_mark_function(DstFunction *func) { @@ -263,6 +267,7 @@ static void dst_deinit_block(DstGCMemoryHeader *block) { free(def->environments); free(def->constants); free(def->bytecode); + free(def->sourcemap); } break; } diff --git a/core/parse.c b/core/parse.c index ec8298aa..a4dcc75b 100644 --- a/core/parse.c +++ b/core/parse.c @@ -423,10 +423,12 @@ DstParseResult dst_parse(const uint8_t *src, int32_t len) { res.bytes_read = (int32_t) (newsrc - src); if (args.errmsg) { - res.result.error = dst_cstring(args.errmsg); + res.error = dst_cstring(args.errmsg); + res.value = dst_wrap_nil(); res.map = NULL; } else { - res.result.value = dst_array_pop(&args.stack); + res.value = dst_array_pop(&args.stack); + res.error = NULL; res.map = dst_unwrap_tuple(dst_array_pop(&args.mapstack)); } diff --git a/core/syscalls.c b/core/syscalls.c index 8ce59e54..500140a4 100644 --- a/core/syscalls.c +++ b/core/syscalls.c @@ -55,7 +55,7 @@ int dst_sys_asm(DstValue *argv, int32_t argn) { dst_vm_fiber->ret = dst_wrap_function(dst_asm_func(res)); return 0; } else { - dst_vm_fiber->ret = dst_wrap_string(res.result.error); + dst_vm_fiber->ret = dst_wrap_string(res.error); return 1; } } diff --git a/core/table.c b/core/table.c index 4dfb07a5..2dffbcbf 100644 --- a/core/table.c +++ b/core/table.c @@ -175,7 +175,7 @@ DstValue dst_table_next(DstTable *t, DstValue key) { const DstValue *dst_table_to_struct(DstTable *t) { int32_t i; DstValue *st = dst_struct_begin(t->count); - for (i = 0; i < t->capacity; i++) { + for (i = 0; i < t->capacity; i += 2) { if (!dst_checktype(t->data[i], DST_NIL)) dst_struct_put(st, t->data[i], t->data[i + 1]); } diff --git a/dsttest/basic.dst b/dsttest/basic.dst new file mode 100644 index 00000000..6492c9fb --- /dev/null +++ b/dsttest/basic.dst @@ -0,0 +1,4 @@ +# A really basic for to compile. for testing the compiler. Will extend +# as compiler is extended. +123 + diff --git a/dsts/compile.dsts b/dsttest/compile.dsts similarity index 100% rename from dsts/compile.dsts rename to dsttest/compile.dsts diff --git a/dsts/example.dsts b/dsttest/example.dsts similarity index 88% rename from dsts/example.dsts rename to dsttest/example.dsts index 6645beb4..ed3873ce 100644 --- a/dsts/example.dsts +++ b/dsttest/example.dsts @@ -5,7 +5,7 @@ { arity 3 source "source file path" - varargs false + vararg false # Name for reference by nested funcdefs name outerfunc # Contains the bytecode for this function. This can be assembly @@ -22,9 +22,7 @@ (return 0) ] # A source map is optional. The sourcemap corresponds with the byte code. -# Each number is a 64 bit integer, the concatenation of two 32 bit integers. -# These integers represent source character index for each instruction. -# This format may change. +# Each instruction has two source map entries, offset start and offset end. # map [ # 1 # 2 @@ -45,7 +43,7 @@ z ] # Captured outer environments that are referenced - environments [ ] + captures [ ] # Constants are an array or tuple. For named constants, use a tuple that begins with let # For a literal tuple, use (quote tuple), or 'tuple. Without names, constants must be indexed # from their number diff --git a/dsts/minimal.dsts b/dsttest/minimal.dsts similarity index 92% rename from dsts/minimal.dsts rename to dsttest/minimal.dsts index 62899eed..4c7d8d6c 100644 --- a/dsts/minimal.dsts +++ b/dsttest/minimal.dsts @@ -18,7 +18,7 @@ (return-nil) :extra - (push 2r1010101010101010) + (push 2) ] constants [ (def lookup "0123456789abcdef") diff --git a/include/dst/dst.h b/include/dst/dst.h index dbfa4d43..59889257 100644 --- a/include/dst/dst.h +++ b/include/dst/dst.h @@ -432,6 +432,11 @@ struct DstFuncDef { DstValue *constants; /* Contains strings, FuncDefs, etc. */ uint32_t *bytecode; + /* Various debug information */ + int32_t *sourcemap; + const uint8_t *source; + const uint8_t *sourcepath; + uint32_t flags; int32_t slotcount; /* The amount of stack space required for the function */ int32_t arity; /* Not including varargs */ @@ -543,6 +548,7 @@ int dst_string_equalconst(const uint8_t *lhs, const uint8_t *rhs, int32_t rlen, const uint8_t *dst_string_unique(const uint8_t *buf, int32_t len); const uint8_t *dst_cstring_unique(const char *s); const uint8_t *dst_description(DstValue x); +const uint8_t *dst_short_description(DstValue x); const uint8_t *dst_to_string(DstValue x); #define dst_cstringv(cstr) dst_wrap_string(dst_cstring(cstr)) const uint8_t *dst_formatc(const char *format, ...); @@ -608,10 +614,8 @@ typedef enum { typedef struct DstAssembleResult DstAssembleResult; typedef struct DstAssembleOptions DstAssembleOptions; struct DstAssembleResult { - union { - DstFuncDef *def; - const uint8_t *error; - } result; + DstFuncDef *funcdef; + const uint8_t *error; int32_t error_start; int32_t error_end; DstAssembleStatus status; @@ -623,6 +627,7 @@ struct DstAssembleOptions { }; DstAssembleResult dst_asm(DstAssembleOptions opts); DstFunction *dst_asm_func(DstAssembleResult result); +DstValue dst_disasm(DstFuncDef *def); /* Treat similar types through uniform interfaces for iteration */ int dst_seq_view(DstValue seq, const DstValue **data, int32_t *len); @@ -659,10 +664,8 @@ typedef enum { } DstParseStatus; typedef struct DstParseResult DstParseResult; struct DstParseResult { - union { - DstValue value; - const uint8_t *error; - } result; + DstValue value; + const uint8_t *error; const DstValue *map; int32_t bytes_read; DstParseStatus status; @@ -698,11 +701,12 @@ typedef struct DstCompileResults { typedef struct DstCompileOptions { uint32_t flags; const DstValue *sourcemap; - DstValue src; + DstValue source; } DstCompileOptions; /* Compile source code into FuncDef. */ DstCompileResults dst_compile(DstCompileOptions opts); +DstFunction *dst_compile_func(DstCompileResults results); /* GC */ diff --git a/unittests/asm_test.c b/unittests/asm_test.c index 1aa23c63..49064569 100644 --- a/unittests/asm_test.c +++ b/unittests/asm_test.c @@ -7,9 +7,7 @@ int main() { DstAssembleResult ares; DstFunction *func; - printf("sizeof(DstValue) = %lu\n", sizeof(DstValue)); - - FILE *f = fopen("./dsts/minimal.dsts", "rb"); + FILE *f = fopen("./dsttest/minimal.dsts", "rb"); fseek(f, 0, SEEK_END); long fsize = ftell(f); fseek(f, 0, SEEK_SET); //same as rewind(f); @@ -26,25 +24,27 @@ int main() { free(string); if (pres.status == DST_PARSE_ERROR) { - dst_puts(dst_formatc("parse error at %d: %S\n", pres.bytes_read, pres.result.error)); + dst_puts(dst_formatc("parse error at %d: %S\n", pres.bytes_read, pres.error)); return 1; } assert(pres.status == DST_PARSE_OK); - dst_puts(dst_formatc("\nparse result: %v\n\n", pres.result.value)); + dst_puts(dst_formatc("\nparse result: %v\n\n", pres.value)); opts.flags = 0; - opts.source = pres.result.value; + opts.source = pres.value; opts.sourcemap = pres.map; ares = dst_asm(opts); if (ares.status == DST_ASSEMBLE_ERROR) { - dst_puts(dst_formatc("assembly error: %S\n", ares.result.error)); + dst_puts(dst_formatc("assembly error: %S\n", ares.error)); dst_puts(dst_formatc("error location: %d, %d\n", ares.error_start, ares.error_end)); return 1; } assert(ares.status == DST_ASSEMBLE_OK); func = dst_asm_func(ares); + + dst_puts(dst_formatc("\nfuncdef: %v\n\n", dst_disasm(ares.funcdef))); dst_run(dst_wrap_function(func)); dst_puts(dst_formatc("result: %v\n", dst_vm_fiber->ret)); diff --git a/unittests/compile_test.c b/unittests/compile_test.c new file mode 100644 index 00000000..9e5c56be --- /dev/null +++ b/unittests/compile_test.c @@ -0,0 +1,55 @@ +#include "unit.h" +#include + +int main() { + DstParseResult pres; + DstCompileOptions opts; + DstCompileResults cres; + DstFunction *func; + + FILE *f = fopen("./dsttest/basic.dst", "rb"); + fseek(f, 0, SEEK_END); + long fsize = ftell(f); + fseek(f, 0, SEEK_SET); //same as rewind(f); + + char *string = malloc(fsize + 1); + fread(string, fsize, 1, f); + fclose(f); + + string[fsize] = 0; + + dst_init(); + + pres = dst_parsec(string); + free(string); + + if (pres.status == DST_PARSE_ERROR) { + dst_puts(dst_formatc("parse error at %d: %S\n", pres.bytes_read, pres.error)); + return 1; + } + assert(pres.status == DST_PARSE_OK); + dst_puts(dst_formatc("\nparse result: %v\n\n", pres.value)); + + opts.flags = 0; + opts.source = pres.value; + opts.sourcemap = pres.map; + + cres = dst_compile(opts); + if (cres.status == DST_COMPILE_ERROR) { + dst_puts(dst_formatc("compilation error: %S\n", cres.error)); + dst_puts(dst_formatc("error location: %d, %d\n", cres.error_start, cres.error_end)); + return 1; + } + assert(cres.status == DST_COMPILE_OK); + + dst_puts(dst_formatc("\nfuncdef: %v\n\n", dst_disasm(cres.funcdef))); + + func = dst_compile_func(cres); + + dst_run(dst_wrap_function(func)); + dst_puts(dst_formatc("result: %v\n", dst_vm_fiber->ret)); + + dst_deinit(); + + return 0; +} diff --git a/unittests/parse_test.c b/unittests/parse_test.c index be0e856d..818ee971 100644 --- a/unittests/parse_test.c +++ b/unittests/parse_test.c @@ -10,9 +10,9 @@ int main() { pres = dst_parsec("'(+ 1 () [] 3 5 :hello \"hi\\h41\")"); assert(pres.status == DST_PARSE_OK); - assert(dst_checktype(pres.result.value, DST_TUPLE)); + assert(dst_checktype(pres.value, DST_TUPLE)); - str = dst_to_string(pres.result.value); + str = dst_to_string(pres.value); printf("%.*s\n", dst_string_length(str), (const char *) str); return 0;