mirror of
https://github.com/janet-lang/janet
synced 2024-09-29 07:20:41 +00:00
More work on compiler. Add compiler unit test that currently
segfaults alot. Added dst_disasm to reconstruct dsts assembly from a funcdef.
This commit is contained in:
parent
2d781ef21b
commit
01a95426b3
230
3
230
3
@ -1,230 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2017 Calvin Rose
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to
|
|
||||||
* deal in the Software without restriction, including without limitation the
|
|
||||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
||||||
* sell copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
||||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
||||||
* IN THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef DST_COMPILE_H
|
|
||||||
#define DST_COMPILE_H
|
|
||||||
|
|
||||||
#include <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
|
|
6
Makefile
6
Makefile
@ -59,7 +59,8 @@ $(DST_XXD): libs/xxd.c
|
|||||||
###################################
|
###################################
|
||||||
|
|
||||||
DST_CORE_SOURCES=$(addprefix core/,\
|
DST_CORE_SOURCES=$(addprefix core/,\
|
||||||
array.c asm.c buffer.c compile.c fiber.c func.c gc.c parse.c string.c strtod.c\
|
array.c asm.c buffer.c compile.c compile_slotpool.c \
|
||||||
|
fiber.c func.c gc.c parse.c string.c strtod.c\
|
||||||
struct.c symcache.c syscalls.c table.c tuple.c userdata.c util.c\
|
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))
|
||||||
@ -78,7 +79,7 @@ $(DST_TARGET): $(DST_CORE_OBJECTS)
|
|||||||
CCU_FLAGS = $(CFLAGS) -DDST_UNIT_TEST
|
CCU_FLAGS = $(CFLAGS) -DDST_UNIT_TEST
|
||||||
|
|
||||||
DST_UNIT_BINARIES=$(addprefix unittests/,\
|
DST_UNIT_BINARIES=$(addprefix unittests/,\
|
||||||
asm_test.out array_test.out buffer_test.out fiber_test.out \
|
asm_test.out array_test.out buffer_test.out compile_test.out fiber_test.out \
|
||||||
parse_test.out strtod_test.out table_test.out)
|
parse_test.out strtod_test.out table_test.out)
|
||||||
|
|
||||||
%.out: %.c $(DST_CORE_OBJECTS) $(DST_ALL_HEADERS) unittests/unit.h
|
%.out: %.c $(DST_CORE_OBJECTS) $(DST_ALL_HEADERS) unittests/unit.h
|
||||||
@ -88,6 +89,7 @@ unit: $(DST_UNIT_BINARIES)
|
|||||||
unittests/array_test.out
|
unittests/array_test.out
|
||||||
unittests/asm_test.out
|
unittests/asm_test.out
|
||||||
unittests/buffer_test.out
|
unittests/buffer_test.out
|
||||||
|
unittests/compile_test.out
|
||||||
unittests/fiber_test.out
|
unittests/fiber_test.out
|
||||||
unittests/parse_test.out
|
unittests/parse_test.out
|
||||||
unittests/strtod_test.out
|
unittests/strtod_test.out
|
||||||
|
10
core/array.c
10
core/array.c
@ -24,10 +24,12 @@
|
|||||||
|
|
||||||
/* Iniializes an array */
|
/* Iniializes an array */
|
||||||
DstArray *dst_array_init(DstArray *array, int32_t capacity) {
|
DstArray *dst_array_init(DstArray *array, int32_t capacity) {
|
||||||
if (capacity < 0) capacity = 0;
|
DstValue *data = NULL;
|
||||||
DstValue *data = (DstValue *) malloc(sizeof(DstValue) * capacity);
|
if (capacity > 0) {
|
||||||
if (NULL == data) {
|
data = (DstValue *) malloc(sizeof(DstValue) * capacity);
|
||||||
DST_OUT_OF_MEMORY;
|
if (NULL == data) {
|
||||||
|
DST_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
array->count = 0;
|
array->count = 0;
|
||||||
array->capacity = capacity;
|
array->capacity = capacity;
|
||||||
|
203
core/asm.c
203
core/asm.c
@ -518,6 +518,9 @@ static DstAssembleResult dst_asm1(DstAssembler *parent, DstAssembleOptions opts)
|
|||||||
def->flags = 0;
|
def->flags = 0;
|
||||||
def->slotcount = 0;
|
def->slotcount = 0;
|
||||||
def->arity = 0;
|
def->arity = 0;
|
||||||
|
def->source = NULL;
|
||||||
|
def->sourcepath = NULL;
|
||||||
|
def->sourcemap = NULL;
|
||||||
def->constants_length = 0;
|
def->constants_length = 0;
|
||||||
def->bytecode_length = 0;
|
def->bytecode_length = 0;
|
||||||
def->environments_length = 1;
|
def->environments_length = 1;
|
||||||
@ -544,7 +547,7 @@ static DstAssembleResult dst_asm1(DstAssembler *parent, DstAssembleOptions opts)
|
|||||||
dst_asm_deinit(&a);
|
dst_asm_deinit(&a);
|
||||||
longjmp(a.parent->on_error, 1);
|
longjmp(a.parent->on_error, 1);
|
||||||
}
|
}
|
||||||
result.result.error = a.errmessage;
|
result.error = a.errmessage;
|
||||||
result.status = DST_ASSEMBLE_ERROR;
|
result.status = DST_ASSEMBLE_ERROR;
|
||||||
if (a.errmap != NULL) {
|
if (a.errmap != NULL) {
|
||||||
result.error_start = dst_unwrap_integer(a.errmap[0]);
|
result.error_start = dst_unwrap_integer(a.errmap[0]);
|
||||||
@ -560,6 +563,23 @@ static DstAssembleResult dst_asm1(DstAssembler *parent, DstAssembleOptions opts)
|
|||||||
x = dst_struct_get(st, dst_csymbolv("arity"));
|
x = dst_struct_get(st, dst_csymbolv("arity"));
|
||||||
def->arity = dst_checktype(x, DST_INTEGER) ? dst_unwrap_integer(x) : 0;
|
def->arity = dst_checktype(x, DST_INTEGER) ? dst_unwrap_integer(x) : 0;
|
||||||
|
|
||||||
|
/* Check vararg */
|
||||||
|
x = dst_struct_get(st, dst_csymbolv("vararg"));
|
||||||
|
if (dst_truthy(x))
|
||||||
|
def->flags |= DST_FUNCDEF_FLAG_VARARG;
|
||||||
|
|
||||||
|
/* Check source */
|
||||||
|
x = dst_struct_get(st, dst_csymbolv("source"));
|
||||||
|
if (dst_checktype(x, DST_STRING)) {
|
||||||
|
def->source = dst_unwrap_string(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check source path */
|
||||||
|
x = dst_struct_get(st, dst_csymbolv("sourcepath"));
|
||||||
|
if (dst_checktype(x, DST_STRING)) {
|
||||||
|
def->sourcepath = dst_unwrap_string(x);
|
||||||
|
}
|
||||||
|
|
||||||
/* Create slot aliases */
|
/* Create slot aliases */
|
||||||
x = dst_struct_get(st, dst_csymbolv("slots"));
|
x = dst_struct_get(st, dst_csymbolv("slots"));
|
||||||
if (dst_seq_view(x, &arr, &count)) {
|
if (dst_seq_view(x, &arr, &count)) {
|
||||||
@ -586,10 +606,10 @@ static DstAssembleResult dst_asm1(DstAssembler *parent, DstAssembleOptions opts)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Create environment aliases */
|
/* Create environment aliases */
|
||||||
x = dst_struct_get(st, dst_csymbolv("environments"));
|
x = dst_struct_get(st, dst_csymbolv("captures"));
|
||||||
if (dst_seq_view(x, &arr, &count)) {
|
if (dst_seq_view(x, &arr, &count)) {
|
||||||
const DstValue *emap =
|
const DstValue *emap =
|
||||||
dst_parse_submap_value(opts.sourcemap, dst_csymbolv("environments"));
|
dst_parse_submap_value(opts.sourcemap, dst_csymbolv("captures"));
|
||||||
for (i = 0; i < count; i++) {
|
for (i = 0; i < count; i++) {
|
||||||
const DstValue *imap = dst_parse_submap_index(emap, i);
|
const DstValue *imap = dst_parse_submap_index(emap, i);
|
||||||
dst_asm_assert(&a, dst_checktype(arr[i], DST_SYMBOL), imap, "environment must be a symbol");
|
dst_asm_assert(&a, dst_checktype(arr[i], DST_SYMBOL), imap, "environment must be a symbol");
|
||||||
@ -691,11 +711,37 @@ static DstAssembleResult dst_asm1(DstAssembler *parent, DstAssembleOptions opts)
|
|||||||
dst_asm_error(&a, opts.sourcemap, "bytecode expected");
|
dst_asm_error(&a, opts.sourcemap, "bytecode expected");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check for source mapping */
|
||||||
|
x = dst_struct_get(st, dst_csymbolv("sourcemap"));
|
||||||
|
if (dst_seq_view(x, &arr, &count)) {
|
||||||
|
const DstValue *bmap =
|
||||||
|
dst_parse_submap_value(opts.sourcemap, dst_csymbolv("sourcemap"));
|
||||||
|
dst_asm_assert(&a, count != 2 * def->bytecode_length, bmap, "sourcemap must have twice the length of the bytecode");
|
||||||
|
def->sourcemap = malloc(sizeof(int32_t) * 2 * count);
|
||||||
|
for (i = 0; i < count; i += 2) {
|
||||||
|
DstValue start = arr[i];
|
||||||
|
DstValue end = arr[i + 1];
|
||||||
|
if (!(dst_checktype(start, DST_INTEGER) ||
|
||||||
|
dst_unwrap_integer(start) < 0)) {
|
||||||
|
const DstValue *submap = dst_parse_submap_index(bmap, i);
|
||||||
|
dst_asm_error(&a, submap, "expected positive integer");
|
||||||
|
}
|
||||||
|
if (!(dst_checktype(end, DST_INTEGER) ||
|
||||||
|
dst_unwrap_integer(end) < 0)) {
|
||||||
|
const DstValue *submap = dst_parse_submap_index(bmap, i + 1);
|
||||||
|
dst_asm_error(&a, submap, "expected positive integer");
|
||||||
|
}
|
||||||
|
def->sourcemap[i] = dst_unwrap_integer(start);
|
||||||
|
def->sourcemap[i+1] = dst_unwrap_integer(end);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/* Finish everything and return funcdef */
|
/* Finish everything and return funcdef */
|
||||||
dst_asm_deinit(&a);
|
dst_asm_deinit(&a);
|
||||||
def->environments =
|
def->environments =
|
||||||
realloc(def->environments, def->environments_length * sizeof(int32_t));
|
realloc(def->environments, def->environments_length * sizeof(int32_t));
|
||||||
result.result.def = def;
|
result.funcdef = def;
|
||||||
result.status = DST_ASSEMBLE_OK;
|
result.status = DST_ASSEMBLE_OK;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -711,7 +757,154 @@ DstFunction *dst_asm_func(DstAssembleResult result) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
DstFunction *func = dst_alloc(DST_MEMORY_FUNCTION, sizeof(DstFunction));
|
DstFunction *func = dst_alloc(DST_MEMORY_FUNCTION, sizeof(DstFunction));
|
||||||
func->def = result.result.def;
|
func->def = result.funcdef;
|
||||||
func->envs = NULL;
|
func->envs = NULL;
|
||||||
return func;
|
return func;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Disassembly */
|
||||||
|
|
||||||
|
/* Find the deinfintion of an instruction given the instruction word. Return
|
||||||
|
* NULL if not found. */
|
||||||
|
static const DstInstructionDef *dst_asm_reverse_lookup(uint32_t instr) {
|
||||||
|
size_t i;
|
||||||
|
uint32_t opcode = instr & 0xFF;
|
||||||
|
for (i = 0; i < sizeof(dst_ops)/sizeof(DstInstructionDef); i++) {
|
||||||
|
const DstInstructionDef *def = dst_ops + i;
|
||||||
|
if (def->opcode == opcode)
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create some constant sized tuples */
|
||||||
|
static DstValue tup1(DstValue x) {
|
||||||
|
DstValue *tup = dst_tuple_begin(1);
|
||||||
|
tup[0] = x;
|
||||||
|
return dst_wrap_tuple(dst_tuple_end(tup));
|
||||||
|
}
|
||||||
|
static DstValue tup2(DstValue x, DstValue y) {
|
||||||
|
DstValue *tup = dst_tuple_begin(2);
|
||||||
|
tup[0] = x;
|
||||||
|
tup[1] = y;
|
||||||
|
return dst_wrap_tuple(dst_tuple_end(tup));
|
||||||
|
}
|
||||||
|
static DstValue tup3(DstValue x, DstValue y, DstValue z) {
|
||||||
|
DstValue *tup = dst_tuple_begin(3);
|
||||||
|
tup[0] = x;
|
||||||
|
tup[1] = y;
|
||||||
|
tup[2] = z;
|
||||||
|
return dst_wrap_tuple(dst_tuple_end(tup));
|
||||||
|
}
|
||||||
|
static DstValue tup4(DstValue w, DstValue x, DstValue y, DstValue z) {
|
||||||
|
DstValue *tup = dst_tuple_begin(4);
|
||||||
|
tup[0] = w;
|
||||||
|
tup[1] = x;
|
||||||
|
tup[2] = y;
|
||||||
|
tup[3] = z;
|
||||||
|
return dst_wrap_tuple(dst_tuple_end(tup));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Given an argument, convert it to the appriate integer or symbol */
|
||||||
|
static DstValue dst_asm_decode_instruction(uint32_t instr) {
|
||||||
|
const DstInstructionDef *def = dst_asm_reverse_lookup(instr);
|
||||||
|
DstValue name;
|
||||||
|
if (NULL == def) {
|
||||||
|
return dst_wrap_integer((int32_t)instr);
|
||||||
|
}
|
||||||
|
name = dst_csymbolv(def->name);
|
||||||
|
#define oparg(shift, mask) ((instr >> ((shift) << 3)) & (mask))
|
||||||
|
switch (def->type) {
|
||||||
|
case DIT_0:
|
||||||
|
return tup1(name);
|
||||||
|
case DIT_S:
|
||||||
|
return tup2(name, dst_wrap_integer(oparg(1, 0xFFFFFF)));
|
||||||
|
case DIT_L:
|
||||||
|
return tup2(name, dst_wrap_integer((int32_t)instr >> 8));
|
||||||
|
case DIT_SS:
|
||||||
|
case DIT_ST:
|
||||||
|
case DIT_SC:
|
||||||
|
case DIT_SU:
|
||||||
|
return tup3(name,
|
||||||
|
dst_wrap_integer(oparg(1, 0xFF)),
|
||||||
|
dst_wrap_integer(oparg(2, 0xFFFF)));
|
||||||
|
case DIT_SI:
|
||||||
|
case DIT_SL:
|
||||||
|
return tup3(name,
|
||||||
|
dst_wrap_integer(oparg(1, 0xFF)),
|
||||||
|
dst_wrap_integer((int32_t)instr >> 16));
|
||||||
|
case DIT_SSS:
|
||||||
|
case DIT_SES:
|
||||||
|
case DIT_SSU:
|
||||||
|
return tup4(name,
|
||||||
|
dst_wrap_integer(oparg(1, 0xFF)),
|
||||||
|
dst_wrap_integer(oparg(2, 0xFF)),
|
||||||
|
dst_wrap_integer(oparg(3, 0xFF)));
|
||||||
|
case DIT_SSI:
|
||||||
|
return tup4(name,
|
||||||
|
dst_wrap_integer(oparg(1, 0xFF)),
|
||||||
|
dst_wrap_integer(oparg(2, 0xFF)),
|
||||||
|
dst_wrap_integer((int32_t)instr >> 24));
|
||||||
|
}
|
||||||
|
#undef oparg
|
||||||
|
}
|
||||||
|
|
||||||
|
DstValue dst_disasm(DstFuncDef *def) {
|
||||||
|
int32_t i;
|
||||||
|
DstArray *bcode = dst_array(def->bytecode_length);
|
||||||
|
DstArray *constants = dst_array(def->constants_length);
|
||||||
|
DstTable *ret = dst_table(10);
|
||||||
|
dst_table_put(ret, dst_csymbolv("arity"), dst_wrap_integer(def->arity));
|
||||||
|
dst_table_put(ret, dst_csymbolv("bytecode"), dst_wrap_array(bcode));
|
||||||
|
dst_table_put(ret, dst_csymbolv("constants"), dst_wrap_array(constants));
|
||||||
|
if (def->sourcepath) {
|
||||||
|
dst_table_put(ret, dst_csymbolv("sourcepath"), dst_wrap_string(def->sourcepath));
|
||||||
|
}
|
||||||
|
if (def->source) {
|
||||||
|
dst_table_put(ret, dst_csymbolv("source"), dst_wrap_string(def->source));
|
||||||
|
}
|
||||||
|
if (def->flags & DST_FUNCDEF_FLAG_VARARG) {
|
||||||
|
dst_table_put(ret, dst_csymbolv("vararg"), dst_wrap_true());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add constants */
|
||||||
|
for (i = 0; i < def->constants_length; i++) {
|
||||||
|
DstValue src = def->constants[i];
|
||||||
|
DstValue dest;
|
||||||
|
if (dst_checktype(src, DST_TUPLE)) {
|
||||||
|
dest = tup2(dst_csymbolv("quote"), src);
|
||||||
|
} else {
|
||||||
|
dest = src;
|
||||||
|
}
|
||||||
|
constants->data[i] = dest;
|
||||||
|
}
|
||||||
|
constants->count = def->constants_length;
|
||||||
|
|
||||||
|
/* Add bytecode */
|
||||||
|
for (i = 0; i < def->bytecode_length; i++) {
|
||||||
|
bcode->data[i] = dst_asm_decode_instruction(def->bytecode[i]);
|
||||||
|
}
|
||||||
|
bcode->count = def->bytecode_length;
|
||||||
|
|
||||||
|
/* Add source map */
|
||||||
|
if (def->sourcemap) {
|
||||||
|
DstArray *sourcemap = dst_array(def->bytecode_length * 2);
|
||||||
|
for (i = 0; i < def->bytecode_length * 2; i++) {
|
||||||
|
sourcemap->data[i] = dst_wrap_integer(def->sourcemap[i]);
|
||||||
|
}
|
||||||
|
sourcemap->count = def->bytecode_length * 2;
|
||||||
|
dst_table_put(ret, dst_csymbolv("sourcemap"), dst_wrap_array(sourcemap));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add environments */
|
||||||
|
if (def->environments) {
|
||||||
|
DstArray *envs = dst_array(def->environments_length);
|
||||||
|
for (i = 0; i < def->environments_length; i++) {
|
||||||
|
envs->data[i] = dst_wrap_integer(def->environments[i]);
|
||||||
|
}
|
||||||
|
envs->count = def->environments_length;
|
||||||
|
dst_table_put(ret, dst_csymbolv("environments"), dst_wrap_array(envs));
|
||||||
|
}
|
||||||
|
|
||||||
|
return dst_wrap_struct(dst_table_to_struct(ret));
|
||||||
|
}
|
||||||
|
354
core/compile.c
354
core/compile.c
@ -24,29 +24,17 @@
|
|||||||
#include "compile.h"
|
#include "compile.h"
|
||||||
|
|
||||||
/* Lazily sort the optimizers */
|
/* Lazily sort the optimizers */
|
||||||
static int optimizers_sorted = 0;
|
/*static int optimizers_sorted = 0;*/
|
||||||
|
|
||||||
/* Lookups for specials and optimizable c functions. */
|
/* Lookups for specials and optimizable c functions. */
|
||||||
DstCFunctionOptimizer dst_compiler_optimizers[255];
|
/*DstCFunctionOptimizer dst_compiler_optimizers[255];*/
|
||||||
DstSpecial dst_compiler_specials[16];
|
/*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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Throw an error with a dst string */
|
/* Throw an error with a dst string */
|
||||||
void 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) {
|
||||||
c->error_start = dst_unwrap_integer(sourcemap[0]);
|
c->results.error_start = dst_unwrap_integer(sourcemap[0]);
|
||||||
c->error_end = dst_unwrap_integer(sourcemap[1]);
|
c->results.error_end = dst_unwrap_integer(sourcemap[1]);
|
||||||
c->error = dst_wrap_string(m);
|
c->results.error = m;
|
||||||
longjmp(c->on_error, 1);
|
longjmp(c->on_error, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,72 +65,6 @@ DstFormOptions dst_compile_getopts_value(DstFormOptions opts, DstValue key) {
|
|||||||
opts.sourcemap = sourcemap;
|
opts.sourcemap = sourcemap;
|
||||||
return opts;
|
return opts;
|
||||||
}
|
}
|
||||||
|
|
||||||
void dst_compile_slotpool_init(DstSlotPool *pool) {
|
|
||||||
pool->s = NULL;
|
|
||||||
pool->count = 0;
|
|
||||||
pool->free = 0;
|
|
||||||
pool->cap = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void dst_compile_slotpool_deinit(DstSlotPool *pool) {
|
|
||||||
free(pool->s);
|
|
||||||
pool->s = NULL;
|
|
||||||
pool->cap = 0;
|
|
||||||
pool->count = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void dst_compile_slotpool_extend(DstSlotPool *pool, int32_t extra) {
|
|
||||||
int32_t i;
|
|
||||||
int32_t newcount = pool->count + extra;
|
|
||||||
if (newcount > pool->cap) {
|
|
||||||
int32_t newcap = 2 * newcount;
|
|
||||||
pool->s = realloc(pool->s, newcap * sizeof(DstSlot));
|
|
||||||
if (NULL == pool->s) {
|
|
||||||
DST_OUT_OF_MEMORY;
|
|
||||||
}
|
|
||||||
pool->cap = newcap;
|
|
||||||
}
|
|
||||||
/* Mark all slots as free */
|
|
||||||
for (i = pool->count; i < newcount; i++) {
|
|
||||||
pool->s[i].flags = 0;
|
|
||||||
}
|
|
||||||
pool->count = newcount;
|
|
||||||
}
|
|
||||||
|
|
||||||
DstSlot *dst_compile_slotpool_alloc(DstSlotPool *pool) {
|
|
||||||
int32_t oldcount = pool->count;
|
|
||||||
int32_t newcount = oldcount == 0xF0 ? 0x101 : oldcount + 1;
|
|
||||||
while (pool->free < pool->count) {
|
|
||||||
if (!(pool->s[pool->free].flags & DST_SLOT_NOTEMPTY)) {
|
|
||||||
return pool->s + pool->free;
|
|
||||||
}
|
|
||||||
pool->free++;
|
|
||||||
}
|
|
||||||
dst_compile_slotpool_extend(pool, newcount - oldcount);
|
|
||||||
pool->s[oldcount].flags = DST_SLOT_NOTEMPTY;
|
|
||||||
pool->s[oldcount].index = newcount - 1;
|
|
||||||
return pool->s + newcount - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void dst_compile_slotpool_freeindex(DstSlotPool *pool, int32_t index) {
|
|
||||||
if (index > 0 && index < pool->count) {
|
|
||||||
pool->s[index].flags = 0;
|
|
||||||
if (index < pool->free)
|
|
||||||
pool->free = index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void dst_compile_slotpool_free(DstSlotPool *pool, DstSlot *s) {
|
|
||||||
DstSlot *oldfree = pool->s + pool->free;
|
|
||||||
if (s >= pool->s && s < (pool->s + pool->count)) {
|
|
||||||
if (s < oldfree) {
|
|
||||||
pool->free = s - pool->s;
|
|
||||||
}
|
|
||||||
s->flags = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Eneter a new scope */
|
/* Eneter a new scope */
|
||||||
void dst_compile_scope(DstCompiler *c, int newfn) {
|
void dst_compile_scope(DstCompiler *c, int newfn) {
|
||||||
int32_t newcount, oldcount;
|
int32_t newcount, oldcount;
|
||||||
@ -154,7 +76,7 @@ void dst_compile_scope(DstCompiler *c, int newfn) {
|
|||||||
? c->scopes[c->scopecount - 1].level
|
? c->scopes[c->scopecount - 1].level
|
||||||
: 0;
|
: 0;
|
||||||
newlevel = oldlevel + newfn;
|
newlevel = oldlevel + newfn;
|
||||||
if (newcount < c->scopecap) {
|
if (newcount > c->scopecap) {
|
||||||
int32_t newcap = 2 * newcount;
|
int32_t newcap = 2 * newcount;
|
||||||
c->scopes = realloc(c->scopes, newcap * sizeof(DstScope));
|
c->scopes = realloc(c->scopes, newcap * sizeof(DstScope));
|
||||||
if (NULL == c->scopes) {
|
if (NULL == c->scopes) {
|
||||||
@ -164,7 +86,7 @@ void dst_compile_scope(DstCompiler *c, int newfn) {
|
|||||||
}
|
}
|
||||||
scope = c->scopes + oldcount;
|
scope = c->scopes + oldcount;
|
||||||
c->scopecount = newcount;
|
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);
|
dst_table_init(&scope->constantrev, 4);
|
||||||
|
|
||||||
@ -206,7 +128,7 @@ DstSlot *dst_compile_constantslot(DstCompiler *c, DstValue x) {
|
|||||||
ret->flags = (1 << dst_type(x)) | DST_SLOT_CONSTANT | DST_SLOT_NOTEMPTY;
|
ret->flags = (1 << dst_type(x)) | DST_SLOT_CONSTANT | DST_SLOT_NOTEMPTY;
|
||||||
ret->index = -1;
|
ret->index = -1;
|
||||||
ret->constant = x;
|
ret->constant = x;
|
||||||
ret->envindex = scope->level;
|
ret->envindex = 0;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -331,72 +253,13 @@ DstSlot *dst_compile_resolve(
|
|||||||
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 a single value */
|
|
||||||
DstSlot *dst_compile_value(DstFormOptions opts) {
|
|
||||||
DstSlot *ret;
|
|
||||||
if (opts.compiler->recursion_guard <= 0) {
|
|
||||||
dst_compile_cerror(opts.compiler, opts.sourcemap, "recursed too deeply");
|
|
||||||
}
|
|
||||||
opts.compiler->recursion_guard--;
|
|
||||||
switch (dst_type(opts.x)) {
|
|
||||||
default:
|
|
||||||
ret = dst_compile_constantslot(opts.compiler, opts.x);
|
|
||||||
break;
|
|
||||||
case DST_SYMBOL:
|
|
||||||
{
|
|
||||||
const uint8_t *sym = dst_unwrap_symbol(opts.x);
|
|
||||||
if (dst_string_length(sym) > 0 && sym[0] != ':')
|
|
||||||
ret = dst_compile_resolve(opts.compiler, opts.sourcemap, sym);
|
|
||||||
else
|
|
||||||
ret = dst_compile_constantslot(opts.compiler, opts.x);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
/*case DST_TUPLE:*/
|
|
||||||
/*ret = dst_compile_tuple(opts); */
|
|
||||||
/*break;*/
|
|
||||||
/*case DST_ARRAY:*/
|
|
||||||
/*ret = dst_compile_array(opts); */
|
|
||||||
/*break;*/
|
|
||||||
/*case DST_STRUCT:*/
|
|
||||||
/*ret = dst_compile_struct(opts); */
|
|
||||||
/*break;*/
|
|
||||||
/*case DST_TABLE:*/
|
|
||||||
/*ret = dst_compile_table(opts);*/
|
|
||||||
/*break;*/
|
|
||||||
}
|
|
||||||
opts.compiler->recursion_guard++;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Emit a raw instruction with source mapping. */
|
/* Emit a raw instruction with source mapping. */
|
||||||
void dst_compile_emit(DstCompiler *c, const DstValue *sourcemap, uint32_t instr) {
|
void dst_compile_emit(DstCompiler *c, const DstValue *sourcemap, uint32_t instr) {
|
||||||
int32_t index = c->buffercount;
|
int32_t index = c->buffercount;
|
||||||
int32_t newcount = index + 1;
|
int32_t newcount = index + 1;
|
||||||
if (newcount > c->buffercap) {
|
if (newcount > c->buffercap) {
|
||||||
int32_t newcap = 2 * newcount;
|
int32_t newcap = 2 * newcount;
|
||||||
c->buffer = realloc(c->buffer, newcap * sizeof(int32_t));
|
c->buffer = realloc(c->buffer, newcap * sizeof(uint32_t));
|
||||||
c->mapbuffer = realloc(c->mapbuffer, newcap * sizeof(int32_t) * 2);
|
c->mapbuffer = realloc(c->mapbuffer, newcap * sizeof(int32_t) * 2);
|
||||||
if (NULL == c->buffer || NULL == c->mapbuffer) {
|
if (NULL == c->buffer || NULL == c->mapbuffer) {
|
||||||
DST_OUT_OF_MEMORY;
|
DST_OUT_OF_MEMORY;
|
||||||
@ -405,8 +268,8 @@ void dst_compile_emit(DstCompiler *c, const DstValue *sourcemap, uint32_t instr)
|
|||||||
}
|
}
|
||||||
c->buffercount = newcount;
|
c->buffercount = newcount;
|
||||||
if (NULL != sourcemap) {
|
if (NULL != sourcemap) {
|
||||||
c->mapbuffer[index][0] = dst_unwrap_integer(sourcemap[0]);
|
c->mapbuffer[index * 2] = dst_unwrap_integer(sourcemap[0]);
|
||||||
c->mapbuffer[index][1] = dst_unwrap_integer(sourcemap[1]);
|
c->mapbuffer[index * 2 + 1] = dst_unwrap_integer(sourcemap[1]);
|
||||||
}
|
}
|
||||||
c->buffer[index] = instr;
|
c->buffer[index] = instr;
|
||||||
}
|
}
|
||||||
@ -569,30 +432,168 @@ static void dst_compile_slot_post(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dst_compile_pop_funcdef(DstCompiler *c) {
|
/* Generate the return instruction for a slot. */
|
||||||
DstScope *scope = dst_compiler_topscope(c);
|
static void dst_compile_return(DstCompiler *c, const DstValue *sourcemap, DstSlot *s) {
|
||||||
|
if (s->flags & DST_SLOT_CONSTANT && dst_checktype(s->constant, DST_NIL)) {
|
||||||
|
dst_compile_emit(c, sourcemap, DOP_RETURN_NIL);
|
||||||
|
} else {
|
||||||
|
DstLocalSlot ls = dst_compile_slot_pre(
|
||||||
|
c, sourcemap, 0xFFFF, -1,
|
||||||
|
1, 1, s);
|
||||||
|
dst_compile_emit(c, sourcemap, DOP_RETURN | (ls.index << 8));
|
||||||
|
dst_compile_slot_post(c, sourcemap, ls);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DstSlot *dst_compile_def(DstFormOptions opts, int32_t argn, const DstValue *argv) {
|
||||||
|
DstScope *scope;
|
||||||
|
DstSlot *rvalue;
|
||||||
|
DstFormOptions subopts;
|
||||||
|
DstValue check;
|
||||||
|
if (argn != 2)
|
||||||
|
dst_compile_cerror(opts.compiler, opts.sourcemap, "expected 2 arguments");
|
||||||
|
if (!dst_checktype(argv[0], DST_SYMBOL))
|
||||||
|
dst_compile_cerror(opts.compiler, opts.sourcemap, "expected symbol");
|
||||||
|
scope = dst_compile_topscope(opts.compiler);
|
||||||
|
check = dst_table_get(&scope->symbols, argv[0]);
|
||||||
|
if (dst_checktype(check, DST_INTEGER)) {
|
||||||
|
dst_compile_cerror(opts.compiler, opts.sourcemap, "cannot redefine symbol");
|
||||||
|
}
|
||||||
|
subopts = dst_compile_getopts_index(opts, 1);
|
||||||
|
rvalue = dst_compile_value(subopts);
|
||||||
|
dst_table_put(&scope->symbols, argv[0], dst_wrap_userdata(rvalue));
|
||||||
|
return rvalue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Compile an array */
|
||||||
|
|
||||||
|
/* Compile a single value */
|
||||||
|
DstSlot *dst_compile_value(DstFormOptions opts) {
|
||||||
|
DstSlot *ret;
|
||||||
|
int doreturn = opts.flags & DST_FOPTS_TAIL;
|
||||||
|
if (opts.compiler->recursion_guard <= 0) {
|
||||||
|
dst_compile_cerror(opts.compiler, opts.sourcemap, "recursed too deeply");
|
||||||
|
}
|
||||||
|
opts.compiler->recursion_guard--;
|
||||||
|
switch (dst_type(opts.x)) {
|
||||||
|
default:
|
||||||
|
ret = dst_compile_constantslot(opts.compiler, opts.x);
|
||||||
|
break;
|
||||||
|
case DST_SYMBOL:
|
||||||
|
{
|
||||||
|
const uint8_t *sym = dst_unwrap_symbol(opts.x);
|
||||||
|
if (dst_string_length(sym) > 0 && sym[0] != ':') {
|
||||||
|
ret = dst_compile_resolve(opts.compiler, opts.sourcemap, sym);
|
||||||
|
} else {
|
||||||
|
ret = dst_compile_constantslot(opts.compiler, opts.x);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/*case DST_TUPLE:*/
|
||||||
|
/*ret = dst_compile_tuple(opts); */
|
||||||
|
/*break;*/
|
||||||
|
/*case DST_ARRAY:*/
|
||||||
|
/*ret = dst_compile_array(opts); */
|
||||||
|
/*break;*/
|
||||||
|
/*case DST_STRUCT:*/
|
||||||
|
/*ret = dst_compile_struct(opts); */
|
||||||
|
/*break;*/
|
||||||
|
/*case DST_TABLE:*/
|
||||||
|
/*ret = dst_compile_table(opts);*/
|
||||||
|
/*break;*/
|
||||||
|
}
|
||||||
|
if (doreturn) {
|
||||||
|
dst_compile_return(opts.compiler, opts.sourcemap, ret);
|
||||||
|
}
|
||||||
|
opts.compiler->recursion_guard++;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Compile a funcdef */
|
||||||
|
static DstFuncDef *dst_compile_pop_funcdef(DstCompiler *c) {
|
||||||
|
DstScope *scope = dst_compile_topscope(c);
|
||||||
DstFuncDef *def;
|
DstFuncDef *def;
|
||||||
|
|
||||||
/* Initialize funcdef */
|
/* Initialize funcdef */
|
||||||
def = dst_alloc(DST_MEMORY_FUNCDEF, sizeof(DstFuncDef));
|
def = dst_alloc(DST_MEMORY_FUNCDEF, sizeof(DstFuncDef));
|
||||||
def->environments = NULL;
|
def->environments_length = scope->envcount;
|
||||||
def->constants = NULL;
|
def->environments = malloc(sizeof(int32_t) * def->environments_length);
|
||||||
def->bytecode = NULL;
|
|
||||||
def->flags = 0;
|
|
||||||
def->slotcount = 0;
|
|
||||||
def->arity = 0;
|
|
||||||
def->constants_length = 0;
|
def->constants_length = 0;
|
||||||
def->bytecode_length = 0;
|
def->constants = malloc(sizeof(DstValue) * scope->constants.count);
|
||||||
def->environments_length = 1;
|
def->bytecode_length = c->buffercount - scope->bytecode_start;
|
||||||
|
def->bytecode = malloc(sizeof(uint32_t) * def->bytecode_length);
|
||||||
|
def->slotcount = scope->slots.count;
|
||||||
|
|
||||||
|
if (NULL == def->environments ||
|
||||||
|
NULL == def->constants ||
|
||||||
|
NULL == def->bytecode) {
|
||||||
|
DST_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(def->environments, scope->envs, def->environments_length * sizeof(int32_t));
|
||||||
|
memcpy(def->constants, scope->constants.data, def->constants_length * sizeof(DstValue));
|
||||||
|
memcpy(def->bytecode, c->buffer + c->buffercount, def->bytecode_length * sizeof(uint32_t));
|
||||||
|
|
||||||
|
if (c->mapbuffer) {
|
||||||
|
def->sourcemap = malloc(sizeof(uint32_t) * 2 * def->bytecode_length);
|
||||||
|
if (NULL == def->sourcemap) {
|
||||||
|
DST_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
memcpy(def->sourcemap, c->mapbuffer + 2 * c->buffercount, def->bytecode_length * 2 * sizeof(uint32_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reset bytecode gen */
|
||||||
|
c->buffercount = scope->bytecode_start;
|
||||||
|
|
||||||
|
/* Manually set arity and flags later */
|
||||||
|
def->flags = 0;
|
||||||
|
def->arity = 0;
|
||||||
|
|
||||||
|
/* Set some flags */
|
||||||
|
if (scope->flags & DST_SCOPE_ENV) {
|
||||||
|
def->flags |= DST_FUNCDEF_FLAG_NEEDSENV;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Pop the scope */
|
||||||
|
dst_compile_popscope(c);
|
||||||
|
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Print a slot for debugging */
|
||||||
|
/*static void print_slot(DstSlot *s) {*/
|
||||||
|
/*if (!(s->flags & DST_SLOT_NOTEMPTY)) {*/
|
||||||
|
/*printf("X");*/
|
||||||
|
/*} else if (s->flags & DST_SLOT_CONSTANT) {*/
|
||||||
|
/*dst_puts(dst_short_description(s->constant));*/
|
||||||
|
/*} else if (s->envindex > 0) {*/
|
||||||
|
/*printf("UP%d[%d]", s->envindex, s->index);*/
|
||||||
|
/*} else {*/
|
||||||
|
/*printf("%d", s->index);*/
|
||||||
|
/*}*/
|
||||||
|
/*}*/
|
||||||
|
|
||||||
|
/* Deinitialize a compiler struct */
|
||||||
|
static void dst_compile_cleanup(DstCompiler *c) {
|
||||||
|
while (c->scopecount)
|
||||||
|
dst_compile_popscope(c);
|
||||||
|
free(c->scopes);
|
||||||
|
free(c->buffer);
|
||||||
|
free(c->mapbuffer);
|
||||||
|
c->buffer = NULL;
|
||||||
|
c->mapbuffer = NULL;
|
||||||
|
c->scopes = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
DstCompileResults dst_compile(DstCompileOptions opts) {
|
DstCompileResults dst_compile(DstCompileOptions opts) {
|
||||||
DstCompiler c;
|
DstCompiler c;
|
||||||
|
DstFormOptions fopts;
|
||||||
|
DstSlot *s;
|
||||||
|
|
||||||
if (setjmp(c.on_error)) {
|
if (setjmp(c.on_error)) {
|
||||||
c.results.status = DST_COMPILE_ERROR;
|
c.results.status = DST_COMPILE_ERROR;
|
||||||
dst_compile_cleanup(&c);
|
dst_compile_cleanup(&c);
|
||||||
results.funcdef = NULL;
|
c.results.funcdef = NULL;
|
||||||
return c.results;
|
return c.results;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -602,9 +603,36 @@ DstCompileResults dst_compile(DstCompileOptions opts) {
|
|||||||
c.scopes = NULL;
|
c.scopes = NULL;
|
||||||
c.buffercap = 0;
|
c.buffercap = 0;
|
||||||
c.buffercount = 0;
|
c.buffercount = 0;
|
||||||
c->buffer = NULL;
|
c.buffer = NULL;
|
||||||
c->mapbuffer;
|
c.mapbuffer = NULL;
|
||||||
c->recursion_guard = 1024;
|
c.recursion_guard = 1024;
|
||||||
|
|
||||||
|
/* Push a function scope */
|
||||||
|
dst_compile_scope(&c, 1);
|
||||||
|
|
||||||
|
fopts.compiler = &c;
|
||||||
|
fopts.sourcemap = opts.sourcemap;
|
||||||
|
fopts.flags = DST_FOPTS_TAIL | DST_SLOTTYPE_ANY;
|
||||||
|
fopts.hint = 0;
|
||||||
|
fopts.x = opts.source;
|
||||||
|
|
||||||
|
/* Compile the value */
|
||||||
|
s = dst_compile_value(fopts);
|
||||||
|
|
||||||
|
c.results.funcdef = dst_compile_pop_funcdef(&c);
|
||||||
|
c.results.status = DST_COMPILE_OK;
|
||||||
|
|
||||||
|
dst_compile_cleanup(&c);
|
||||||
|
|
||||||
|
return c.results;
|
||||||
|
}
|
||||||
|
|
||||||
|
DstFunction *dst_compile_func(DstCompileResults res) {
|
||||||
|
if (res.status != DST_COMPILE_OK) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
DstFunction *func = dst_alloc(DST_MEMORY_FUNCTION, sizeof(DstFunction));
|
||||||
|
func->def = res.funcdef;
|
||||||
|
func->envs = NULL;
|
||||||
|
return func;
|
||||||
}
|
}
|
||||||
|
@ -38,10 +38,8 @@ typedef struct DstCFunctionOptimizer DstCFunctionOptimizer;
|
|||||||
|
|
||||||
#define DST_SLOT_CONSTANT 0x10000
|
#define DST_SLOT_CONSTANT 0x10000
|
||||||
#define DST_SLOT_NAMED 0x20000
|
#define DST_SLOT_NAMED 0x20000
|
||||||
#define DST_SLOT_RETURNED 0x40000
|
#define DST_SLOT_MUTABLE 0x40000
|
||||||
#define DST_SLOT_NIL 0x80000
|
#define DST_SLOT_NOTEMPTY 0x80000
|
||||||
#define DST_SLOT_MUTABLE 0x100000
|
|
||||||
#define DST_SLOT_NOTEMPTY 0x200000
|
|
||||||
|
|
||||||
#define DST_SLOTTYPE_ANY 0xFFFF
|
#define DST_SLOTTYPE_ANY 0xFFFF
|
||||||
|
|
||||||
@ -116,7 +114,7 @@ struct DstCompiler {
|
|||||||
int32_t buffercap;
|
int32_t buffercap;
|
||||||
int32_t buffercount;
|
int32_t buffercount;
|
||||||
uint32_t *buffer;
|
uint32_t *buffer;
|
||||||
int32_t (*mapbuffer)[2];
|
int32_t *mapbuffer;
|
||||||
|
|
||||||
DstCompileResults results;
|
DstCompileResults results;
|
||||||
};
|
};
|
||||||
@ -130,6 +128,7 @@ struct DstFormOptions {
|
|||||||
DstValue x;
|
DstValue x;
|
||||||
const DstValue *sourcemap;
|
const DstValue *sourcemap;
|
||||||
uint32_t flags; /* bit set of accepted primitive types */
|
uint32_t flags; /* bit set of accepted primitive types */
|
||||||
|
int32_t hint;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* A grouping of optimizations on a cfunction given certain conditions
|
/* A grouping of optimizations on a cfunction given certain conditions
|
||||||
|
92
core/compile_slotpool.c
Normal file
92
core/compile_slotpool.c
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2017 Calvin Rose
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to
|
||||||
|
* deal in the Software without restriction, including without limitation the
|
||||||
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
* sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
* IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <dst/dst.h>
|
||||||
|
#include "compile.h"
|
||||||
|
|
||||||
|
void dst_compile_slotpool_init(DstSlotPool *pool) {
|
||||||
|
pool->s = NULL;
|
||||||
|
pool->count = 0;
|
||||||
|
pool->free = 0;
|
||||||
|
pool->cap = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dst_compile_slotpool_deinit(DstSlotPool *pool) {
|
||||||
|
free(pool->s);
|
||||||
|
pool->s = NULL;
|
||||||
|
pool->cap = 0;
|
||||||
|
pool->count = 0;
|
||||||
|
pool->free = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dst_compile_slotpool_extend(DstSlotPool *pool, int32_t extra) {
|
||||||
|
int32_t i;
|
||||||
|
int32_t newcount = pool->count + extra;
|
||||||
|
if (newcount > pool->cap) {
|
||||||
|
int32_t newcap = 2 * newcount;
|
||||||
|
pool->s = realloc(pool->s, newcap * sizeof(DstSlot));
|
||||||
|
if (NULL == pool->s) {
|
||||||
|
DST_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
pool->cap = newcap;
|
||||||
|
}
|
||||||
|
/* Mark all new slots as free */
|
||||||
|
for (i = pool->count; i < newcount; i++) {
|
||||||
|
pool->s[i].flags = 0;
|
||||||
|
}
|
||||||
|
pool->count = newcount;
|
||||||
|
}
|
||||||
|
|
||||||
|
DstSlot *dst_compile_slotpool_alloc(DstSlotPool *pool) {
|
||||||
|
int32_t oldcount = pool->count;
|
||||||
|
int32_t newcount = oldcount == 0xF0 ? 0x101 : oldcount + 1;
|
||||||
|
int32_t index = newcount - 1;
|
||||||
|
while (pool->free < pool->count) {
|
||||||
|
if (!(pool->s[pool->free].flags & DST_SLOT_NOTEMPTY)) {
|
||||||
|
return pool->s + pool->free;
|
||||||
|
}
|
||||||
|
pool->free++;
|
||||||
|
}
|
||||||
|
dst_compile_slotpool_extend(pool, newcount - oldcount);
|
||||||
|
pool->s[index].flags = DST_SLOT_NOTEMPTY;
|
||||||
|
pool->s[index].index = index;
|
||||||
|
return pool->s + index;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dst_compile_slotpool_freeindex(DstSlotPool *pool, int32_t index) {
|
||||||
|
if (index > 0 && index < pool->count) {
|
||||||
|
pool->s[index].flags = 0;
|
||||||
|
if (index < pool->free)
|
||||||
|
pool->free = index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void dst_compile_slotpool_free(DstSlotPool *pool, DstSlot *s) {
|
||||||
|
DstSlot *oldfree = pool->s + pool->free;
|
||||||
|
if (s >= pool->s && s < (pool->s + pool->count)) {
|
||||||
|
if (s < oldfree) {
|
||||||
|
pool->free = s - pool->s;
|
||||||
|
}
|
||||||
|
s->flags = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -179,6 +179,10 @@ static void dst_mark_funcdef(DstFuncDef *def) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (def->source)
|
||||||
|
dst_mark_string(def->source);
|
||||||
|
if (def->sourcepath)
|
||||||
|
dst_mark_string(def->sourcepath);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dst_mark_function(DstFunction *func) {
|
static void dst_mark_function(DstFunction *func) {
|
||||||
@ -263,6 +267,7 @@ static void dst_deinit_block(DstGCMemoryHeader *block) {
|
|||||||
free(def->environments);
|
free(def->environments);
|
||||||
free(def->constants);
|
free(def->constants);
|
||||||
free(def->bytecode);
|
free(def->bytecode);
|
||||||
|
free(def->sourcemap);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -423,10 +423,12 @@ DstParseResult dst_parse(const uint8_t *src, int32_t len) {
|
|||||||
res.bytes_read = (int32_t) (newsrc - src);
|
res.bytes_read = (int32_t) (newsrc - src);
|
||||||
|
|
||||||
if (args.errmsg) {
|
if (args.errmsg) {
|
||||||
res.result.error = dst_cstring(args.errmsg);
|
res.error = dst_cstring(args.errmsg);
|
||||||
|
res.value = dst_wrap_nil();
|
||||||
res.map = NULL;
|
res.map = NULL;
|
||||||
} else {
|
} else {
|
||||||
res.result.value = dst_array_pop(&args.stack);
|
res.value = dst_array_pop(&args.stack);
|
||||||
|
res.error = NULL;
|
||||||
res.map = dst_unwrap_tuple(dst_array_pop(&args.mapstack));
|
res.map = dst_unwrap_tuple(dst_array_pop(&args.mapstack));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,7 +55,7 @@ int dst_sys_asm(DstValue *argv, int32_t argn) {
|
|||||||
dst_vm_fiber->ret = dst_wrap_function(dst_asm_func(res));
|
dst_vm_fiber->ret = dst_wrap_function(dst_asm_func(res));
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
dst_vm_fiber->ret = dst_wrap_string(res.result.error);
|
dst_vm_fiber->ret = dst_wrap_string(res.error);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -175,7 +175,7 @@ DstValue dst_table_next(DstTable *t, DstValue key) {
|
|||||||
const DstValue *dst_table_to_struct(DstTable *t) {
|
const DstValue *dst_table_to_struct(DstTable *t) {
|
||||||
int32_t i;
|
int32_t i;
|
||||||
DstValue *st = dst_struct_begin(t->count);
|
DstValue *st = dst_struct_begin(t->count);
|
||||||
for (i = 0; i < t->capacity; i++) {
|
for (i = 0; i < t->capacity; i += 2) {
|
||||||
if (!dst_checktype(t->data[i], DST_NIL))
|
if (!dst_checktype(t->data[i], DST_NIL))
|
||||||
dst_struct_put(st, t->data[i], t->data[i + 1]);
|
dst_struct_put(st, t->data[i], t->data[i + 1]);
|
||||||
}
|
}
|
||||||
|
4
dsttest/basic.dst
Normal file
4
dsttest/basic.dst
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
# A really basic for to compile. for testing the compiler. Will extend
|
||||||
|
# as compiler is extended.
|
||||||
|
123
|
||||||
|
|
@ -5,7 +5,7 @@
|
|||||||
{
|
{
|
||||||
arity 3
|
arity 3
|
||||||
source "source file path"
|
source "source file path"
|
||||||
varargs false
|
vararg false
|
||||||
# Name for reference by nested funcdefs
|
# Name for reference by nested funcdefs
|
||||||
name outerfunc
|
name outerfunc
|
||||||
# Contains the bytecode for this function. This can be assembly
|
# Contains the bytecode for this function. This can be assembly
|
||||||
@ -22,9 +22,7 @@
|
|||||||
(return 0)
|
(return 0)
|
||||||
]
|
]
|
||||||
# A source map is optional. The sourcemap corresponds with the byte code.
|
# A source map is optional. The sourcemap corresponds with the byte code.
|
||||||
# Each number is a 64 bit integer, the concatenation of two 32 bit integers.
|
# Each instruction has two source map entries, offset start and offset end.
|
||||||
# These integers represent source character index for each instruction.
|
|
||||||
# This format may change.
|
|
||||||
# map [
|
# map [
|
||||||
# 1
|
# 1
|
||||||
# 2
|
# 2
|
||||||
@ -45,7 +43,7 @@
|
|||||||
z
|
z
|
||||||
]
|
]
|
||||||
# Captured outer environments that are referenced
|
# Captured outer environments that are referenced
|
||||||
environments [ ]
|
captures [ ]
|
||||||
# Constants are an array or tuple. For named constants, use a tuple that begins with let
|
# Constants are an array or tuple. For named constants, use a tuple that begins with let
|
||||||
# For a literal tuple, use (quote tuple), or 'tuple. Without names, constants must be indexed
|
# For a literal tuple, use (quote tuple), or 'tuple. Without names, constants must be indexed
|
||||||
# from their number
|
# from their number
|
@ -18,7 +18,7 @@
|
|||||||
(return-nil)
|
(return-nil)
|
||||||
|
|
||||||
:extra
|
:extra
|
||||||
(push 2r1010101010101010)
|
(push 2)
|
||||||
]
|
]
|
||||||
constants [
|
constants [
|
||||||
(def lookup "0123456789abcdef")
|
(def lookup "0123456789abcdef")
|
@ -432,6 +432,11 @@ struct DstFuncDef {
|
|||||||
DstValue *constants; /* Contains strings, FuncDefs, etc. */
|
DstValue *constants; /* Contains strings, FuncDefs, etc. */
|
||||||
uint32_t *bytecode;
|
uint32_t *bytecode;
|
||||||
|
|
||||||
|
/* Various debug information */
|
||||||
|
int32_t *sourcemap;
|
||||||
|
const uint8_t *source;
|
||||||
|
const uint8_t *sourcepath;
|
||||||
|
|
||||||
uint32_t flags;
|
uint32_t flags;
|
||||||
int32_t slotcount; /* The amount of stack space required for the function */
|
int32_t slotcount; /* The amount of stack space required for the function */
|
||||||
int32_t arity; /* Not including varargs */
|
int32_t arity; /* Not including varargs */
|
||||||
@ -543,6 +548,7 @@ int dst_string_equalconst(const uint8_t *lhs, const uint8_t *rhs, int32_t rlen,
|
|||||||
const uint8_t *dst_string_unique(const uint8_t *buf, int32_t len);
|
const uint8_t *dst_string_unique(const uint8_t *buf, int32_t len);
|
||||||
const uint8_t *dst_cstring_unique(const char *s);
|
const uint8_t *dst_cstring_unique(const char *s);
|
||||||
const uint8_t *dst_description(DstValue x);
|
const uint8_t *dst_description(DstValue x);
|
||||||
|
const uint8_t *dst_short_description(DstValue x);
|
||||||
const uint8_t *dst_to_string(DstValue x);
|
const uint8_t *dst_to_string(DstValue x);
|
||||||
#define dst_cstringv(cstr) dst_wrap_string(dst_cstring(cstr))
|
#define dst_cstringv(cstr) dst_wrap_string(dst_cstring(cstr))
|
||||||
const uint8_t *dst_formatc(const char *format, ...);
|
const uint8_t *dst_formatc(const char *format, ...);
|
||||||
@ -608,10 +614,8 @@ typedef enum {
|
|||||||
typedef struct DstAssembleResult DstAssembleResult;
|
typedef struct DstAssembleResult DstAssembleResult;
|
||||||
typedef struct DstAssembleOptions DstAssembleOptions;
|
typedef struct DstAssembleOptions DstAssembleOptions;
|
||||||
struct DstAssembleResult {
|
struct DstAssembleResult {
|
||||||
union {
|
DstFuncDef *funcdef;
|
||||||
DstFuncDef *def;
|
const uint8_t *error;
|
||||||
const uint8_t *error;
|
|
||||||
} result;
|
|
||||||
int32_t error_start;
|
int32_t error_start;
|
||||||
int32_t error_end;
|
int32_t error_end;
|
||||||
DstAssembleStatus status;
|
DstAssembleStatus status;
|
||||||
@ -623,6 +627,7 @@ struct DstAssembleOptions {
|
|||||||
};
|
};
|
||||||
DstAssembleResult dst_asm(DstAssembleOptions opts);
|
DstAssembleResult dst_asm(DstAssembleOptions opts);
|
||||||
DstFunction *dst_asm_func(DstAssembleResult result);
|
DstFunction *dst_asm_func(DstAssembleResult result);
|
||||||
|
DstValue dst_disasm(DstFuncDef *def);
|
||||||
|
|
||||||
/* Treat similar types through uniform interfaces for iteration */
|
/* Treat similar types through uniform interfaces for iteration */
|
||||||
int dst_seq_view(DstValue seq, const DstValue **data, int32_t *len);
|
int dst_seq_view(DstValue seq, const DstValue **data, int32_t *len);
|
||||||
@ -659,10 +664,8 @@ typedef enum {
|
|||||||
} DstParseStatus;
|
} DstParseStatus;
|
||||||
typedef struct DstParseResult DstParseResult;
|
typedef struct DstParseResult DstParseResult;
|
||||||
struct DstParseResult {
|
struct DstParseResult {
|
||||||
union {
|
DstValue value;
|
||||||
DstValue value;
|
const uint8_t *error;
|
||||||
const uint8_t *error;
|
|
||||||
} result;
|
|
||||||
const DstValue *map;
|
const DstValue *map;
|
||||||
int32_t bytes_read;
|
int32_t bytes_read;
|
||||||
DstParseStatus status;
|
DstParseStatus status;
|
||||||
@ -698,11 +701,12 @@ typedef struct DstCompileResults {
|
|||||||
typedef struct DstCompileOptions {
|
typedef struct DstCompileOptions {
|
||||||
uint32_t flags;
|
uint32_t flags;
|
||||||
const DstValue *sourcemap;
|
const DstValue *sourcemap;
|
||||||
DstValue src;
|
DstValue source;
|
||||||
} DstCompileOptions;
|
} DstCompileOptions;
|
||||||
|
|
||||||
/* Compile source code into FuncDef. */
|
/* Compile source code into FuncDef. */
|
||||||
DstCompileResults dst_compile(DstCompileOptions opts);
|
DstCompileResults dst_compile(DstCompileOptions opts);
|
||||||
|
DstFunction *dst_compile_func(DstCompileResults results);
|
||||||
|
|
||||||
/* GC */
|
/* GC */
|
||||||
|
|
||||||
|
@ -7,9 +7,7 @@ int main() {
|
|||||||
DstAssembleResult ares;
|
DstAssembleResult ares;
|
||||||
DstFunction *func;
|
DstFunction *func;
|
||||||
|
|
||||||
printf("sizeof(DstValue) = %lu\n", sizeof(DstValue));
|
FILE *f = fopen("./dsttest/minimal.dsts", "rb");
|
||||||
|
|
||||||
FILE *f = fopen("./dsts/minimal.dsts", "rb");
|
|
||||||
fseek(f, 0, SEEK_END);
|
fseek(f, 0, SEEK_END);
|
||||||
long fsize = ftell(f);
|
long fsize = ftell(f);
|
||||||
fseek(f, 0, SEEK_SET); //same as rewind(f);
|
fseek(f, 0, SEEK_SET); //same as rewind(f);
|
||||||
@ -26,19 +24,19 @@ int main() {
|
|||||||
free(string);
|
free(string);
|
||||||
|
|
||||||
if (pres.status == DST_PARSE_ERROR) {
|
if (pres.status == DST_PARSE_ERROR) {
|
||||||
dst_puts(dst_formatc("parse error at %d: %S\n", pres.bytes_read, pres.result.error));
|
dst_puts(dst_formatc("parse error at %d: %S\n", pres.bytes_read, pres.error));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
assert(pres.status == DST_PARSE_OK);
|
assert(pres.status == DST_PARSE_OK);
|
||||||
dst_puts(dst_formatc("\nparse result: %v\n\n", pres.result.value));
|
dst_puts(dst_formatc("\nparse result: %v\n\n", pres.value));
|
||||||
|
|
||||||
opts.flags = 0;
|
opts.flags = 0;
|
||||||
opts.source = pres.result.value;
|
opts.source = pres.value;
|
||||||
opts.sourcemap = pres.map;
|
opts.sourcemap = pres.map;
|
||||||
|
|
||||||
ares = dst_asm(opts);
|
ares = dst_asm(opts);
|
||||||
if (ares.status == DST_ASSEMBLE_ERROR) {
|
if (ares.status == DST_ASSEMBLE_ERROR) {
|
||||||
dst_puts(dst_formatc("assembly error: %S\n", ares.result.error));
|
dst_puts(dst_formatc("assembly error: %S\n", ares.error));
|
||||||
dst_puts(dst_formatc("error location: %d, %d\n", ares.error_start, ares.error_end));
|
dst_puts(dst_formatc("error location: %d, %d\n", ares.error_start, ares.error_end));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -46,6 +44,8 @@ int main() {
|
|||||||
|
|
||||||
func = dst_asm_func(ares);
|
func = dst_asm_func(ares);
|
||||||
|
|
||||||
|
dst_puts(dst_formatc("\nfuncdef: %v\n\n", dst_disasm(ares.funcdef)));
|
||||||
|
|
||||||
dst_run(dst_wrap_function(func));
|
dst_run(dst_wrap_function(func));
|
||||||
dst_puts(dst_formatc("result: %v\n", dst_vm_fiber->ret));
|
dst_puts(dst_formatc("result: %v\n", dst_vm_fiber->ret));
|
||||||
|
|
||||||
|
55
unittests/compile_test.c
Normal file
55
unittests/compile_test.c
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
#include "unit.h"
|
||||||
|
#include <dst/dst.h>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
DstParseResult pres;
|
||||||
|
DstCompileOptions opts;
|
||||||
|
DstCompileResults cres;
|
||||||
|
DstFunction *func;
|
||||||
|
|
||||||
|
FILE *f = fopen("./dsttest/basic.dst", "rb");
|
||||||
|
fseek(f, 0, SEEK_END);
|
||||||
|
long fsize = ftell(f);
|
||||||
|
fseek(f, 0, SEEK_SET); //same as rewind(f);
|
||||||
|
|
||||||
|
char *string = malloc(fsize + 1);
|
||||||
|
fread(string, fsize, 1, f);
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
string[fsize] = 0;
|
||||||
|
|
||||||
|
dst_init();
|
||||||
|
|
||||||
|
pres = dst_parsec(string);
|
||||||
|
free(string);
|
||||||
|
|
||||||
|
if (pres.status == DST_PARSE_ERROR) {
|
||||||
|
dst_puts(dst_formatc("parse error at %d: %S\n", pres.bytes_read, pres.error));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
assert(pres.status == DST_PARSE_OK);
|
||||||
|
dst_puts(dst_formatc("\nparse result: %v\n\n", pres.value));
|
||||||
|
|
||||||
|
opts.flags = 0;
|
||||||
|
opts.source = pres.value;
|
||||||
|
opts.sourcemap = pres.map;
|
||||||
|
|
||||||
|
cres = dst_compile(opts);
|
||||||
|
if (cres.status == DST_COMPILE_ERROR) {
|
||||||
|
dst_puts(dst_formatc("compilation error: %S\n", cres.error));
|
||||||
|
dst_puts(dst_formatc("error location: %d, %d\n", cres.error_start, cres.error_end));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
assert(cres.status == DST_COMPILE_OK);
|
||||||
|
|
||||||
|
dst_puts(dst_formatc("\nfuncdef: %v\n\n", dst_disasm(cres.funcdef)));
|
||||||
|
|
||||||
|
func = dst_compile_func(cres);
|
||||||
|
|
||||||
|
dst_run(dst_wrap_function(func));
|
||||||
|
dst_puts(dst_formatc("result: %v\n", dst_vm_fiber->ret));
|
||||||
|
|
||||||
|
dst_deinit();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
@ -10,9 +10,9 @@ int main() {
|
|||||||
pres = dst_parsec("'(+ 1 () [] 3 5 :hello \"hi\\h41\")");
|
pres = dst_parsec("'(+ 1 () [] 3 5 :hello \"hi\\h41\")");
|
||||||
|
|
||||||
assert(pres.status == DST_PARSE_OK);
|
assert(pres.status == DST_PARSE_OK);
|
||||||
assert(dst_checktype(pres.result.value, DST_TUPLE));
|
assert(dst_checktype(pres.value, DST_TUPLE));
|
||||||
|
|
||||||
str = dst_to_string(pres.result.value);
|
str = dst_to_string(pres.value);
|
||||||
printf("%.*s\n", dst_string_length(str), (const char *) str);
|
printf("%.*s\n", dst_string_length(str), (const char *) str);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user