mirror of
https://github.com/janet-lang/janet
synced 2024-11-28 11:09:54 +00:00
Compiler is coming along. Work on Slot system and general compiler strategy.
This commit is contained in:
parent
1293d2e301
commit
2d781ef21b
230
3
Normal file
230
3
Normal file
@ -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 <dst/dst.h>
|
||||||
|
#include <setjmp.h>
|
||||||
|
|
||||||
|
/* 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
|
4
Makefile
4
Makefile
@ -26,7 +26,7 @@ PREFIX?=/usr/local
|
|||||||
BINDIR=$(PREFIX)/bin
|
BINDIR=$(PREFIX)/bin
|
||||||
VERSION=\"0.0.0-beta\"
|
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
|
PREFIX=/usr/local
|
||||||
DST_TARGET=dst
|
DST_TARGET=dst
|
||||||
DST_XXD=xxd
|
DST_XXD=xxd
|
||||||
@ -59,7 +59,7 @@ $(DST_XXD): libs/xxd.c
|
|||||||
###################################
|
###################################
|
||||||
|
|
||||||
DST_CORE_SOURCES=$(addprefix core/,\
|
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\
|
struct.c symcache.c syscalls.c table.c tuple.c userdata.c util.c\
|
||||||
value.c vm.c wrap.c)
|
value.c vm.c wrap.c)
|
||||||
DST_CORE_OBJECTS=$(patsubst %.c,%.o,$(DST_CORE_SOURCES))
|
DST_CORE_OBJECTS=$(patsubst %.c,%.o,$(DST_CORE_SOURCES))
|
||||||
|
@ -133,13 +133,16 @@ static const DstInstructionDef dst_ops[] = {
|
|||||||
{"jump-if", DIT_SL, DOP_JUMP_IF},
|
{"jump-if", DIT_SL, DOP_JUMP_IF},
|
||||||
{"jump-if-not", DIT_SL, DOP_JUMP_IF_NOT},
|
{"jump-if-not", DIT_SL, DOP_JUMP_IF_NOT},
|
||||||
{"less-than", DIT_SSS, DOP_LESS_THAN},
|
{"less-than", DIT_SSS, DOP_LESS_THAN},
|
||||||
{"load-boolean", DIT_S, DOP_LOAD_BOOLEAN},
|
|
||||||
{"load-constant", DIT_SC, DOP_LOAD_CONSTANT},
|
{"load-constant", DIT_SC, DOP_LOAD_CONSTANT},
|
||||||
|
{"load-false", DIT_S, DOP_LOAD_FALSE},
|
||||||
{"load-integer", DIT_SI, DOP_LOAD_INTEGER},
|
{"load-integer", DIT_SI, DOP_LOAD_INTEGER},
|
||||||
{"load-nil", DIT_S, DOP_LOAD_NIL},
|
{"load-nil", DIT_S, DOP_LOAD_NIL},
|
||||||
|
{"load-self", DIT_S, DOP_LOAD_SELF},
|
||||||
{"load-syscall", DIT_SU, DOP_LOAD_SYSCALL},
|
{"load-syscall", DIT_SU, DOP_LOAD_SYSCALL},
|
||||||
|
{"load-true", DIT_S, DOP_LOAD_TRUE},
|
||||||
{"load-upvalue", DIT_SES, DOP_LOAD_UPVALUE},
|
{"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", DIT_SSS, DOP_MULTIPLY},
|
||||||
{"multiply-immediate", DIT_SSI, DOP_MULTIPLY_IMMEDIATE},
|
{"multiply-immediate", DIT_SSI, DOP_MULTIPLY_IMMEDIATE},
|
||||||
{"multiply-integer", DIT_SSS, DOP_MULTIPLY_INTEGER},
|
{"multiply-integer", DIT_SSS, DOP_MULTIPLY_INTEGER},
|
||||||
|
595
core/compile.c
595
core/compile.c
@ -23,46 +23,54 @@
|
|||||||
#include <dst/dst.h>
|
#include <dst/dst.h>
|
||||||
#include "compile.h"
|
#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) {
|
/* Throw an error with a dst string */
|
||||||
DstSlot ret;
|
void dst_compile_error(DstCompiler *c, const DstValue *sourcemap, const uint8_t *m) {
|
||||||
c->error_start = dst_unwrap_integer(sourcemap[0]);
|
c->error_start = dst_unwrap_integer(sourcemap[0]);
|
||||||
c->error_end = dst_unwrap_integer(sourcemap[1]);
|
c->error_end = dst_unwrap_integer(sourcemap[1]);
|
||||||
c->error = m;
|
c->error = dst_wrap_string(m);
|
||||||
ret.flags = DST_SLOT_ERROR;
|
longjmp(c->on_error, 1);
|
||||||
ret.index = 0;
|
|
||||||
ret.constant = dst_wrap_nil();
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DstSlot dst_compile_cerror(DstCompiler *c, const DstValue *sourcemap, const char *m) {
|
/* Throw an error with a message in a cstring */
|
||||||
return dst_compile_error(c, sourcemap, dst_cstring(m));
|
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
|
/* Use these to get sub options. They will traverse the source map so
|
||||||
* compiler errors make sense. Then modify the returned options. */
|
* compiler errors make sense. Then modify the returned options. */
|
||||||
DstFormOptions dst_compile_getopts_index(DstFormOptions opts, int32_t index) {
|
DstFormOptions dst_compile_getopts_index(DstFormOptions opts, int32_t index) {
|
||||||
DstCompiler *c = opts.compiler;
|
|
||||||
const DstValue *sourcemap = dst_parse_submap_index(opts.sourcemap, index);
|
const DstValue *sourcemap = dst_parse_submap_index(opts.sourcemap, index);
|
||||||
DstValue nextval = dst_getindex(opts.x, index);
|
DstValue nextval = dst_getindex(opts.x, index);
|
||||||
opts.x = nextval;
|
opts.x = nextval;
|
||||||
opts.sourcemap = sourcemap;
|
opts.sourcemap = sourcemap;
|
||||||
return opts;
|
return opts;
|
||||||
}
|
}
|
||||||
|
|
||||||
DstFormOptions dst_compile_getopts_key(DstFormOptions opts, DstValue key) {
|
DstFormOptions dst_compile_getopts_key(DstFormOptions opts, DstValue key) {
|
||||||
DstCompiler *c = opts.compiler;
|
|
||||||
const DstValue *sourcemap = dst_parse_submap_key(opts.sourcemap, key);
|
const DstValue *sourcemap = dst_parse_submap_key(opts.sourcemap, key);
|
||||||
opts.x = key;
|
opts.x = key;
|
||||||
opts.sourcemap = sourcemap;
|
opts.sourcemap = sourcemap;
|
||||||
return opts;
|
return opts;
|
||||||
}
|
}
|
||||||
|
|
||||||
DstFormOptions dst_compile_getopts_value(DstFormOptions opts, DstValue key) {
|
DstFormOptions dst_compile_getopts_value(DstFormOptions opts, DstValue key) {
|
||||||
DstCompiler *c = opts.compiler;
|
|
||||||
const DstValue *sourcemap = dst_parse_submap_value(opts.sourcemap, key);
|
const DstValue *sourcemap = dst_parse_submap_value(opts.sourcemap, key);
|
||||||
DstValue nextval = dst_get(opts.x, key);
|
DstValue nextval = dst_get(opts.x, key);
|
||||||
opts.x = nextval;
|
opts.x = nextval;
|
||||||
@ -70,142 +78,152 @@ DstFormOptions dst_compile_getopts_value(DstFormOptions opts, DstValue key) {
|
|||||||
return opts;
|
return opts;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Eneter a new scope */
|
void dst_compile_slotpool_init(DstSlotPool *pool) {
|
||||||
void dst_compile_scope(DstCompiler *c, int newfn) {
|
pool->s = NULL;
|
||||||
DstScope *scope;
|
pool->count = 0;
|
||||||
if (c->scopecap < c->scopecount) {
|
pool->free = 0;
|
||||||
c->scopes = realloc(c->scopes, 2 * sizeof(DstScope) * c->scopecount + 2);
|
pool->cap = 0;
|
||||||
if (NULL == c->scope) {
|
}
|
||||||
|
|
||||||
|
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;
|
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_array_init(&scope->constants, 0);
|
||||||
dst_table_init(&scope->symbols, 4);
|
dst_table_init(&scope->symbols, 4);
|
||||||
|
dst_table_init(&scope->constantrev, 4);
|
||||||
|
|
||||||
scope->envs = NULL;
|
scope->envs = NULL;
|
||||||
scope->envcount = 0;
|
scope->envcount = 0;
|
||||||
scope->envcap = 0;
|
scope->envcap = 0;
|
||||||
|
|
||||||
scope->slots = NULL;
|
scope->bytecode_start = c->buffercount;
|
||||||
scope->slotcount = 0;
|
|
||||||
scope->slotcap = 0;
|
|
||||||
|
|
||||||
scope->freeslots = NULL;
|
dst_compile_slotpool_init(&scope->slots);
|
||||||
scope->freeslotcount = 0;
|
dst_compile_slotpool_init(&scope->unorderedslots);
|
||||||
scope->freeslotcap = 0;
|
|
||||||
|
|
||||||
scope->buffer_offset = c->buffer.count;
|
scope->level = newlevel;
|
||||||
scope->nextslot = 0;
|
|
||||||
scope->lastslot = -1;
|
|
||||||
scope->flags = newfn ? DST_SCOPE_FUNCTION : 0;
|
scope->flags = newfn ? DST_SCOPE_FUNCTION : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
DstSlot dst_slot_nil() {
|
/* Leave a scope. */
|
||||||
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*/
|
|
||||||
void dst_compile_popscope(DstCompiler *c) {
|
void dst_compile_popscope(DstCompiler *c) {
|
||||||
DstScope *scope;
|
DstScope *scope;
|
||||||
DstSlot ret;
|
|
||||||
dst_assert(c->scopecount, "could not pop scope");
|
dst_assert(c->scopecount, "could not pop scope");
|
||||||
scope = c->scopes + --c->scopecount;
|
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) {
|
if (!(scope->flags & DST_SCOPE_FUNCTION) && c->scopecount) {
|
||||||
int32_t i;
|
DstScope *newscope = dst_compile_topscope(c);
|
||||||
int32_t newcount;
|
dst_compile_slotpool_extend(&newscope->slots, scope->slots.count);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
dst_table_deinit(&scope->symbols);
|
dst_table_deinit(&scope->symbols);
|
||||||
|
dst_table_deinit(&scope->constantrev);
|
||||||
dst_array_deinit(&scope->constants);
|
dst_array_deinit(&scope->constants);
|
||||||
free(scope->slots);
|
dst_compile_slotpool_deinit(&scope->slots);
|
||||||
free(scope->freeslots);
|
dst_compile_slotpool_deinit(&scope->unorderedslots);
|
||||||
free(scope->envs);
|
free(scope->envs);
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define dst_compile_topscope(c) ((c)->scopes + (c)->scopecount - 1)
|
DstSlot *dst_compile_constantslot(DstCompiler *c, DstValue x) {
|
||||||
|
|
||||||
/* Allocate a slot space */
|
|
||||||
static int32_t dst_compile_slotalloc(DstCompiler *c) {
|
|
||||||
DstScope *scope = dst_compile_topscope(c);
|
DstScope *scope = dst_compile_topscope(c);
|
||||||
if (scope->freeslotcount == 0) {
|
DstSlot *ret = dst_compile_slotpool_alloc(&scope->unorderedslots);
|
||||||
return scope->nextslot++;
|
ret->flags = (1 << dst_type(x)) | DST_SLOT_CONSTANT | DST_SLOT_NOTEMPTY;
|
||||||
} else {
|
ret->index = -1;
|
||||||
return scope->freeslots[--scope->freeslotcount];
|
ret->constant = x;
|
||||||
}
|
ret->envindex = scope->level;
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Free a single slot */
|
/* 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);
|
DstScope *scope = dst_compile_topscope(c);
|
||||||
int32_t newcount = scope->freeslotcount + 1;
|
if (slot->flags & (DST_SLOT_CONSTANT)) {
|
||||||
if (slot.flags & (DST_SLOT_CONSTANT | DST_SLOT_ERROR))
|
|
||||||
return;
|
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;
|
if (slot->envindex != 0) {
|
||||||
scope->freeslotcount = newcount;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
/* 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]);
|
|
||||||
}
|
}
|
||||||
|
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.
|
* but ensures a few properties.
|
||||||
* * Environments are on the stack unless they need to be closurized
|
* * Environments are on the stack unless they need to be closurized
|
||||||
* * Environments can be shared between closures
|
* * 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 */
|
/* Allow searching for symbols. Return information about the symbol */
|
||||||
DstSlot dst_compile_resolve(
|
DstSlot *dst_compile_resolve(
|
||||||
DstCompiler *c,
|
DstCompiler *c,
|
||||||
const DstValue *sourcemap,
|
const DstValue *sourcemap,
|
||||||
const uint8_t *sym) {
|
const uint8_t *sym) {
|
||||||
|
|
||||||
DstSlot ret;
|
DstSlot *ret = NULL;
|
||||||
DstScope *scope = dst_compile_topscope(c);
|
DstScope *scope = dst_compile_topscope(c);
|
||||||
int32_t env_index = 0;
|
int32_t env_index = 0;
|
||||||
int foundlocal;
|
int foundlocal = 1;
|
||||||
|
|
||||||
/* Search scopes for symbol, starting from top */
|
/* Search scopes for symbol, starting from top */
|
||||||
while (scope >= c->scopes) {
|
while (scope >= c->scopes) {
|
||||||
DstValue check = dst_table_get(scope->symbols, dst_wrap_symbol(sym));
|
DstValue check = dst_table_get(&scope->symbols, dst_wrap_symbol(sym));
|
||||||
if (dst_checktype(check, DST_INTEGER)) {
|
if (dst_checktype(check, DST_USERDATA)) {
|
||||||
ret = scope->slots[dst_unwrap_integer(check)];
|
ret = dst_unwrap_pointer(check);
|
||||||
goto found;
|
goto found;
|
||||||
}
|
}
|
||||||
scope--;
|
scope--;
|
||||||
|
if (scope->flags & DST_SCOPE_FUNCTION)
|
||||||
|
foundlocal = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Symbol not found */
|
/* 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 */
|
/* Symbol was found */
|
||||||
found:
|
found:
|
||||||
|
|
||||||
/* Constants and errors can be returned immediately (they are stateless) */
|
/* Constants can be returned immediately (they are stateless) */
|
||||||
if (ret.flags & (DST_SLOT_CONSTANT | DST_SLOT_ERROR))
|
if (ret->flags & DST_SLOT_CONSTANT)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
/* non-local scope needs to expose its environment */
|
/* non-local scope needs to expose its environment */
|
||||||
foundlocal = scope == dst_compile_topscope(c);
|
|
||||||
if (!foundlocal) {
|
if (!foundlocal) {
|
||||||
scope->flags |= DST_SCOPE_ENV;
|
scope->flags |= DST_SCOPE_ENV;
|
||||||
if (scope->envcount < 1) {
|
if (scope->envcount < 1) {
|
||||||
@ -264,61 +283,86 @@ DstSlot dst_compile_resolve(
|
|||||||
DST_OUT_OF_MEMORY;
|
DST_OUT_OF_MEMORY;
|
||||||
}
|
}
|
||||||
scope->envcap = 10;
|
scope->envcap = 10;
|
||||||
scope->envs[0] = -1;
|
scope->envs[0] = 0;
|
||||||
}
|
}
|
||||||
scope++;
|
scope++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Propogate env up to current scope */
|
/* Propogate env up to current scope */
|
||||||
while (scope <= dst_compile_topscope(c)) {
|
while (scope <= dst_compile_topscope(c)) {
|
||||||
int32_t j;
|
if (scope->flags & DST_SCOPE_FUNCTION) {
|
||||||
int32_t newcount = scope->envcount + 1;
|
int32_t j;
|
||||||
int scopefound = 0;
|
int32_t newcount = scope->envcount + 1;
|
||||||
/* Check if scope already has env. If so, break */
|
int scopefound = 0;
|
||||||
for (j = 1; j < scope->envcount; j++) {
|
/* Check if scope already has env. If so, break */
|
||||||
if (scope->envs[j] == env_index) {
|
for (j = 1; j < scope->envcount; j++) {
|
||||||
scopefound = 1;
|
if (scope->envs[j] == env_index) {
|
||||||
env_index = j;
|
scopefound = 1;
|
||||||
break;
|
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;
|
|
||||||
}
|
}
|
||||||
scope->envcap = newcap;
|
|
||||||
}
|
}
|
||||||
scope->envs[scope->envcount] = env_index;
|
if (!scopefound) {
|
||||||
scope->envcount = newcount;
|
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++;
|
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) {
|
if (!foundlocal) {
|
||||||
ret.envindex = env_index;
|
DstSlot *newret = dst_compile_slotpool_alloc(&scope->unorderedslots);
|
||||||
|
*newret = *ret;
|
||||||
|
newret->envindex = env_index;
|
||||||
|
ret = newret;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
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 an array */
|
||||||
|
|
||||||
/* Compile a single value */
|
/* Compile a single value */
|
||||||
DstSlot dst_compile_value(DstFormOptions opts) {
|
DstSlot *dst_compile_value(DstFormOptions opts) {
|
||||||
DstSlot ret;
|
DstSlot *ret;
|
||||||
if (opts.compiler->recursion_guard <= 0) {
|
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--;
|
opts.compiler->recursion_guard--;
|
||||||
switch (dst_type(opts.x)) {
|
switch (dst_type(opts.x)) {
|
||||||
default:
|
default:
|
||||||
ret = dst_compile_constantslot(opts.x);
|
ret = dst_compile_constantslot(opts.compiler, opts.x);
|
||||||
break;
|
break;
|
||||||
case DST_SYMBOL:
|
case DST_SYMBOL:
|
||||||
{
|
{
|
||||||
@ -326,28 +370,241 @@ DstSlot dst_compile_value(DstFormOptions opts) {
|
|||||||
if (dst_string_length(sym) > 0 && sym[0] != ':')
|
if (dst_string_length(sym) > 0 && sym[0] != ':')
|
||||||
ret = dst_compile_resolve(opts.compiler, opts.sourcemap, sym);
|
ret = dst_compile_resolve(opts.compiler, opts.sourcemap, sym);
|
||||||
else
|
else
|
||||||
ret = dst_compile_constantslot(opts.x);
|
ret = dst_compile_constantslot(opts.compiler, opts.x);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DST_TUPLE:
|
/*case DST_TUPLE:*/
|
||||||
ret = dst_compile_tuple(opts);
|
/*ret = dst_compile_tuple(opts); */
|
||||||
break;
|
/*break;*/
|
||||||
case DST_ARRAY:
|
/*case DST_ARRAY:*/
|
||||||
ret = dst_compile_array(opts);
|
/*ret = dst_compile_array(opts); */
|
||||||
break;
|
/*break;*/
|
||||||
case DST_STRUCT:
|
/*case DST_STRUCT:*/
|
||||||
ret = dst_compile_struct(opts);
|
/*ret = dst_compile_struct(opts); */
|
||||||
break;
|
/*break;*/
|
||||||
case DST_TABLE:
|
/*case DST_TABLE:*/
|
||||||
ret = dst_compile_table(opts);
|
/*ret = dst_compile_table(opts);*/
|
||||||
break;
|
/*break;*/
|
||||||
}
|
}
|
||||||
opts.compiler->recursion_guard++;
|
opts.compiler->recursion_guard++;
|
||||||
return ret;
|
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
|
/* Represents a local slot - not a constant, and within a specified range. Also
|
||||||
* the slot unaltered. Otherwise, move and load upvalues as necesarry to set the slot. */
|
* contains if it corresponds to a real slot. If temp, then the slot index
|
||||||
DstSlot dst_compile_coercetargetslot(DstFormOptions opts, DstSlot s);
|
* 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;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
173
core/compile.h
173
core/compile.h
@ -24,20 +24,24 @@
|
|||||||
#define DST_COMPILE_H
|
#define DST_COMPILE_H
|
||||||
|
|
||||||
#include <dst/dst.h>
|
#include <dst/dst.h>
|
||||||
|
#include <setjmp.h>
|
||||||
|
#include "opcodes.h"
|
||||||
|
|
||||||
/* Compiler typedefs */
|
/* Compiler typedefs */
|
||||||
typedef struct DstCompiler DstCompiler;
|
typedef struct DstCompiler DstCompiler;
|
||||||
typedef struct FormOptions FormOptions;
|
typedef struct FormOptions FormOptions;
|
||||||
typedef struct SlotTracker SlotTracker;
|
typedef struct SlotTracker SlotTracker;
|
||||||
typedef struct DstScope DstScope;
|
typedef struct DstScope DstScope;
|
||||||
|
typedef struct DstSlot DstSlot;
|
||||||
|
typedef struct DstFormOptions DstFormOptions;
|
||||||
typedef struct DstCFunctionOptimizer DstCFunctionOptimizer;
|
typedef struct DstCFunctionOptimizer DstCFunctionOptimizer;
|
||||||
|
|
||||||
#define DST_SLOT_CONSTANT 0x10000
|
#define DST_SLOT_CONSTANT 0x10000
|
||||||
#define DST_SLOT_TEMP 0x20000
|
#define DST_SLOT_NAMED 0x20000
|
||||||
#define DST_SLOT_RETURNED 0x40000
|
#define DST_SLOT_RETURNED 0x40000
|
||||||
#define DST_SLOT_NIL 0x80000
|
#define DST_SLOT_NIL 0x80000
|
||||||
#define DST_SLOT_MUTABLE 0x100000
|
#define DST_SLOT_MUTABLE 0x100000
|
||||||
#define DST_SLOT_ERROR 0x200000
|
#define DST_SLOT_NOTEMPTY 0x200000
|
||||||
|
|
||||||
#define DST_SLOTTYPE_ANY 0xFFFF
|
#define DST_SLOTTYPE_ANY 0xFFFF
|
||||||
|
|
||||||
@ -47,7 +51,7 @@ struct DstSlot {
|
|||||||
int32_t envindex; /* 0 is local, positive number is an upvalue */
|
int32_t envindex; /* 0 is local, positive number is an upvalue */
|
||||||
uint32_t flags;
|
uint32_t flags;
|
||||||
DstValue constant; /* If the slot has a constant value */
|
DstValue constant; /* If the slot has a constant value */
|
||||||
}
|
};
|
||||||
|
|
||||||
/* Most forms that return a constant will not generate any bytecode */
|
/* Most forms that return a constant will not generate any bytecode */
|
||||||
|
|
||||||
@ -62,67 +66,59 @@ struct DstSlot {
|
|||||||
* do
|
* 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_FUNCTION 1
|
||||||
#define DST_SCOPE_LASTSLOT 2
|
#define DST_SCOPE_LASTSLOT 2
|
||||||
#define DST_SCOPE_FIRSTSLOT 4
|
#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 */
|
/* A lexical scope during compilation */
|
||||||
struct DstScope {
|
struct DstScope {
|
||||||
|
int32_t level;
|
||||||
DstArray constants; /* Constants for the funcdef */
|
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
|
/* Hold all slots in use. Data structures that store
|
||||||
* slots should link them to this datatstructure */
|
* slots should link them to this datatstructure */
|
||||||
DstSlot *slots;
|
DstSlotPool slots;
|
||||||
int32_t slotcount;
|
DstSlotPool unorderedslots;
|
||||||
int32_t slotcap;
|
|
||||||
|
|
||||||
/* A vector of freed slots. */
|
/* Referenced closure environents. The values at each index correspond
|
||||||
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
|
* 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. */
|
* that corresponds to the direct parent's stack will always have value 0. */
|
||||||
int32_t *envs;
|
int32_t *envs;
|
||||||
int32_t envcount;
|
int32_t envcount;
|
||||||
int32_t envcap;
|
int32_t envcap;
|
||||||
|
|
||||||
int32_t buffer_offset; /* Where the bytecode for this scope begins */
|
int32_t bytecode_start;
|
||||||
|
|
||||||
uint32_t flags;
|
uint32_t flags;
|
||||||
}
|
};
|
||||||
|
|
||||||
|
#define dst_compile_topscope(c) ((c)->scopes + (c)->scopecount - 1)
|
||||||
|
|
||||||
/* Compilation state */
|
/* Compilation state */
|
||||||
struct DstCompiler {
|
struct DstCompiler {
|
||||||
|
jmp_buf on_error;
|
||||||
|
int recursion_guard;
|
||||||
int32_t scopecount;
|
int32_t scopecount;
|
||||||
int32_t scopecap;
|
int32_t scopecap;
|
||||||
DstScope *scopes;
|
DstScope *scopes;
|
||||||
DstBuffer buffer;
|
|
||||||
DstBuffer mapbuffer;
|
int32_t buffercap;
|
||||||
int32_t error_start;
|
int32_t buffercount;
|
||||||
int32_t error_end;
|
uint32_t *buffer;
|
||||||
DstValue error;
|
int32_t (*mapbuffer)[2];
|
||||||
int recursion_guard;
|
|
||||||
|
DstCompileResults results;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define DST_FOPTS_TAIL 0x10000
|
#define DST_FOPTS_TAIL 0x10000
|
||||||
@ -136,58 +132,48 @@ struct DstFormOptions {
|
|||||||
uint32_t flags; /* bit set of accepted primitive types */
|
uint32_t flags; /* bit set of accepted primitive types */
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef enum DstCompileStatus {
|
/* A grouping of optimizations on a cfunction given certain conditions
|
||||||
DST_COMPILE_OK,
|
* on the arguments (such as all constants, or some known types). The appropriate
|
||||||
DST_COMPILE_ERROR
|
* optimizations should be tried before compiling a normal function call. */
|
||||||
} DstCompileStatus;
|
struct DstCFunctionOptimizer {
|
||||||
|
DstCFunction cfun;
|
||||||
/* Results of compilation */
|
DstSlot (*optimize)(DstFormOptions opts, int32_t argn, const DstValue *argv);
|
||||||
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;
|
|
||||||
};
|
};
|
||||||
|
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. */
|
/* An array of optimizers sorted by key */
|
||||||
typedef DstSlot (*DstFormCompiler)(DstFormOptions opts);
|
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 */
|
/* Dispatch to correct form compiler */
|
||||||
DstSlot dst_compile_value(DstFormOptions opts);
|
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 */
|
/* Compile special forms */
|
||||||
DstSlot dst_compile_do(DstFormOptions opts);
|
DstSlot *dst_compile_do(DstFormOptions opts, int32_t argn, const DstValue *argv);
|
||||||
DstSlot dst_compile_fn(DstFormOptions opts);
|
DstSlot *dst_compile_fn(DstFormOptions opts, int32_t argn, const DstValue *argv);
|
||||||
DstSlot dst_compile_cond(DstFormOptions opts);
|
DstSlot *dst_compile_cond(DstFormOptions opts, int32_t argn, const DstValue *argv);
|
||||||
DstSlot dst_compile_while(DstFormOptions opts);
|
DstSlot *dst_compile_while(DstFormOptions opts, int32_t argn, const DstValue *argv);
|
||||||
DstSlot dst_compile_quote(DstFormOptions opts);
|
DstSlot *dst_compile_quote(DstFormOptions opts, int32_t argn, const DstValue *argv);
|
||||||
DstSlot dst_compile_def(DstFormOptions opts);
|
DstSlot *dst_compile_def(DstFormOptions opts, int32_t argn, const DstValue *argv);
|
||||||
DstSlot dst_compile_var(DstFormOptions opts);
|
DstSlot *dst_compile_var(DstFormOptions opts, int32_t argn, const DstValue *argv);
|
||||||
DstSlot dst_compile_varset(DstFormOptions opts);
|
DstSlot *dst_compile_varset(DstFormOptions opts, int32_t argn, const DstValue *argv);
|
||||||
|
|
||||||
/* Compile source code into FuncDef. */
|
|
||||||
DstCompileResults dst_compile(DstCompileOptions opts);
|
|
||||||
|
|
||||||
/****************************************************/
|
/****************************************************/
|
||||||
|
|
||||||
DstSlot dst_compile_error(DstCompiler *c, const DstValue *sourcemap, const uint8_t *m);
|
void 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_cerror(DstCompiler *c, const DstValue *sourcemap, const char *m);
|
||||||
|
|
||||||
/* Use these to get sub options. They will traverse the source map so
|
/* Use these to get sub options. They will traverse the source map so
|
||||||
* compiler errors make sense. Then modify the returned options. */
|
* 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);
|
DstFormOptions dst_compile_getopts_value(DstFormOptions opts, DstValue key);
|
||||||
|
|
||||||
void dst_compile_scope(DstCompiler *c, int newfn);
|
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_constantslot(DstCompiler *c, DstValue x);
|
||||||
DstSlot dst_compile_normalslot(DstCompiler *c, uint32_t types);
|
void dst_compile_freeslot(DstCompiler *c, DstSlot *slot);
|
||||||
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 */
|
/* 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. */
|
/* Emit instructions. */
|
||||||
DstSlot dst_compile_targetslot(DstFormOptions opts, DstSlot s);
|
|
||||||
|
|
||||||
/* Coerce any slot into the target slot. If no target is specified, return
|
void dst_compile_emit(DstCompiler *c, const DstValue *sourcemap, uint32_t instr);
|
||||||
* 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);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -55,7 +55,8 @@ enum DstOpCode {
|
|||||||
DOP_SHIFT_RIGHT_IMMEDIATE,
|
DOP_SHIFT_RIGHT_IMMEDIATE,
|
||||||
DOP_SHIFT_RIGHT_UNSIGNED,
|
DOP_SHIFT_RIGHT_UNSIGNED,
|
||||||
DOP_SHIFT_RIGHT_UNSIGNED_IMMEDIATE,
|
DOP_SHIFT_RIGHT_UNSIGNED_IMMEDIATE,
|
||||||
DOP_MOVE,
|
DOP_MOVE_FAR,
|
||||||
|
DOP_MOVE_NEAR,
|
||||||
DOP_JUMP,
|
DOP_JUMP,
|
||||||
DOP_JUMP_IF,
|
DOP_JUMP_IF,
|
||||||
DOP_JUMP_IF_NOT,
|
DOP_JUMP_IF_NOT,
|
||||||
@ -64,9 +65,11 @@ enum DstOpCode {
|
|||||||
DOP_EQUALS,
|
DOP_EQUALS,
|
||||||
DOP_COMPARE,
|
DOP_COMPARE,
|
||||||
DOP_LOAD_NIL,
|
DOP_LOAD_NIL,
|
||||||
DOP_LOAD_BOOLEAN,
|
DOP_LOAD_TRUE,
|
||||||
|
DOP_LOAD_FALSE,
|
||||||
DOP_LOAD_INTEGER,
|
DOP_LOAD_INTEGER,
|
||||||
DOP_LOAD_CONSTANT,
|
DOP_LOAD_CONSTANT,
|
||||||
|
DOP_LOAD_SELF,
|
||||||
DOP_LOAD_UPVALUE,
|
DOP_LOAD_UPVALUE,
|
||||||
DOP_SET_UPVALUE,
|
DOP_SET_UPVALUE,
|
||||||
DOP_CLOSURE,
|
DOP_CLOSURE,
|
||||||
|
21
core/vm.c
21
core/vm.c
@ -280,11 +280,16 @@ int dst_continue() {
|
|||||||
pc++;
|
pc++;
|
||||||
vm_next();
|
vm_next();
|
||||||
|
|
||||||
case DOP_MOVE:
|
case DOP_MOVE_NEAR:
|
||||||
stack[oparg(1, 0xFF)] = stack[oparg(2, 0xFFFF)];
|
stack[oparg(1, 0xFF)] = stack[oparg(2, 0xFFFF)];
|
||||||
pc++;
|
pc++;
|
||||||
vm_next();
|
vm_next();
|
||||||
|
|
||||||
|
case DOP_MOVE_FAR:
|
||||||
|
stack[oparg(2, 0xFFFF)] = stack[oparg(1, 0xFF)];
|
||||||
|
pc++;
|
||||||
|
vm_next();
|
||||||
|
|
||||||
case DOP_JUMP:
|
case DOP_JUMP:
|
||||||
pc += (*(int32_t *)pc) >> 8;
|
pc += (*(int32_t *)pc) >> 8;
|
||||||
vm_next();
|
vm_next();
|
||||||
@ -342,8 +347,13 @@ int dst_continue() {
|
|||||||
pc++;
|
pc++;
|
||||||
vm_next();
|
vm_next();
|
||||||
|
|
||||||
case DOP_LOAD_BOOLEAN:
|
case DOP_LOAD_TRUE:
|
||||||
stack[oparg(1, 0xFF)] = dst_wrap_boolean(oparg(2, 0xFFFF));
|
stack[oparg(1, 0xFFFFFF)] = dst_wrap_boolean(1);
|
||||||
|
pc++;
|
||||||
|
vm_next();
|
||||||
|
|
||||||
|
case DOP_LOAD_FALSE:
|
||||||
|
stack[oparg(1, 0xFFFFFF)] = dst_wrap_boolean(0);
|
||||||
pc++;
|
pc++;
|
||||||
vm_next();
|
vm_next();
|
||||||
|
|
||||||
@ -358,6 +368,11 @@ int dst_continue() {
|
|||||||
pc++;
|
pc++;
|
||||||
vm_next();
|
vm_next();
|
||||||
|
|
||||||
|
case DOP_LOAD_SELF:
|
||||||
|
stack[oparg(1, 0xFFFFFF)] = dst_wrap_function(func);
|
||||||
|
pc++;
|
||||||
|
vm_next();
|
||||||
|
|
||||||
case DOP_LOAD_UPVALUE:
|
case DOP_LOAD_UPVALUE:
|
||||||
{
|
{
|
||||||
int32_t eindex = oparg(2, 0xFF);
|
int32_t eindex = oparg(2, 0xFF);
|
||||||
|
@ -20,8 +20,8 @@
|
|||||||
* IN THE SOFTWARE.
|
* IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef DST_NANBOX_H_defined
|
#ifndef DST_H_defined
|
||||||
#define DST_NANBOX_H_defined
|
#define DST_H_defined
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -680,6 +680,30 @@ int dst_continue();
|
|||||||
int dst_run(DstValue callee);
|
int dst_run(DstValue callee);
|
||||||
DstValue dst_transfer(DstFiber *fiber, DstValue x);
|
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 */
|
/* GC */
|
||||||
|
|
||||||
/* The metadata header associated with an allocated block of memory */
|
/* The metadata header associated with an allocated block of memory */
|
||||||
|
Loading…
Reference in New Issue
Block a user