From 2d781ef21b7d82b90e1d86dd74d0da1b6e83f2ae Mon Sep 17 00:00:00 2001 From: bakpakin Date: Sat, 16 Dec 2017 01:17:53 -0500 Subject: [PATCH] Compiler is coming along. Work on Slot system and general compiler strategy. --- 3 | 230 ++++++++++++++++++ Makefile | 4 +- core/asm.c | 7 +- core/compile.c | 599 +++++++++++++++++++++++++++++++++------------- core/compile.h | 173 ++++++------- core/opcodes.h | 7 +- core/vm.c | 21 +- include/dst/dst.h | 28 ++- 8 files changed, 789 insertions(+), 280 deletions(-) create mode 100644 3 diff --git a/3 b/3 new file mode 100644 index 00000000..01a78d5b --- /dev/null +++ b/3 @@ -0,0 +1,230 @@ +/* +* 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 cee8dac6..8613d7b4 100644 --- a/Makefile +++ b/Makefile @@ -26,7 +26,7 @@ PREFIX?=/usr/local BINDIR=$(PREFIX)/bin VERSION=\"0.0.0-beta\" -CFLAGS=-std=c99 -Wall -Wextra -I./include -I./libs -g -DDST_VERSION=$(VERSION) +CFLAGS=-std=c99 -Wall -Wextra -Wfatal-errors -I./include -I./libs -g -DDST_VERSION=$(VERSION) PREFIX=/usr/local DST_TARGET=dst DST_XXD=xxd @@ -59,7 +59,7 @@ $(DST_XXD): libs/xxd.c ################################### DST_CORE_SOURCES=$(addprefix core/,\ - array.c asm.c buffer.c fiber.c func.c gc.c parse.c string.c strtod.c\ + array.c asm.c buffer.c compile.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)) diff --git a/core/asm.c b/core/asm.c index 131b5944..dde149d0 100644 --- a/core/asm.c +++ b/core/asm.c @@ -133,13 +133,16 @@ static const DstInstructionDef dst_ops[] = { {"jump-if", DIT_SL, DOP_JUMP_IF}, {"jump-if-not", DIT_SL, DOP_JUMP_IF_NOT}, {"less-than", DIT_SSS, DOP_LESS_THAN}, - {"load-boolean", DIT_S, DOP_LOAD_BOOLEAN}, {"load-constant", DIT_SC, DOP_LOAD_CONSTANT}, + {"load-false", DIT_S, DOP_LOAD_FALSE}, {"load-integer", DIT_SI, DOP_LOAD_INTEGER}, {"load-nil", DIT_S, DOP_LOAD_NIL}, + {"load-self", DIT_S, DOP_LOAD_SELF}, {"load-syscall", DIT_SU, DOP_LOAD_SYSCALL}, + {"load-true", DIT_S, DOP_LOAD_TRUE}, {"load-upvalue", DIT_SES, DOP_LOAD_UPVALUE}, - {"move", DIT_SS, DOP_MOVE}, + {"move-far", DIT_SS, DOP_MOVE_FAR}, + {"move-near", DIT_SS, DOP_MOVE_NEAR}, {"multiply", DIT_SSS, DOP_MULTIPLY}, {"multiply-immediate", DIT_SSI, DOP_MULTIPLY_IMMEDIATE}, {"multiply-integer", DIT_SSS, DOP_MULTIPLY_INTEGER}, diff --git a/core/compile.c b/core/compile.c index 460d0e5d..a86e5f3b 100644 --- a/core/compile.c +++ b/core/compile.c @@ -23,46 +23,54 @@ #include #include "compile.h" -static void dst_compile_cleanup(DstCompiler *c) { +/* Lazily sort the optimizers */ +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; } -DstSlot dst_compile_error(DstCompiler *c, const DstValue *sourcemap, const uint8_t *m) { - DstSlot ret; +/* 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 = m; - ret.flags = DST_SLOT_ERROR; - ret.index = 0; - ret.constant = dst_wrap_nil(); - return ret; + c->error = dst_wrap_string(m); + longjmp(c->on_error, 1); } -DstSlot dst_compile_cerror(DstCompiler *c, const DstValue *sourcemap, const char *m) { - return dst_compile_error(c, sourcemap, dst_cstring(m)); +/* Throw an error with a message in a cstring */ +void dst_compile_cerror(DstCompiler *c, const DstValue *sourcemap, const char *m) { + dst_compile_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. */ DstFormOptions dst_compile_getopts_index(DstFormOptions opts, int32_t index) { - DstCompiler *c = opts.compiler; const DstValue *sourcemap = dst_parse_submap_index(opts.sourcemap, index); DstValue nextval = dst_getindex(opts.x, index); opts.x = nextval; opts.sourcemap = sourcemap; return opts; } - DstFormOptions dst_compile_getopts_key(DstFormOptions opts, DstValue key) { - DstCompiler *c = opts.compiler; const DstValue *sourcemap = dst_parse_submap_key(opts.sourcemap, key); opts.x = key; opts.sourcemap = sourcemap; return opts; } - DstFormOptions dst_compile_getopts_value(DstFormOptions opts, DstValue key) { - DstCompiler *c = opts.compiler; const DstValue *sourcemap = dst_parse_submap_value(opts.sourcemap, key); DstValue nextval = dst_get(opts.x, key); opts.x = nextval; @@ -70,142 +78,152 @@ DstFormOptions dst_compile_getopts_value(DstFormOptions opts, DstValue key) { return opts; } -/* Eneter a new scope */ -void dst_compile_scope(DstCompiler *c, int newfn) { - DstScope *scope; - if (c->scopecap < c->scopecount) { - c->scopes = realloc(c->scopes, 2 * sizeof(DstScope) * c->scopecount + 2); - if (NULL == c->scope) { +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; } - scope = c->scopes + c->scopecount++; + /* 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; + int32_t newlevel, oldlevel; + DstScope *scope; + oldcount = c->scopecount; + newcount = oldcount + 1; + oldlevel = c->scopecount + ? c->scopes[c->scopecount - 1].level + : 0; + newlevel = oldlevel + newfn; + if (newcount < c->scopecap) { + int32_t newcap = 2 * newcount; + c->scopes = realloc(c->scopes, newcap * sizeof(DstScope)); + if (NULL == c->scopes) { + DST_OUT_OF_MEMORY; + } + c->scopecap = newcap; + } + scope = c->scopes + oldcount; + c->scopecount = newcount; dst_array_init(&scope->constants, 0); dst_table_init(&scope->symbols, 4); + dst_table_init(&scope->constantrev, 4); scope->envs = NULL; scope->envcount = 0; scope->envcap = 0; + + scope->bytecode_start = c->buffercount; - scope->slots = NULL; - scope->slotcount = 0; - scope->slotcap = 0; + dst_compile_slotpool_init(&scope->slots); + dst_compile_slotpool_init(&scope->unorderedslots); - scope->freeslots = NULL; - scope->freeslotcount = 0; - scope->freeslotcap = 0; - - scope->buffer_offset = c->buffer.count; - scope->nextslot = 0; - scope->lastslot = -1; + scope->level = newlevel; scope->flags = newfn ? DST_SCOPE_FUNCTION : 0; } -DstSlot dst_slot_nil() { - DstSlot ret; - ret.index = 0; - ret.flags = (1 << DST_TYPE_NIL) | DST_SLOT_CONSTANT; - ret.constant = dst_wrap_nil(); - return ret; -} - -/* Leave a scope. Does not build closure*/ +/* Leave a scope. */ void dst_compile_popscope(DstCompiler *c) { DstScope *scope; - DstSlot ret; dst_assert(c->scopecount, "could not pop scope"); scope = c->scopes + --c->scopecount; - /* Move free slots to parent scope if not a new function */ + /* Move free slots to parent scope if not a new function. + * We need to know the total number of slots used when compiling the function. */ if (!(scope->flags & DST_SCOPE_FUNCTION) && c->scopecount) { - int32_t i; - int32_t newcount; - DstScope *topscope = c->scopes + c->scopecount - 1; - topscope->nextslot = scope->nextslot; - newcount = topscope->freeslotcount + scope->freeslotcount; - if (topscope->freeslotcap < newcount) { - topscope->freeslots = realloc(topscope->freeslot, sizeof(int32_t) * newcount); - if (NULL == topscope->freeslots) { - DST_OUT_OF_MEMORY; - } - topscope->freeslotcap = newcount; - } - memcpy( - topscope->freeslots + topescope->freeslotcount, - scope->freeslots, - sizeof(int32_t) * scope->freeslotcount); - topscope->freeslotcount = newcount; + DstScope *newscope = dst_compile_topscope(c); + dst_compile_slotpool_extend(&newscope->slots, scope->slots.count); } dst_table_deinit(&scope->symbols); + dst_table_deinit(&scope->constantrev); dst_array_deinit(&scope->constants); - free(scope->slots); - free(scope->freeslots); + dst_compile_slotpool_deinit(&scope->slots); + dst_compile_slotpool_deinit(&scope->unorderedslots); free(scope->envs); - return ret; } -#define dst_compile_topscope(c) ((c)->scopes + (c)->scopecount - 1) - -/* Allocate a slot space */ -static int32_t dst_compile_slotalloc(DstCompiler *c) { +DstSlot *dst_compile_constantslot(DstCompiler *c, DstValue x) { DstScope *scope = dst_compile_topscope(c); - if (scope->freeslotcount == 0) { - return scope->nextslot++; - } else { - return scope->freeslots[--scope->freeslotcount]; - } -} - -int dst_compile_slotmatch(DstFormOptions opts, DstSlot slot) { - return opts.type & slot.type; -} - -DstSlot dst_compile_normalslot(DstCompiler *c, uint32_t flags) { - DstSlot ret; - int32_t index = dst_compile_slotalloc(c); - ret.flags = flags; - ret.constant = dst_wrap_nil(); - ret.index = index; - ret.envindex = 0; - return ret; -} - -DstSlot dst_compile_constantslot(DstCompiler *c, DstValue x) { - DstSlot ret; - ret.flags = (1 << dst_type(x)) | DST_SLOT_CONSTANT; - ret.index = -1; - ret.constant = x; - ret.envindex = 0; + DstSlot *ret = dst_compile_slotpool_alloc(&scope->unorderedslots); + ret->flags = (1 << dst_type(x)) | DST_SLOT_CONSTANT | DST_SLOT_NOTEMPTY; + ret->index = -1; + ret->constant = x; + ret->envindex = scope->level; return ret; } /* Free a single slot */ -void dst_compile_freeslot(DstCompiler *c, DstSlot slot) { +void dst_compile_freeslot(DstCompiler *c, DstSlot *slot) { DstScope *scope = dst_compile_topscope(c); - int32_t newcount = scope->freeslotcount + 1; - if (slot.flags & (DST_SLOT_CONSTANT | DST_SLOT_ERROR)) + if (slot->flags & (DST_SLOT_CONSTANT)) { return; - if (scope->freeslotcap < newcount) { - int32_t newcap = 2 * newcount; - scope->freeslots = realloc(scope->freeslots, sizeof(int32_t) * newcap); - if (NULL == scope->freeslots) { - DST_OUT_OF_MEMORY; - } - scope->freeslotcap = newcap; } - scope->freeslots[scope->freeslotcount] = slot.index; - scope->freeslotcount = newcount; -} - -/* Free an array of slots */ -void dst_compile_freeslotarray(DstCompiler *c, DstArray *slots) { - int32_t i; - for (i = 0; i < slots->count; i++) { - dst_compile_freeslot(c, slots->data[i]); + if (slot->envindex != 0) { + return; } + dst_compile_slotpool_free(&scope->slots, slot); } /* - * The mechanism for passing environments to to closures is a bit complicated, + * The mechanism for passing environments to closures is a bit complicated, * but ensures a few properties. * * Environments are on the stack unless they need to be closurized * * Environments can be shared between closures @@ -223,38 +241,39 @@ void dst_compile_freeslotarray(DstCompiler *c, DstArray *slots) { */ /* Allow searching for symbols. Return information about the symbol */ -DstSlot dst_compile_resolve( +DstSlot *dst_compile_resolve( DstCompiler *c, const DstValue *sourcemap, const uint8_t *sym) { - DstSlot ret; + DstSlot *ret = NULL; DstScope *scope = dst_compile_topscope(c); int32_t env_index = 0; - int foundlocal; + int foundlocal = 1; /* Search scopes for symbol, starting from top */ while (scope >= c->scopes) { - DstValue check = dst_table_get(scope->symbols, dst_wrap_symbol(sym)); - if (dst_checktype(check, DST_INTEGER)) { - ret = scope->slots[dst_unwrap_integer(check)]; + DstValue check = dst_table_get(&scope->symbols, dst_wrap_symbol(sym)); + if (dst_checktype(check, DST_USERDATA)) { + ret = dst_unwrap_pointer(check); goto found; } scope--; + if (scope->flags & DST_SCOPE_FUNCTION) + foundlocal = 0; } /* Symbol not found */ - return dst_compile_error(c, sourcemap, dst_formatc("unknown symbol %q", sym)); + dst_compile_error(c, sourcemap, dst_formatc("unknown symbol %q", sym)); /* Symbol was found */ found: - /* Constants and errors can be returned immediately (they are stateless) */ - if (ret.flags & (DST_SLOT_CONSTANT | DST_SLOT_ERROR)) + /* Constants can be returned immediately (they are stateless) */ + if (ret->flags & DST_SLOT_CONSTANT) return ret; /* non-local scope needs to expose its environment */ - foundlocal = scope == dst_compile_topscope(c); if (!foundlocal) { scope->flags |= DST_SCOPE_ENV; if (scope->envcount < 1) { @@ -264,61 +283,86 @@ DstSlot dst_compile_resolve( DST_OUT_OF_MEMORY; } scope->envcap = 10; - scope->envs[0] = -1; + scope->envs[0] = 0; } scope++; } /* Propogate env up to current scope */ while (scope <= dst_compile_topscope(c)) { - int32_t j; - int32_t newcount = scope->envcount + 1; - int scopefound = 0; - /* Check if scope already has env. If so, break */ - for (j = 1; j < scope->envcount; j++) { - if (scope->envs[j] == env_index) { - scopefound = 1; - env_index = j; - break; - } - } - if (!scopefound) { - env_index = scope->envcount; - /* Ensure capacity for adding scope */ - if (newcount > scope->envcap) { - int32_t newcap = 2 * newcount; - scope->envs = realloc(scope->envs, sizeof(int32_t) * newcap); - if (NULL == scope->envs) { - DST_OUT_OF_MEMORY; + if (scope->flags & DST_SCOPE_FUNCTION) { + int32_t j; + int32_t newcount = scope->envcount + 1; + int scopefound = 0; + /* Check if scope already has env. If so, break */ + for (j = 1; j < scope->envcount; j++) { + if (scope->envs[j] == env_index) { + scopefound = 1; + env_index = j; + break; } - scope->envcap = newcap; } - scope->envs[scope->envcount] = env_index; - scope->envcount = newcount; + if (!scopefound) { + env_index = scope->envcount; + /* Ensure capacity for adding scope */ + if (newcount > scope->envcap) { + int32_t newcap = 2 * newcount; + scope->envs = realloc(scope->envs, sizeof(int32_t) * newcap); + if (NULL == scope->envs) { + DST_OUT_OF_MEMORY; + } + scope->envcap = newcap; + } + scope->envs[scope->envcount] = env_index; + scope->envcount = newcount; + } } scope++; } - - /* Take the slot from the upper scope, and set its envindex before returning. */ + + /* Store in the unordered slots so we don't modify the original slot. */ if (!foundlocal) { - ret.envindex = env_index; + DstSlot *newret = dst_compile_slotpool_alloc(&scope->unorderedslots); + *newret = *ret; + newret->envindex = env_index; + ret = newret; } 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; +DstSlot *dst_compile_value(DstFormOptions opts) { + DstSlot *ret; if (opts.compiler->recursion_guard <= 0) { - return dst_compiler_cerror(opts.compiler, opts.sourcemap, "recursed too deeply"); + 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.x); + ret = dst_compile_constantslot(opts.compiler, opts.x); break; case DST_SYMBOL: { @@ -326,28 +370,241 @@ DstSlot dst_compile_value(DstFormOptions opts) { if (dst_string_length(sym) > 0 && sym[0] != ':') ret = dst_compile_resolve(opts.compiler, opts.sourcemap, sym); else - ret = dst_compile_constantslot(opts.x); + 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; + /*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; } -DstSlot dst_compile_targetslot(DstFormOptions opts, DstSlot s); +/* 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->mapbuffer = realloc(c->mapbuffer, newcap * sizeof(int32_t) * 2); + if (NULL == c->buffer || NULL == c->mapbuffer) { + DST_OUT_OF_MEMORY; + } + c->buffercap = newcap; + } + 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->buffer[index] = instr; +} -/* 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); +/* Represents a local slot - not a constant, and within a specified range. Also + * contains if it corresponds to a real slot. If temp, then the slot index + * should be free right after use */ +typedef struct DstLocalSlot DstLocalSlot; +struct DstLocalSlot { + DstSlot *orig; + int temp; + int dirty; + int32_t index; +}; + +/* Get the index of a constant */ +static int32_t dst_compile_constant_index(DstCompiler *c, const DstValue *sourcemap, DstValue x) { + DstScope *scope = dst_compile_topscope(c); + DstValue check; + int32_t count = scope->constants.count; + check = dst_table_get(&scope->constantrev, x); + if (dst_checktype(check, DST_INTEGER)) { + return dst_unwrap_integer(check); + } + if (count >= 0xFFFF) { + dst_compile_cerror(c, sourcemap, "too many constants"); + } + dst_array_push(&scope->constants, x); + dst_table_put(&scope->constantrev, x, dst_wrap_integer(count)); + return count; +} + +/* Realize any slot to a local slot. Call this to get a slot index + * that can be used in an instruction. */ +static DstLocalSlot dst_compile_slot_pre( + DstCompiler *c, + const DstValue *sourcemap, + int32_t max, + int32_t hint, + int isdest, + int nth, + DstSlot *s) { + + DstScope *scope = dst_compile_topscope(c); + DstLocalSlot ret; + ret.orig = s; + ret.dirty = isdest; + ret.temp = 0; + + if (s->flags & DST_SLOT_CONSTANT) { + int32_t cindex; + int32_t nextfree = dst_compile_slotpool_alloc(&scope->slots)->index; + if (hint >= 0 && hint <= 0xFF) { + ret.index = hint; + } else if (nextfree >= 0xF0) { + ret.index = 0xF0 + nth; + dst_compile_slotpool_freeindex(&scope->slots, nextfree); + } else { + ret.temp = 1; + ret.index = nextfree; + } + /* Use instructions for loading certain constants */ + switch (dst_type(s->constant)) { + case DST_NIL: + dst_compile_emit(c, sourcemap, ((uint32_t)(ret.index) << 8) | DOP_LOAD_NIL); + break; + case DST_TRUE: + dst_compile_emit(c, sourcemap, ((uint32_t)(ret.index) << 8) | DOP_LOAD_TRUE); + break; + case DST_FALSE: + dst_compile_emit(c, sourcemap, ((uint32_t)(ret.index) << 8) | DOP_LOAD_FALSE); + break; + case DST_INTEGER: + { + int32_t i = dst_unwrap_integer(s->constant); + if (i <= INT16_MAX && i >= INT16_MIN) { + dst_compile_emit(c, sourcemap, + ((uint32_t)i << 16) | + ((uint32_t)(ret.index) << 8) | + DOP_LOAD_INTEGER); + break; + } + /* fallthrough */ + } + default: + cindex = dst_compile_constant_index(c, sourcemap, s->constant); + if (isdest) + dst_compile_cerror(c, sourcemap, "cannot write to a constant"); + dst_compile_emit(c, sourcemap, + ((uint32_t)cindex << 16) | + ((uint32_t)(ret.index) << 8) | + DOP_LOAD_CONSTANT); + break; + } + } else if (s->envindex > 0 || s->index > max) { + /* Get a local slot to shadow the environment or far slot */ + int32_t nextfree = dst_compile_slotpool_alloc(&scope->slots)->index; + if (hint >= 0 && hint <= 0xFF) { + ret.index = hint; + } else if (nextfree >= 0xF0) { + ret.index = 0xF0 + nth; + dst_compile_slotpool_freeindex(&scope->slots, nextfree); + } else { + ret.temp = 1; + ret.index = nextfree; + } + if (!isdest) { + /* Move the remote slot into the local space */ + if (s->envindex > 0) { + /* Load the higher slot */ + dst_compile_emit(c, sourcemap, + ((uint32_t)(s->index) << 24) | + ((uint32_t)(s->envindex) << 16) | + ((uint32_t)(ret.index) << 8) | + DOP_LOAD_UPVALUE); + } else { + /* Slot is a far slot: greater than 0xFF. Get + * the far data and bring it to the near slot. */ + dst_compile_emit(c, sourcemap, + ((uint32_t)(s->index) << 16) | + ((uint32_t)(ret.index) << 8) | + DOP_MOVE_NEAR); + } + } + } else if (hint >= 0 && hint <= 0xFF && isdest) { + ret.index = hint; + } else { + /* We have a normal slot that fits in the required bit width */ + ret.index = s->index; + } + return ret; +} + +/* Call this on a DstLocalSlot to free the slot or sync any changes + * made after the instruction has been emitted. */ +static void dst_compile_slot_post( + DstCompiler *c, + const DstValue *sourcemap, + DstLocalSlot ls) { + DstSlot *s = ls.orig; + DstScope *scope = dst_compile_topscope(c); + if (ls.temp) + dst_compile_slotpool_freeindex(&scope->slots, ls.index); + if (ls.dirty) { + /* We need to save the data in the local slot to the original slot */ + if (s->envindex > 0) { + /* Load the higher slot */ + dst_compile_emit(c, sourcemap, + ((uint32_t)(s->index) << 24) | + ((uint32_t)(s->envindex) << 16) | + ((uint32_t)(ls.index) << 8) | + DOP_SET_UPVALUE); + } else if (s->index != ls.index) { + /* There was a local remapping */ + dst_compile_emit(c, sourcemap, + ((uint32_t)(s->index) << 16) | + ((uint32_t)(ls.index) << 8) | + DOP_MOVE_FAR); + } + } +} + +static void dst_compile_pop_funcdef(DstCompiler *c) { + DstScope *scope = dst_compiler_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->constants_length = 0; + def->bytecode_length = 0; + def->environments_length = 1; +} + +DstCompileResults dst_compile(DstCompileOptions opts) { + DstCompiler c; + + if (setjmp(c.on_error)) { + c.results.status = DST_COMPILE_ERROR; + dst_compile_cleanup(&c); + results.funcdef = NULL; + return c.results; + } + + /* Initialize the compiler struct */ + c.scopecount = 0; + c.scopecap = 0; + c.scopes = NULL; + c.buffercap = 0; + c.buffercount = 0; + c->buffer = NULL; + c->mapbuffer; + c->recursion_guard = 1024; + + +} diff --git a/core/compile.h b/core/compile.h index 15a2865e..4788ffdc 100644 --- a/core/compile.h +++ b/core/compile.h @@ -24,20 +24,24 @@ #define DST_COMPILE_H #include +#include +#include "opcodes.h" /* Compiler typedefs */ typedef struct DstCompiler DstCompiler; typedef struct FormOptions FormOptions; typedef struct SlotTracker SlotTracker; typedef struct DstScope DstScope; +typedef struct DstSlot DstSlot; +typedef struct DstFormOptions DstFormOptions; typedef struct DstCFunctionOptimizer DstCFunctionOptimizer; #define DST_SLOT_CONSTANT 0x10000 -#define DST_SLOT_TEMP 0x20000 +#define DST_SLOT_NAMED 0x20000 #define DST_SLOT_RETURNED 0x40000 #define DST_SLOT_NIL 0x80000 #define DST_SLOT_MUTABLE 0x100000 -#define DST_SLOT_ERROR 0x200000 +#define DST_SLOT_NOTEMPTY 0x200000 #define DST_SLOTTYPE_ANY 0xFFFF @@ -47,7 +51,7 @@ struct DstSlot { 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 */ @@ -62,67 +66,59 @@ struct DstSlot { * 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 +#define DST_SCOPE_ENV 8 + +/* Hold a bunch of slots together */ +typedef struct DstSlotPool DstSlotPool; +struct DstSlotPool { + DstSlot *s; + int32_t count; + int32_t cap; + int32_t free; +}; /* A lexical scope during compilation */ struct DstScope { + int32_t level; DstArray constants; /* Constants for the funcdef */ - DstTable symbols; /* Map symbols -> Slot inidices */ + DstTable constantrev; /* Map constants -> constant inidices */ + DstTable symbols; /* Map symbols -> Slot pointers */ /* Hold all slots in use. Data structures that store * slots should link them to this datatstructure */ - DstSlot *slots; - int32_t slotcount; - int32_t slotcap; + DstSlotPool slots; + DstSlotPool unorderedslots; - /* 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 + /* Referenced closure environents. 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 */ - + int32_t bytecode_start; uint32_t flags; -} +}; + +#define dst_compile_topscope(c) ((c)->scopes + (c)->scopecount - 1) /* Compilation state */ struct DstCompiler { + jmp_buf on_error; + int recursion_guard; 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; + + int32_t buffercap; + int32_t buffercount; + uint32_t *buffer; + int32_t (*mapbuffer)[2]; + + DstCompileResults results; }; #define DST_FOPTS_TAIL 0x10000 @@ -136,58 +132,48 @@ struct DstFormOptions { 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; +/* 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. */ +struct DstCFunctionOptimizer { + DstCFunction cfun; + DstSlot (*optimize)(DstFormOptions opts, int32_t argn, const DstValue *argv); }; +typedef struct DstSpecial { + const char *name; + DstSlot (*compile)(DstFormOptions opts, int32_t argn, const DstValue *argv); +} DstSpecial; -/* Compiler handlers. Used to compile different kinds of expressions. */ -typedef DstSlot (*DstFormCompiler)(DstFormOptions opts); +/* An array of optimizers sorted by key */ +extern DstCFunctionOptimizer dst_compiler_optimizers[255]; + +/* An array of special forms */ +extern DstSpecial dst_compiler_specials[16]; + +void dst_compile_slotpool_init(DstSlotPool *pool); +void dst_compile_slotpool_deinit(DstSlotPool *pool); +DstSlot *dst_compile_slotpool_alloc(DstSlotPool *pool); +void dst_compile_slotpool_extend(DstSlotPool *pool, int32_t extra); +void dst_compile_slotpool_free(DstSlotPool *pool, DstSlot *s); +void dst_compile_slotpool_freeindex(DstSlotPool *pool, int32_t index); /* 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); +DstSlot *dst_compile_value(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_do(DstFormOptions opts, int32_t argn, const DstValue *argv); +DstSlot *dst_compile_fn(DstFormOptions opts, int32_t argn, const DstValue *argv); +DstSlot *dst_compile_cond(DstFormOptions opts, int32_t argn, const DstValue *argv); +DstSlot *dst_compile_while(DstFormOptions opts, int32_t argn, const DstValue *argv); +DstSlot *dst_compile_quote(DstFormOptions opts, int32_t argn, const DstValue *argv); +DstSlot *dst_compile_def(DstFormOptions opts, int32_t argn, const DstValue *argv); +DstSlot *dst_compile_var(DstFormOptions opts, int32_t argn, const DstValue *argv); +DstSlot *dst_compile_varset(DstFormOptions opts, int32_t argn, const DstValue *argv); /****************************************************/ -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); +void dst_compile_error(DstCompiler *c, const DstValue *sourcemap, const uint8_t *m); +void 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. */ @@ -196,25 +182,16 @@ 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); +void 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); +DstSlot *dst_compile_constantslot(DstCompiler *c, DstValue x); +void dst_compile_freeslot(DstCompiler *c, DstSlot *slot); /* Search for a symbol */ -DstSlot dst_compile_resolve(DstCompiler *c, const DstValue *sourcemap, const uint8_t *sym); +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); +/* Emit instructions. */ -/* 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); +void dst_compile_emit(DstCompiler *c, const DstValue *sourcemap, uint32_t instr); #endif diff --git a/core/opcodes.h b/core/opcodes.h index a029b183..5da5a30b 100644 --- a/core/opcodes.h +++ b/core/opcodes.h @@ -55,7 +55,8 @@ enum DstOpCode { DOP_SHIFT_RIGHT_IMMEDIATE, DOP_SHIFT_RIGHT_UNSIGNED, DOP_SHIFT_RIGHT_UNSIGNED_IMMEDIATE, - DOP_MOVE, + DOP_MOVE_FAR, + DOP_MOVE_NEAR, DOP_JUMP, DOP_JUMP_IF, DOP_JUMP_IF_NOT, @@ -64,9 +65,11 @@ enum DstOpCode { DOP_EQUALS, DOP_COMPARE, DOP_LOAD_NIL, - DOP_LOAD_BOOLEAN, + DOP_LOAD_TRUE, + DOP_LOAD_FALSE, DOP_LOAD_INTEGER, DOP_LOAD_CONSTANT, + DOP_LOAD_SELF, DOP_LOAD_UPVALUE, DOP_SET_UPVALUE, DOP_CLOSURE, diff --git a/core/vm.c b/core/vm.c index 0032f101..d45faffd 100644 --- a/core/vm.c +++ b/core/vm.c @@ -280,11 +280,16 @@ int dst_continue() { pc++; vm_next(); - case DOP_MOVE: + case DOP_MOVE_NEAR: stack[oparg(1, 0xFF)] = stack[oparg(2, 0xFFFF)]; pc++; vm_next(); + case DOP_MOVE_FAR: + stack[oparg(2, 0xFFFF)] = stack[oparg(1, 0xFF)]; + pc++; + vm_next(); + case DOP_JUMP: pc += (*(int32_t *)pc) >> 8; vm_next(); @@ -342,8 +347,13 @@ int dst_continue() { pc++; vm_next(); - case DOP_LOAD_BOOLEAN: - stack[oparg(1, 0xFF)] = dst_wrap_boolean(oparg(2, 0xFFFF)); + case DOP_LOAD_TRUE: + stack[oparg(1, 0xFFFFFF)] = dst_wrap_boolean(1); + pc++; + vm_next(); + + case DOP_LOAD_FALSE: + stack[oparg(1, 0xFFFFFF)] = dst_wrap_boolean(0); pc++; vm_next(); @@ -358,6 +368,11 @@ int dst_continue() { pc++; vm_next(); + case DOP_LOAD_SELF: + stack[oparg(1, 0xFFFFFF)] = dst_wrap_function(func); + pc++; + vm_next(); + case DOP_LOAD_UPVALUE: { int32_t eindex = oparg(2, 0xFF); diff --git a/include/dst/dst.h b/include/dst/dst.h index 3b674e03..dbfa4d43 100644 --- a/include/dst/dst.h +++ b/include/dst/dst.h @@ -20,8 +20,8 @@ * IN THE SOFTWARE. */ -#ifndef DST_NANBOX_H_defined -#define DST_NANBOX_H_defined +#ifndef DST_H_defined +#define DST_H_defined #include #include @@ -680,6 +680,30 @@ int dst_continue(); int dst_run(DstValue callee); DstValue dst_transfer(DstFiber *fiber, DstValue x); +/* Compile */ +typedef enum DstCompileStatus { + DST_COMPILE_OK, + DST_COMPILE_ERROR +} DstCompileStatus; + +/* Results of compilation */ +typedef struct DstCompileResults { + DstCompileStatus status; + DstFuncDef *funcdef; + const uint8_t *error; + int32_t error_start; + int32_t error_end; +} DstCompileResults; + +typedef struct DstCompileOptions { + uint32_t flags; + const DstValue *sourcemap; + DstValue src; +} DstCompileOptions; + +/* Compile source code into FuncDef. */ +DstCompileResults dst_compile(DstCompileOptions opts); + /* GC */ /* The metadata header associated with an allocated block of memory */