1
0
mirror of https://github.com/janet-lang/janet synced 2024-12-23 23:10:26 +00:00

Much work on compiler. Fixing bugs and gradually cleaning

up code. Generalized some vector code.
This commit is contained in:
bakpakin 2018-01-05 16:17:55 -05:00
parent e4735e14d2
commit 2771171658
34 changed files with 1356 additions and 1212 deletions

View File

@ -31,7 +31,7 @@ PREFIX=/usr/local
DST_TARGET=dst DST_TARGET=dst
DST_XXD=xxd DST_XXD=xxd
DEBUGGER=lldb DEBUGGER=lldb
DST_INTERNAL_HEADERS=$(addprefix core/,symcache.h opcodes.h strtod.h compile.h gc.h sourcemap.h) DST_INTERNAL_HEADERS=$(addprefix core/,symcache.h opcodes.h strtod.h compile.h gc.h sourcemap.h vector.h)
DST_HEADERS=$(addprefix include/dst/,dst.h dstconfig.h dsttypes.h dststate.h dststl.h) DST_HEADERS=$(addprefix include/dst/,dst.h dstconfig.h dsttypes.h dststate.h dststl.h)
############################# #############################
@ -48,9 +48,9 @@ all: $(DST_TARGET)
DST_CORE_SOURCES=$(addprefix core/,\ DST_CORE_SOURCES=$(addprefix core/,\
abstract.c array.c asm.c buffer.c compile.c\ abstract.c array.c asm.c buffer.c compile.c\
fiber.c func.c gc.c math.c parse.c sourcemap.c string.c\ fiber.c gc.c math.c parse.c sourcemap.c string.c\
stl.c strtod.c struct.c symcache.c table.c tuple.c util.c\ stl.c strtod.c struct.c symcache.c table.c tuple.c util.c\
value.c vm.c wrap.c) value.c vector.c vm.c wrap.c)
DST_CLIENT_SOURCES=$(addprefix client/,\ DST_CLIENT_SOURCES=$(addprefix client/,\
main.c) main.c)
@ -58,29 +58,6 @@ DST_CLIENT_SOURCES=$(addprefix client/,\
$(DST_TARGET): $(DST_CORE_SOURCES) $(DST_CLIENT_SOURCES) $(DST_ALL_HEADERS) $(DST_TARGET): $(DST_CORE_SOURCES) $(DST_CLIENT_SOURCES) $(DST_ALL_HEADERS)
$(CC) $(CFLAGS) $(DST_CORE_SOURCES) $(DST_CLIENT_SOURCES) -o $(DST_TARGET) $(CC) $(CFLAGS) $(DST_CORE_SOURCES) $(DST_CLIENT_SOURCES) -o $(DST_TARGET)
######################
##### Unit Tests #####
######################
CCU_FLAGS = $(CFLAGS) -DDST_UNIT_TEST
DST_UNIT_BINARIES=$(addprefix unittests/,\
asm_test.out array_test.out buffer_test.out compile_test.out fiber_test.out \
parse_test.out strtod_test.out table_test.out)
%.out: %.c $(DST_CORE_OBJECTS) $(DST_ALL_HEADERS) unittests/unit.h
$(CC) $(CCU_FLAGS) $(DST_CORE_OBJECTS) $< -o $@
unit: $(DST_UNIT_BINARIES)
unittests/array_test.out
unittests/asm_test.out
unittests/buffer_test.out
unittests/compile_test.out
unittests/fiber_test.out
unittests/parse_test.out
unittests/strtod_test.out
unittests/table_test.out
################### ###################
##### Testing ##### ##### Testing #####
################### ###################
@ -95,7 +72,7 @@ valgrind: $(DST_TARGET)
@ valgrind --leak-check=full -v ./$(DST_TARGET) @ valgrind --leak-check=full -v ./$(DST_TARGET)
test: $(DST_TARGET) test: $(DST_TARGET)
@ ./$(DST_TARGET) dsttests/basic.dst @ ./$(DST_TARGET) dsttest/suite0.dst
valtest: $(DST_TARGET) valtest: $(DST_TARGET)
valgrind --leak-check=full -v ./$(DST_TARGET) dsttests/basic.dst valgrind --leak-check=full -v ./$(DST_TARGET) dsttests/basic.dst

View File

@ -66,8 +66,11 @@ void dst_array_setcount(DstArray *array, int32_t count) {
if (count < 0) if (count < 0)
return; return;
if (count > array->count) { if (count > array->count) {
int32_t i;
dst_array_ensure(array, count + 1); dst_array_ensure(array, count + 1);
dst_memempty(array->data + array->count, count - array->count); for (i = array->count; i < count; i++) {
array->data[i] = dst_wrap_nil();
}
} }
array->count = count; array->count = count;
} }

View File

@ -90,11 +90,12 @@ struct DstAssembler {
DstFuncDef *def; DstFuncDef *def;
jmp_buf on_error; jmp_buf on_error;
const uint8_t *errmessage; const uint8_t *errmessage;
const uint8_t *name;
int32_t environments_capacity; int32_t environments_capacity;
int32_t defs_capacity;
int32_t bytecode_count; /* Used for calculating labels */ int32_t bytecode_count; /* Used for calculating labels */
DstValue name;
DstTable labels; /* symbol -> bytecode index */ DstTable labels; /* symbol -> bytecode index */
DstTable constants; /* symbol -> constant index */ DstTable constants; /* symbol -> constant index */
DstTable slots; /* symbol -> slot index */ DstTable slots; /* symbol -> slot index */
@ -166,39 +167,6 @@ static const DstInstructionDef dst_ops[] = {
{"typecheck", DIT_ST, DOP_TYPECHECK}, {"typecheck", DIT_ST, DOP_TYPECHECK},
}; };
/* Compare a DST string to a native 0 terminated c string. Used in the
* binary search for the instruction definition. */
static int dst_strcompare(const uint8_t *str, const char *other) {
int32_t len = dst_string_length(str);
int32_t index;
for (index = 0; index < len; index++) {
uint8_t c = str[index];
uint8_t k = ((const uint8_t *)other)[index];
if (c < k) return -1;
if (c > k) return 1;
if (k == '\0') break;
}
return (other[index] == '\0') ? 0 : -1;
}
/* Find an instruction definition given its name */
static const DstInstructionDef *dst_findi(const uint8_t *key) {
const DstInstructionDef *low = dst_ops;
const DstInstructionDef *hi = dst_ops + (sizeof(dst_ops) / sizeof(DstInstructionDef));
while (low < hi) {
const DstInstructionDef *mid = low + ((hi - low) / 2);
int comp = dst_strcompare(key, mid->name);
if (comp < 0) {
hi = mid;
} else if (comp > 0) {
low = mid + 1;
} else {
return mid;
}
}
return NULL;
}
/* Check a dst string against a bunch of test_strings. Return the /* Check a dst string against a bunch of test_strings. Return the
* index of the matching test_string, or -1 if not found. */ * index of the matching test_string, or -1 if not found. */
static int32_t strsearch(const uint8_t *str, const char **test_strings) { static int32_t strsearch(const uint8_t *str, const char **test_strings) {
@ -246,31 +214,36 @@ static void dst_asm_errorv(DstAssembler *a, const uint8_t *m) {
* to reference outer function environments, and may change the outer environment. * to reference outer function environments, and may change the outer environment.
* Returns the index of the environment in the assembler's environments, or -1 * Returns the index of the environment in the assembler's environments, or -1
* if not found. */ * if not found. */
/*static int32_t dst_asm_addenv(DstAssembler *a, DstValue envname) {*/ static int32_t dst_asm_addenv(DstAssembler *a, DstValue envname) {
/*DstValue check;*/ DstValue check;
/*DstFuncDef *def = a->def;*/ DstFuncDef *def = a->def;
/*int32_t oldlen;*/ int32_t envindex;
/*int64_t res;*/ int32_t res;
/*[> Check for memoized value <]*/ if (dst_equals(a->name, envname)) {
/*check = dst_table_get(&a->envs, envname);*/ return 0;
/*if (!dst_checktype(check, DST_NIL)) return dst_unwrap_integer(check);*/ }
/*if (NULL == a->parent) return -1;*/ /* Check for memoized value */
/*res = dst_asm_addenv(a->parent, envname);*/ check = dst_table_get(&a->envs, envname);
/*if (res < 0)*/ if (dst_checktype(check, DST_INTEGER)) return dst_unwrap_integer(check);
/*return res;*/ if (NULL == a->parent) return -1;
/*oldlen = def->environments_length;*/ res = dst_asm_addenv(a->parent, envname);
/*dst_table_put(&a->envs, envname, dst_wrap_integer(def->environments_length));*/ if (res < 0)
/*if (oldlen >= a->environments_capacity) {*/ return res;
/*int32_t newcap = 2 + 2 * oldlen;*/ envindex = def->environments_length;
/*def->environments = realloc(def->environments, newcap * sizeof(int32_t));*/ if (envindex == 0) envindex = 1;
/*if (NULL == def->environments) {*/ dst_table_put(&a->envs, envname, dst_wrap_integer(envindex));
/*DST_OUT_OF_MEMORY;*/ if (envindex >= a->environments_capacity) {
/*}*/ int32_t newcap = 2 * envindex;
/*a->environments_capacity = newcap;*/ def->environments = realloc(def->environments, newcap * sizeof(int32_t));
/*}*/ if (NULL == def->environments) {
/*def->environments[def->environments_length++] = (int32_t) res;*/ DST_OUT_OF_MEMORY;
/*return (int32_t) oldlen;*/ }
/*}*/ a->environments_capacity = newcap;
}
def->environments[envindex] = (int32_t) res;
def->environments_length = envindex + 1;
return envindex;
}
/* Parse an argument to an assembly instruction, and return the result as an /* Parse an argument to an assembly instruction, and return the result as an
* integer. This integer will need to be bounds checked. */ * integer. This integer will need to be bounds checked. */
@ -348,6 +321,13 @@ static int32_t doarg_1(
} else { } else {
goto error; goto error;
} }
if (argtype == DST_OAT_ENVIRONMENT && ret == -1) {
/* Add a new env */
ret = dst_asm_addenv(a, x);
if (ret < 0) {
dst_asm_errorv(a, dst_formatc("unknown environment %q", x));
}
}
break; break;
} }
} }
@ -530,14 +510,15 @@ static DstAssembleResult dst_asm1(DstAssembler *parent, DstAssembleOptions opts)
a.def = def; a.def = def;
a.parent = parent; a.parent = parent;
a.errmessage = NULL; a.errmessage = NULL;
a.name = NULL;
a.environments_capacity = 0; a.environments_capacity = 0;
a.bytecode_count = 0; a.bytecode_count = 0;
dst_table_init(&a.labels, 10); a.defs_capacity = 0;
dst_table_init(&a.constants, 10); a.name = dst_wrap_nil();
dst_table_init(&a.slots, 10); dst_table_init(&a.labels, 0);
dst_table_init(&a.envs, 10); dst_table_init(&a.constants, 0);
dst_table_init(&a.defs, 10); dst_table_init(&a.slots, 0);
dst_table_init(&a.envs, 0);
dst_table_init(&a.defs, 0);
/* Set error jump */ /* Set error jump */
if (setjmp(a.on_error)) { if (setjmp(a.on_error)) {
@ -557,8 +538,7 @@ static DstAssembleResult dst_asm1(DstAssembler *parent, DstAssembleOptions opts)
"expected struct or table for assembly source"); "expected struct or table for assembly source");
/* Check for function name */ /* Check for function name */
x = dst_get(s, dst_csymbolv("name")); a.name = dst_get(s, dst_csymbolv("name"));
if (dst_checktype(x, DST_SYMBOL)) a.name = dst_unwrap_symbol(x);
/* Set function arity */ /* Set function arity */
x = dst_get(s, dst_csymbolv("arity")); x = dst_get(s, dst_csymbolv("arity"));
@ -613,11 +593,11 @@ static DstAssembleResult dst_asm1(DstAssembler *parent, DstAssembleOptions opts)
const DstValue *t = dst_unwrap_tuple(ct); const DstValue *t = dst_unwrap_tuple(ct);
int32_t tcount = dst_tuple_length(t); int32_t tcount = dst_tuple_length(t);
const uint8_t *macro = dst_unwrap_symbol(t[0]); const uint8_t *macro = dst_unwrap_symbol(t[0]);
if (0 == dst_strcompare(macro, "quote")) { if (0 == dst_cstrcmp(macro, "quote")) {
def->constants[i] = t[1]; def->constants[i] = t[1];
} else if (tcount == 3 && } else if (tcount == 3 &&
dst_checktype(t[1], DST_SYMBOL) && dst_checktype(t[1], DST_SYMBOL) &&
0 == dst_strcompare(macro, "def")) { 0 == dst_cstrcmp(macro, "def")) {
def->constants[i] = t[2]; def->constants[i] = t[2];
dst_table_put(&a.constants, t[1], dst_wrap_integer(i)); dst_table_put(&a.constants, t[1], dst_wrap_integer(i));
} else { } else {
@ -633,10 +613,37 @@ static DstAssembleResult dst_asm1(DstAssembler *parent, DstAssembleOptions opts)
} }
/* Parse sub funcdefs */ /* Parse sub funcdefs */
/*x = dst_get(s, dst_csymbolv("closures"));*/ x = dst_get(s, dst_csymbolv("closures"));
/*if (dst_seq_view(x, &arr, &count)) {*/ if (dst_seq_view(x, &arr, &count)) {
int32_t i;
/*}*/ for (i = 0; i < count; i++) {
DstAssembleResult subres;
DstAssembleOptions subopts;
DstValue subname;
int32_t newlen;
subopts.source = arr[i];
subopts.flags = opts.flags;
subres = dst_asm1(&a, subopts);
if (subres.status != DST_ASSEMBLE_OK) {
dst_asm_errorv(&a, subres.error);
}
subname = dst_get(arr[i], dst_csymbolv("name"));
if (!dst_checktype(subname, DST_NIL)) {
dst_table_put(&a.defs, subname, dst_wrap_integer(def->defs_length));
}
newlen = def->defs_length + 1;
if (a.defs_capacity < newlen) {
int32_t newcap = newlen;
def->defs = realloc(def->defs, newcap * sizeof(DstFuncDef *));
if (NULL == def->defs) {
DST_OUT_OF_MEMORY;
}
a.defs_capacity = newcap;
}
def->defs[def->defs_length] = subres.funcdef;
def->defs_length = newlen;
}
}
/* Parse bytecode and labels */ /* Parse bytecode and labels */
x = dst_get(s, dst_csymbolv("bytecode")); x = dst_get(s, dst_csymbolv("bytecode"));
@ -675,7 +682,11 @@ static DstAssembleResult dst_asm1(DstAssembler *parent, DstAssembleOptions opts)
} else { } else {
dst_asm_assert(&a, dst_checktype(t[0], DST_SYMBOL), dst_asm_assert(&a, dst_checktype(t[0], DST_SYMBOL),
"expected symbol in assembly instruction"); "expected symbol in assembly instruction");
idef = dst_findi(dst_unwrap_symbol(t[0])); idef = dst_strbinsearch(
&dst_ops,
sizeof(dst_ops)/sizeof(DstInstructionDef),
sizeof(DstInstructionDef),
dst_unwrap_symbol(t[0]));
if (NULL == idef) if (NULL == idef)
dst_asm_errorv(&a, dst_formatc("unknown instruction %v", instr)); dst_asm_errorv(&a, dst_formatc("unknown instruction %v", instr));
op = read_instruction(&a, idef, t); op = read_instruction(&a, idef, t);

File diff suppressed because it is too large Load Diff

View File

@ -53,8 +53,6 @@ struct DstSlot {
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 */
/* Special forms that need support */ /* Special forms that need support */
/* cond /* cond
* while (continue, break) * while (continue, break)
@ -72,55 +70,42 @@ struct DstSlot {
#define DST_SCOPE_TOP 4 #define DST_SCOPE_TOP 4
#define DST_SCOPE_UNUSED 8 #define DST_SCOPE_UNUSED 8
/* A symbol and slot pair */
typedef struct SymPair {
const uint8_t *sym;
DstSlot slot;
} SymPair;
/* A lexical scope during compilation */ /* A lexical scope during compilation */
struct DstScope { struct DstScope {
/* Constants for this funcdef */ /* Constants for this funcdef */
int32_t ccount;
int32_t ccap;
DstValue *consts; DstValue *consts;
/* Map of symbols to slots. Use a simple linear scan for symbols. */ /* Map of symbols to slots. Use a simple linear scan for symbols. */
int32_t symcap; SymPair *syms;
int32_t symcount;
struct {
const uint8_t *sym;
DstSlot slot;
} *syms;
/* Bit vector with allocated slot indices. Used to allocate new slots */ /* Bit vector with allocated slot indices. Used to allocate new slots */
uint32_t *slots; uint32_t *slots;
int32_t scap;
int32_t smax; int32_t smax;
/* FuncDefs */ /* FuncDefs */
int32_t dcount;
int32_t dcap;
DstFuncDef **defs; DstFuncDef **defs;
/* Referenced closure environents. The values at each index correspond /* Referenced closure environents. The values at each index correspond
* to which index to get the environment from in the parent. The enironment * to which index to get the environment from in the parent. The environment
* 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 envcap;
int32_t bytecode_start; int32_t bytecode_start;
int flags; int 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; int recursion_guard;
int32_t scopecount;
int32_t scopecap;
DstScope *scopes; DstScope *scopes;
int32_t buffercap;
int32_t buffercount;
uint32_t *buffer; uint32_t *buffer;
int32_t *mapbuffer; int32_t *mapbuffer;
@ -156,32 +141,32 @@ typedef struct DstSpecial {
} DstSpecial; } DstSpecial;
/* An array of optimizers sorted by key */ /* An array of optimizers sorted by key */
extern DstCFunctionOptimizer dst_compiler_optimizers[255]; extern DstCFunctionOptimizer dstcr_optimizers[255];
/* Dispatch to correct form compiler */ /* Dispatch to correct form compiler */
DstSlot dst_compile_value(DstFormOptions opts); DstSlot dstc_value(DstFormOptions opts);
/****************************************************/ /****************************************************/
void dst_compile_error(DstCompiler *c, const DstValue *sourcemap, const uint8_t *m); void dstc_error(DstCompiler *c, const DstValue *sourcemap, const uint8_t *m);
void dst_compile_cerror(DstCompiler *c, const DstValue *sourcemap, const char *m); void dstc_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. */
DstFormOptions dst_compile_getopts_index(DstFormOptions opts, int32_t index); DstFormOptions dstc_getindex(DstFormOptions opts, int32_t index);
DstFormOptions dst_compile_getopts_key(DstFormOptions opts, DstValue key); DstFormOptions dstc_getkey(DstFormOptions opts, DstValue key);
DstFormOptions dst_compile_getopts_value(DstFormOptions opts, DstValue key); DstFormOptions dstc_getvalue(DstFormOptions opts, DstValue key);
void dst_compile_scope(DstCompiler *c, int newfn); void dstc_scope(DstCompiler *c, int newfn);
void dst_compile_popscope(DstCompiler *c); void dstc_popscope(DstCompiler *c);
DstSlot dst_compile_constantslot(DstValue x); DstSlot dstc_cslot(DstValue x);
void dst_compile_freeslot(DstCompiler *c, DstSlot slot); void dstc_freeslot(DstCompiler *c, DstSlot slot);
/* Search for a symbol */ /* Search for a symbol */
DstSlot dst_compile_resolve(DstCompiler *c, const DstValue *sourcemap, const uint8_t *sym); DstSlot dstc_resolve(DstCompiler *c, const DstValue *sourcemap, const uint8_t *sym);
/* Emit instructions. */ /* Emit instructions. */
void dst_compile_emit(DstCompiler *c, const DstValue *sourcemap, uint32_t instr); void dstc_emit(DstCompiler *c, const DstValue *sourcemap, uint32_t instr);
#endif #endif

View File

@ -101,17 +101,6 @@ void dst_fiber_pushn(DstFiber *fiber, const DstValue *arr, int32_t n) {
fiber->stacktop = newtop; fiber->stacktop = newtop;
} }
/* Pop a value off of the stack. Will not destroy a current stack frame.
* If there is nothing to pop of of the stack, return nil. */
DstValue dst_fiber_popvalue(DstFiber *fiber) {
int32_t newstacktop = fiber->stacktop - 1;
if (newstacktop < fiber->stackstart) {
return dst_wrap_nil();
}
fiber->stacktop = newstacktop;
return fiber->data[newstacktop];
}
/* Help set up function */ /* Help set up function */
static void funcframe_helper(DstFiber *fiber, DstFunction *func) { static void funcframe_helper(DstFiber *fiber, DstFunction *func) {
/* Check varargs */ /* Check varargs */
@ -168,6 +157,23 @@ void dst_fiber_funcframe(DstFiber *fiber, DstFunction *func) {
} }
/* If a frame has a closure environment, detach it from
* the stack and have it keep its own values */
static void dst_function_detach(DstFunction *func) {
/* Check for closure environment */
if (NULL != func->envs && NULL != func->envs[0]) {
DstFuncEnv *env = func->envs[0];
size_t s = sizeof(DstValue) * env->length;
DstValue *vmem = malloc(s);
if (NULL == vmem) {
DST_OUT_OF_MEMORY;
}
memcpy(vmem, env->as.fiber->data + env->offset, s);
env->offset = 0;
env->as.values = vmem;
}
}
/* Create a tail frame for a function */ /* Create a tail frame for a function */
void dst_fiber_funcframe_tail(DstFiber *fiber, DstFunction *func) { void dst_fiber_funcframe_tail(DstFiber *fiber, DstFunction *func) {
int32_t i; int32_t i;

View File

@ -1,40 +0,0 @@
/*
* Copyright (c) 2017 Calvin Rose
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include <dst/dst.h>
/* If a frame has a closure environment, detach it from
* the stack and have it keep its own values */
void dst_function_detach(DstFunction *func) {
/* Check for closure environment */
if (NULL != func->envs && NULL != func->envs[0]) {
DstFuncEnv *env = func->envs[0];
size_t s = sizeof(DstValue) * env->length;
DstValue *vmem = malloc(s);
if (NULL == vmem) {
DST_OUT_OF_MEMORY;
}
memcpy(vmem, env->as.fiber->data + env->offset, s);
env->offset = 0;
env->as.values = vmem;
}
}

View File

@ -40,7 +40,7 @@ static void dst_mark_funcdef(DstFuncDef *def);
static void dst_mark_function(DstFunction *func); static void dst_mark_function(DstFunction *func);
static void dst_mark_array(DstArray *array); static void dst_mark_array(DstArray *array);
static void dst_mark_table(DstTable *table); static void dst_mark_table(DstTable *table);
static void dst_mark_struct(const DstValue *st); static void dst_mark_struct(const DstKV *st);
static void dst_mark_tuple(const DstValue *tuple); static void dst_mark_tuple(const DstValue *tuple);
static void dst_mark_buffer(DstBuffer *buffer); static void dst_mark_buffer(DstBuffer *buffer);
static void dst_mark_string(const uint8_t *str); static void dst_mark_string(const uint8_t *str);
@ -85,6 +85,16 @@ static void dst_mark_many(const DstValue *values, int32_t n) {
} }
} }
/* Mark a bunch of key values items in memory */
static void dst_mark_kvs(const DstKV *kvs, int32_t n) {
const DstKV *end = kvs + n;
while (kvs < end) {
dst_mark(kvs->key);
dst_mark(kvs->value);
kvs++;
}
}
static void dst_mark_array(DstArray *array) { static void dst_mark_array(DstArray *array) {
if (dst_gc_reachable(array)) if (dst_gc_reachable(array))
return; return;
@ -96,14 +106,14 @@ static void dst_mark_table(DstTable *table) {
if (dst_gc_reachable(table)) if (dst_gc_reachable(table))
return; return;
dst_gc_mark(table); dst_gc_mark(table);
dst_mark_many(table->data, table->capacity); dst_mark_kvs(table->data, table->capacity);
} }
static void dst_mark_struct(const DstValue *st) { static void dst_mark_struct(const DstKV *st) {
if (dst_gc_reachable(dst_struct_raw(st))) if (dst_gc_reachable(dst_struct_raw(st)))
return; return;
dst_gc_mark(dst_struct_raw(st)); dst_gc_mark(dst_struct_raw(st));
dst_mark_many(st, dst_struct_capacity(st)); dst_mark_kvs(st, dst_struct_capacity(st));
} }
static void dst_mark_tuple(const DstValue *tuple) { static void dst_mark_tuple(const DstValue *tuple) {
@ -197,7 +207,7 @@ static void dst_deinit_block(DstGCMemoryHeader *block) {
dst_table_deinit((DstTable*) mem); dst_table_deinit((DstTable*) mem);
break; break;
case DST_MEMORY_FIBER: case DST_MEMORY_FIBER:
free(((DstFiber *) mem)->data); free(((DstFiber *)mem)->data);
break; break;
case DST_MEMORY_BUFFER: case DST_MEMORY_BUFFER:
dst_buffer_deinit((DstBuffer *) mem); dst_buffer_deinit((DstBuffer *) mem);
@ -220,6 +230,7 @@ static void dst_deinit_block(DstGCMemoryHeader *block) {
{ {
DstFuncDef *def = (DstFuncDef *)mem; DstFuncDef *def = (DstFuncDef *)mem;
/* TODO - get this all with one alloc and one free */ /* TODO - get this all with one alloc and one free */
free(def->defs);
free(def->environments); free(def->environments);
free(def->constants); free(def->constants);
free(def->bytecode); free(def->bytecode);
@ -241,7 +252,6 @@ void dst_sweep() {
previous = current; previous = current;
current->flags &= ~DST_MEM_REACHABLE; current->flags &= ~DST_MEM_REACHABLE;
} else { } else {
/*printf("freeing block %p\n", current);*/
dst_deinit_block(current); dst_deinit_block(current);
if (NULL != previous) { if (NULL != previous) {
previous->next = next; previous->next = next;
@ -254,22 +264,6 @@ void dst_sweep() {
} }
} }
/*static const char *memtypes[] = {*/
/*"none",*/
/*"string",*/
/*"symbol",*/
/*"array",*/
/*"tuple",*/
/*"table",*/
/*"struct",*/
/*"fiber",*/
/*"buffer",*/
/*"function",*/
/*"abstract",*/
/*"funcenv",*/
/*"funcdef"*/
/*};*/
/* Allocate some memory that is tracked for garbage collection */ /* Allocate some memory that is tracked for garbage collection */
void *dst_gcalloc(DstMemoryType type, size_t size) { void *dst_gcalloc(DstMemoryType type, size_t size) {
DstGCMemoryHeader *mdata; DstGCMemoryHeader *mdata;
@ -294,8 +288,6 @@ void *dst_gcalloc(DstMemoryType type, size_t size) {
mdata->next = dst_vm_blocks; mdata->next = dst_vm_blocks;
dst_vm_blocks = mdata; dst_vm_blocks = mdata;
/*printf("created block %p of size %lu, type %s\n", mem, size, memtypes[type]);*/
return mem + sizeof(DstGCMemoryHeader); return mem + sizeof(DstGCMemoryHeader);
} }
@ -361,7 +353,7 @@ int dst_gcunrootall(DstValue root) {
/* Free all allocated memory */ /* Free all allocated memory */
void dst_clear_memory() { void dst_clear_memory() {
DstGCMemoryHeader *current = dst_vm_blocks; DstGCMemoryHeader *current = dst_vm_blocks;
while (current) { while (NULL != current) {
dst_deinit_block(current); dst_deinit_block(current);
DstGCMemoryHeader *next = current->next; DstGCMemoryHeader *next = current->next;
free(current); free(current);

View File

@ -237,11 +237,13 @@ static const uint8_t *parse_recur(
default: default:
atom: atom:
{ {
int ascii = 1;
DstValue numcheck; DstValue numcheck;
const uint8_t *tokenend = src; const uint8_t *tokenend = src;
if (!is_symbol_char(*src)) goto unexpected_character; if (!is_symbol_char(*src)) goto unexpected_character;
while (tokenend < end && is_symbol_char(*tokenend)) while (tokenend < end && is_symbol_char(*tokenend)) {
tokenend++; if (*tokenend++ > 127) ascii = 0;
}
numcheck = dst_scan_number(src, tokenend - src); numcheck = dst_scan_number(src, tokenend - src);
if (!dst_checktype(numcheck, DST_NIL)) { if (!dst_checktype(numcheck, DST_NIL)) {
ret = numcheck; ret = numcheck;
@ -255,7 +257,9 @@ static const uint8_t *parse_recur(
if (*src >= '0' && *src <= '9') { if (*src >= '0' && *src <= '9') {
goto sym_nodigits; goto sym_nodigits;
} else { } else {
if (!valid_utf8(src, tokenend - src)) /* Don't do full utf8 check unless we have seen non ascii characters. */
int valid = ascii || valid_utf8(src, tokenend - src);
if (!valid)
goto invalid_utf8; goto invalid_utf8;
if (*src == ':') { if (*src == ':') {
ret = dst_stringv(src + 1, tokenend - src - 1); ret = dst_stringv(src + 1, tokenend - src - 1);
@ -415,8 +419,8 @@ static const uint8_t *parse_recur(
ret = dst_wrap_table(t); ret = dst_wrap_table(t);
submapping = dst_wrap_table(subt); submapping = dst_wrap_table(subt);
} else { } else {
DstValue *st = dst_struct_begin(n >> 1); DstKV *st = dst_struct_begin(n >> 1);
DstValue *subst = dst_struct_begin(n >> 1); DstKV *subst = dst_struct_begin(n >> 1);
for (i = n; i > 0; i -= 2) { for (i = n; i > 0; i -= 2) {
DstValue val = dst_array_pop(&args->stack); DstValue val = dst_array_pop(&args->stack);
DstValue key = dst_array_pop(&args->stack); DstValue key = dst_array_pop(&args->stack);

View File

@ -100,7 +100,7 @@ int dst_stl_array(int32_t argn, DstValue *argv, DstValue *ret) {
int dst_stl_table(int32_t argn, DstValue *argv, DstValue *ret) { int dst_stl_table(int32_t argn, DstValue *argv, DstValue *ret) {
int32_t i; int32_t i;
DstTable *table = dst_table(argn/2); DstTable *table = dst_table(argn >> 1);
if (argn & 1) { if (argn & 1) {
*ret = dst_cstringv("expected even number of arguments"); *ret = dst_cstringv("expected even number of arguments");
return 1; return 1;
@ -114,7 +114,7 @@ int dst_stl_table(int32_t argn, DstValue *argv, DstValue *ret) {
int dst_stl_struct(int32_t argn, DstValue *argv, DstValue *ret) { int dst_stl_struct(int32_t argn, DstValue *argv, DstValue *ret) {
int32_t i; int32_t i;
DstValue *st = dst_struct_begin(argn >> 1); DstKV *st = dst_struct_begin(argn >> 1);
if (argn & 1) { if (argn & 1) {
*ret = dst_cstringv("expected even number of arguments"); *ret = dst_cstringv("expected even number of arguments");
return 1; return 1;
@ -126,6 +126,49 @@ int dst_stl_struct(int32_t argn, DstValue *argv, DstValue *ret) {
return 0; return 0;
} }
int dst_stl_fiber(int32_t argn, DstValue *argv, DstValue *ret) {
DstFiber *fiber;
if (argn < 1) {
*ret = dst_cstringv("expected at least one argument");
return 1;
}
if (!dst_checktype(argv[0], DST_FUNCTION)) {
*ret = dst_cstringv("expected a function");
return 1;
}
fiber = dst_fiber(64);
dst_fiber_funcframe(fiber, dst_unwrap_function(argv[0]));
fiber->parent = dst_vm_fiber;
*ret = dst_wrap_fiber(fiber);
return 0;
}
int dst_stl_buffer(int32_t argn, DstValue *argv, DstValue *ret) {
DstBuffer *buffer = dst_buffer(10);
int32_t i;
for (i = 0; i < argn; ++i) {
const uint8_t *bytes = dst_to_string(argv[i]);
int32_t len = dst_string_length(bytes);
dst_buffer_push_bytes(buffer, bytes, len);
}
*ret = dst_wrap_buffer(buffer);
return 0;
}
int dst_stl_gensym(int32_t argn, DstValue *argv, DstValue *ret) {
if (argn > 1) {
*ret = dst_cstringv("expected one argument");
return 1;
}
if (argn == 0) {
*ret = dst_wrap_symbol(dst_symbol_gen(NULL, 0));
} else {
const uint8_t *s = dst_to_string(argv[0]);
*ret = dst_wrap_symbol(dst_symbol_gen(s, dst_string_length(s)));
}
return 0;
}
int dst_stl_get(int32_t argn, DstValue *argv, DstValue *ret) { int dst_stl_get(int32_t argn, DstValue *argv, DstValue *ret) {
int32_t i; int32_t i;
DstValue ds; DstValue ds;
@ -213,6 +256,9 @@ static DstReg stl[] = {
{"array", dst_stl_array}, {"array", dst_stl_array},
{"tuple", dst_stl_tuple}, {"tuple", dst_stl_tuple},
{"struct", dst_stl_struct}, {"struct", dst_stl_struct},
{"fiber", dst_stl_fiber},
{"buffer", dst_stl_buffer},
{"gensym", dst_stl_gensym},
{"asm", dst_stl_asm}, {"asm", dst_stl_asm},
{"disasm", dst_stl_disasm}, {"disasm", dst_stl_disasm},
{"get", dst_stl_get}, {"get", dst_stl_get},

View File

@ -410,13 +410,15 @@ static const char *dst_type_colors[16] = {
static void dst_description_helper(DstPrinter *p, DstValue x); static void dst_description_helper(DstPrinter *p, DstValue x);
/* Print a hastable view inline */ /* Print a hastable view inline */
static void dst_print_hashtable_inner(DstPrinter *p, const DstValue *data, int32_t len, int32_t cap) { static void dst_print_hashtable_inner(DstPrinter *p, const DstKV *data, int32_t len, int32_t cap) {
int32_t i; int32_t i;
int doindent = 0; int doindent = 0;
if (p->flags & DST_PRINTFLAG_INDENT) { if (p->flags & DST_PRINTFLAG_INDENT) {
if (len <= p->token_line_limit) { if (len <= p->token_line_limit) {
for (i = 0; i < cap; i += 2) { for (i = 0; i < cap; i++) {
if (is_print_ds(data[i]) || is_print_ds(data[i + 1])) { const DstKV *kv = data + i;
if (is_print_ds(kv->key) ||
is_print_ds(kv->value)) {
doindent = 1; doindent = 1;
break; break;
} }
@ -428,12 +430,13 @@ static void dst_print_hashtable_inner(DstPrinter *p, const DstValue *data, int32
if (doindent) { if (doindent) {
dst_buffer_push_u8(p->buffer, '\n'); dst_buffer_push_u8(p->buffer, '\n');
p->indent++; p->indent++;
for (i = 0; i < cap; i += 2) { for (i = 0; i < cap; i++) {
if (!dst_checktype(data[i], DST_NIL)) { const DstKV *kv = data + i;
if (!dst_checktype(kv->key, DST_NIL)) {
dst_print_indent(p); dst_print_indent(p);
dst_description_helper(p, data[i]); dst_description_helper(p, kv->key);
dst_buffer_push_u8(p->buffer, ' '); dst_buffer_push_u8(p->buffer, ' ');
dst_description_helper(p, data[i + 1]); dst_description_helper(p, kv->value);
dst_buffer_push_u8(p->buffer, '\n'); dst_buffer_push_u8(p->buffer, '\n');
} }
} }
@ -441,15 +444,16 @@ static void dst_print_hashtable_inner(DstPrinter *p, const DstValue *data, int32
dst_print_indent(p); dst_print_indent(p);
} else { } else {
int isfirst = 1; int isfirst = 1;
for (i = 0; i < cap; i += 2) { for (i = 0; i < cap; i++) {
if (!dst_checktype(data[i], DST_NIL)) { const DstKV *kv = data + i;
if (!dst_checktype(kv->key, DST_NIL)) {
if (isfirst) if (isfirst)
isfirst = 0; isfirst = 0;
else else
dst_buffer_push_u8(p->buffer, ' '); dst_buffer_push_u8(p->buffer, ' ');
dst_description_helper(p, data[i]); dst_description_helper(p, kv->key);
dst_buffer_push_u8(p->buffer, ' '); dst_buffer_push_u8(p->buffer, ' ');
dst_description_helper(p, data[i + 1]); dst_description_helper(p, kv->value);
} }
} }
} }
@ -496,6 +500,7 @@ static void dst_description_helper(DstPrinter *p, DstValue x) {
const char *close; const char *close;
int32_t len, cap; int32_t len, cap;
const DstValue *data; const DstValue *data;
const DstKV *kvs;
DstValue check; DstValue check;
p->depth--; p->depth--;
switch (dst_type(x)) { switch (dst_type(x)) {
@ -537,8 +542,8 @@ static void dst_description_helper(DstPrinter *p, DstValue x) {
dst_buffer_push_cstring(p->buffer, open); dst_buffer_push_cstring(p->buffer, open);
if (p->depth == 0) { if (p->depth == 0) {
dst_buffer_push_cstring(p->buffer, "..."); dst_buffer_push_cstring(p->buffer, "...");
} else if (dst_hashtable_view(x, &data, &len, &cap)) { } else if (dst_hashtable_view(x, &kvs, &len, &cap)) {
dst_print_hashtable_inner(p, data, len, cap); dst_print_hashtable_inner(p, kvs, len, cap);
} else if (dst_seq_view(x, &data, &len)) { } else if (dst_seq_view(x, &data, &len)) {
dst_print_seq_inner(p, data, len); dst_print_seq_inner(p, data, len);
} }

View File

@ -23,40 +23,35 @@
#include <dst/dst.h> #include <dst/dst.h>
#include "gc.h" #include "gc.h"
#define dst_struct_maphash(cap, hash) (((uint32_t)(hash) % (cap)) & 0xFFFFFFFE); #define dst_struct_maphash(cap, hash) ((uint32_t)(hash & (cap - 1)));
/* Begin creation of a struct */ /* Begin creation of a struct */
DstValue *dst_struct_begin(int32_t count) { DstKV *dst_struct_begin(int32_t count) {
/* This expression determines size of structs. It must be a pure
* function of count, and hold at least enough space for count /* Calculate capacity as power of 2 after 2 * count. */
* key value pairs. The minimum it could be is int32_t capacity = dst_tablen(2 * count);
* sizeof(int32_t) * 2 + 2 * count * sizeof(DstValue). Adding more space if (capacity < 0) capacity = dst_tablen(count);
* ensures that structs are less likely to have hash collisions. If more space
* is added or s is changed, change the macro dst_struct_capacity in internal.h */ size_t s = sizeof(int32_t) * 4 + (capacity * sizeof(DstKV));
int32_t capacity = 4 * count;
size_t s = sizeof(int32_t) * 2 + (capacity * sizeof(DstValue));
char *data = dst_gcalloc(DST_MEMORY_STRUCT, s); char *data = dst_gcalloc(DST_MEMORY_STRUCT, s);
DstValue *st = (DstValue *) (data + 2 * sizeof(int32_t)); DstKV *st = (DstKV *) (data + 4 * sizeof(int32_t));
dst_memempty(st, capacity); dst_memempty(st, capacity);
dst_struct_length(st) = count; dst_struct_length(st) = count;
/* Use the hash storage space as a counter to see how many items dst_struct_capacity(st) = capacity;
* were successfully added. If this number is not equal to the
* original number, we will need to remake the struct using
* only the kv pairs in the struct */
dst_struct_hash(st) = 0; dst_struct_hash(st) = 0;
return st; return st;
} }
/* Find an item in a struct */ /* Find an item in a struct */
static const DstValue *dst_struct_find(const DstValue *st, DstValue key) { static const DstKV *dst_struct_find(const DstKV *st, DstValue key) {
int32_t cap = dst_struct_capacity(st); int32_t cap = dst_struct_capacity(st);
int32_t index = dst_struct_maphash(cap, dst_hash(key)); int32_t index = dst_struct_maphash(cap, dst_hash(key));
int32_t i; int32_t i;
for (i = index; i < cap; i += 2) for (i = index; i < cap; i++)
if (dst_checktype(st[i], DST_NIL) || dst_equals(st[i], key)) if (dst_checktype(st[i].key, DST_NIL) || dst_equals(st[i].key, key))
return st + i; return st + i;
for (i = 0; i < index; i += 2) for (i = 0; i < index; i++)
if (dst_checktype(st[i], DST_NIL) || dst_equals(st[i], key)) if (dst_checktype(st[i].key, DST_NIL) || dst_equals(st[i].key, key))
return st + i; return st + i;
return NULL; return NULL;
} }
@ -64,7 +59,7 @@ static const DstValue *dst_struct_find(const DstValue *st, DstValue key) {
/* Put a kv pair into a struct that has not yet been fully constructed. /* Put a kv pair into a struct that has not yet been fully constructed.
* Nil keys and values are ignored, extra keys are ignore, and duplicate keys are * Nil keys and values are ignored, extra keys are ignore, and duplicate keys are
* ignored. */ * ignored. */
void dst_struct_put(DstValue *st, DstValue key, DstValue value) { void dst_struct_put(DstKV *st, DstValue key, DstValue value) {
int32_t cap = dst_struct_capacity(st); int32_t cap = dst_struct_capacity(st);
int32_t hash = dst_hash(key); int32_t hash = dst_hash(key);
int32_t index = dst_struct_maphash(cap, hash); int32_t index = dst_struct_maphash(cap, hash);
@ -74,14 +69,15 @@ void dst_struct_put(DstValue *st, DstValue key, DstValue value) {
/* Avoid extra items */ /* Avoid extra items */
if (dst_struct_hash(st) == dst_struct_length(st)) return; if (dst_struct_hash(st) == dst_struct_length(st)) return;
for (dist = 0, j = 0; j < 4; j += 2) for (dist = 0, j = 0; j < 4; j += 2)
for (i = bounds[j]; i < bounds[j + 1]; i += 2, dist += 2) { for (i = bounds[j]; i < bounds[j + 1]; i++, dist++) {
int status; int status;
int32_t otherhash; int32_t otherhash;
int32_t otherindex, otherdist; int32_t otherindex, otherdist;
DstKV *kv = st + i;
/* We found an empty slot, so just add key and value */ /* We found an empty slot, so just add key and value */
if (dst_checktype(st[i], DST_NIL)) { if (dst_checktype(kv->key, DST_NIL)) {
st[i] = key; kv->key = key;
st[i + 1] = value; kv->value = value;
/* Update the temporary count */ /* Update the temporary count */
dst_struct_hash(st)++; dst_struct_hash(st)++;
return; return;
@ -91,9 +87,9 @@ void dst_struct_put(DstValue *st, DstValue key, DstValue value) {
* hashing to ensure that equivalent structs that are contsructed * hashing to ensure that equivalent structs that are contsructed
* with different order have the same internal layout, and therefor * with different order have the same internal layout, and therefor
* will compare properly - i.e., {1 2 3 4} should equal {3 4 1 2}. */ * will compare properly - i.e., {1 2 3 4} should equal {3 4 1 2}. */
otherhash = dst_hash(st[i]); otherhash = dst_hash(kv->key);
otherindex = dst_struct_maphash(cap, otherhash); otherindex = dst_struct_maphash(cap, otherhash);
otherdist = (i + cap - otherindex) % cap; otherdist = (i + cap - otherindex) & (cap - 1);
if (dist < otherdist) if (dist < otherdist)
status = -1; status = -1;
else if (otherdist < dist) else if (otherdist < dist)
@ -103,95 +99,89 @@ void dst_struct_put(DstValue *st, DstValue key, DstValue value) {
else if (otherhash < hash) else if (otherhash < hash)
status = 1; status = 1;
else else
status = dst_compare(key, st[i]); status = dst_compare(key, kv->key);
/* If other is closer to their ideal slot */ /* If other is closer to their ideal slot */
if (status == 1) { if (status == 1) {
/* Swap current kv pair with pair in slot */ /* Swap current kv pair with pair in slot */
DstValue t1, t2; DstKV temp = *kv;
t1 = st[i]; kv->key = key;
t2 = st[i + 1]; kv->value = value;
st[i] = key; key = temp.key;
st[i + 1] = value; value = temp.value;
key = t1;
value = t2;
/* Save dist and hash of new kv pair */ /* Save dist and hash of new kv pair */
dist = otherdist; dist = otherdist;
hash = otherhash; hash = otherhash;
} else if (status == 0) { } else if (status == 0) {
/* This should not happen - it means /* This should not happen - it means
* than a key was added to the struct more than once */ * than a key was added to the struct more than once */
dst_exit("struct double put fail");
return; return;
} }
} }
} }
/* Finish building a struct */ /* Finish building a struct */
const DstValue *dst_struct_end(DstValue *st) { const DstKV *dst_struct_end(DstKV *st) {
if (dst_struct_hash(st) != dst_struct_length(st)) { if (dst_struct_hash(st) != dst_struct_length(st)) {
/* Error building struct, probably duplicate values. We need to rebuild /* Error building struct, probably duplicate values. We need to rebuild
* the struct using only the values that went in. The second creation should always * the struct using only the values that went in. The second creation should always
* succeed. */ * succeed. */
int32_t i, realCount; int32_t i, realCount;
DstValue *newst; DstKV *newst;
realCount = 0; realCount = 0;
for (i = 0; i < dst_struct_capacity(st); i += 2) { for (i = 0; i < dst_struct_capacity(st); i++) {
realCount += dst_checktype(st[i], DST_NIL) ? 1 : 0; DstKV *kv = st + i;
realCount += dst_checktype(kv->key, DST_NIL) ? 1 : 0;
} }
newst = dst_struct_begin(realCount); newst = dst_struct_begin(realCount);
for (i = 0; i < dst_struct_capacity(st); i += 2) { for (i = 0; i < dst_struct_capacity(st); i++) {
if (!dst_checktype(st[i], DST_NIL)) { DstKV *kv = st + i;
dst_struct_put(newst, st[i], st[i + 1]); if (!dst_checktype(kv->key, DST_NIL)) {
dst_struct_put(newst, kv->key, kv->value);
} }
} }
st = newst; st = newst;
} }
dst_struct_hash(st) = dst_array_calchash(st, dst_struct_capacity(st)); dst_struct_hash(st) = dst_kv_calchash(st, dst_struct_capacity(st));
return (const DstValue *)st; return (const DstKV *)st;
} }
/* Get an item from a struct */ /* Get an item from a struct */
DstValue dst_struct_get(const DstValue *st, DstValue key) { DstValue dst_struct_get(const DstKV *st, DstValue key) {
const DstValue *bucket = dst_struct_find(st, key); const DstKV *kv = dst_struct_find(st, key);
if (NULL == bucket || dst_checktype(*bucket, DST_NIL)) { if (NULL == kv || dst_checktype(kv->key, DST_NIL)) {
return dst_wrap_nil(); return dst_wrap_nil();
} else { } else {
return bucket[1]; return kv->value;
} }
} }
/* Get the next key in a struct */ /* Get the next key in a struct */
DstValue dst_struct_next(const DstValue *st, DstValue key) { const DstKV *dst_struct_next(const DstKV *st, const DstKV *kv) {
const DstValue *bucket, *end; const DstKV *end = st + dst_struct_capacity(st);
end = st + dst_struct_capacity(st); kv = (kv == NULL) ? st : kv + 1;
if (dst_checktype(key, DST_NIL)) { while (kv < end) {
bucket = st; if (!dst_checktype(kv->key, DST_NIL)) return kv;
} else { kv++;
bucket = dst_struct_find(st, key);
if (NULL == bucket || dst_checktype(*bucket, DST_NIL))
return dst_wrap_nil();
bucket += 2;
} }
for (; bucket < end; bucket += 2) { return NULL;
if (!dst_checktype(bucket[0], DST_NIL))
return bucket[0];
}
return dst_wrap_nil();
} }
/* Convert struct to table */ /* Convert struct to table */
DstTable *dst_struct_to_table(const DstValue *st) { DstTable *dst_struct_to_table(const DstKV *st) {
DstTable *table = dst_table(dst_struct_capacity(st)); DstTable *table = dst_table(dst_struct_capacity(st));
int32_t i; int32_t i;
for (i = 0; i < dst_struct_capacity(st); i += 2) { for (i = 0; i < dst_struct_capacity(st); i++) {
if (!dst_checktype(st[i], DST_NIL)) { const DstKV *kv = st + i;
dst_table_put(table, st[i], st[i + 1]); if (!dst_checktype(kv->key, DST_NIL)) {
dst_table_put(table, kv->key, kv->value);
} }
} }
return table; return table;
} }
/* Check if two structs are equal */ /* Check if two structs are equal */
int dst_struct_equal(const DstValue *lhs, const DstValue *rhs) { int dst_struct_equal(const DstKV *lhs, const DstKV *rhs) {
int32_t index; int32_t index;
int32_t llen = dst_struct_capacity(lhs); int32_t llen = dst_struct_capacity(lhs);
int32_t rlen = dst_struct_capacity(rhs); int32_t rlen = dst_struct_capacity(rhs);
@ -199,21 +189,21 @@ int dst_struct_equal(const DstValue *lhs, const DstValue *rhs) {
int32_t rhash = dst_struct_hash(rhs); int32_t rhash = dst_struct_hash(rhs);
if (llen != rlen) if (llen != rlen)
return 0; return 0;
if (lhash == 0)
lhash = dst_struct_hash(lhs) = dst_array_calchash(lhs, llen);
if (rhash == 0)
rhash = dst_struct_hash(rhs) = dst_array_calchash(rhs, rlen);
if (lhash != rhash) if (lhash != rhash)
return 0; return 0;
for (index = 0; index < llen; index++) { for (index = 0; index < llen; index++) {
if (!dst_equals(lhs[index], rhs[index])) const DstKV *l = lhs + index;
const DstKV *r = rhs + index;
if (!dst_equals(l->key, r->key))
return 0;
if (!dst_equals(l->value, r->value))
return 0; return 0;
} }
return 1; return 1;
} }
/* Compare structs */ /* Compare structs */
int dst_struct_compare(const DstValue *lhs, const DstValue *rhs) { int dst_struct_compare(const DstKV *lhs, const DstKV *rhs) {
int32_t i; int32_t i;
int32_t lhash = dst_struct_hash(lhs); int32_t lhash = dst_struct_hash(lhs);
int32_t rhash = dst_struct_hash(rhs); int32_t rhash = dst_struct_hash(rhs);
@ -223,16 +213,16 @@ int dst_struct_compare(const DstValue *lhs, const DstValue *rhs) {
return -1; return -1;
if (llen > rlen) if (llen > rlen)
return 1; return 1;
if (0 == lhash)
lhash = dst_struct_hash(lhs) = dst_array_calchash(lhs, llen);
if (0 == rhash)
rhash = dst_struct_hash(rhs) = dst_array_calchash(rhs, rlen);
if (lhash < rhash) if (lhash < rhash)
return -1; return -1;
if (lhash > rhash) if (lhash > rhash)
return 1; return 1;
for (i = 0; i < llen; ++i) { for (i = 0; i < llen; ++i) {
int comp = dst_compare(lhs[i], rhs[i]); const DstKV *l = lhs + i;
const DstKV *r = rhs + i;
int comp = dst_compare(l->key, r->key);
if (comp != 0) return comp;
comp = dst_compare(l->value, r->value);
if (comp != 0) return comp; if (comp != 0) return comp;
} }
return 0; return 0;

View File

@ -23,18 +23,23 @@
#include <dst/dst.h> #include <dst/dst.h>
#include "gc.h" #include "gc.h"
#define dst_table_maphash(cap, hash) (((uint32_t)(hash) % (cap)) & 0xFFFFFFFE) #define dst_table_maphash(cap, hash) ((uint32_t)(hash) & (cap - 1))
/* Initialize a table */ /* Initialize a table */
DstTable *dst_table_init(DstTable *table, int32_t capacity) { DstTable *dst_table_init(DstTable *table, int32_t capacity) {
DstValue *data; DstKV *data;
if (capacity < 2) capacity = 2; capacity = dst_tablen(capacity);
data = (DstValue *) dst_memalloc_empty(capacity); if (capacity) {
data = (DstKV *) dst_memalloc_empty(capacity);
if (NULL == data) { if (NULL == data) {
DST_OUT_OF_MEMORY; DST_OUT_OF_MEMORY;
} }
table->data = data; table->data = data;
table->capacity = capacity; table->capacity = capacity;
} else {
table->data = NULL;
table->capacity = 0;
}
table->count = 0; table->count = 0;
table->deleted = 0; table->deleted = 0;
return table; return table;
@ -53,35 +58,43 @@ DstTable *dst_table(int32_t capacity) {
/* Find the bucket that contains the given key. Will also return /* Find the bucket that contains the given key. Will also return
* bucket where key should go if not in the table. */ * bucket where key should go if not in the table. */
static DstValue *dst_table_find(DstTable *t, DstValue key) { static DstKV *dst_table_find(DstTable *t, DstValue key) {
int32_t index = dst_table_maphash(t->capacity, dst_hash(key)); int32_t index = dst_table_maphash(t->capacity, dst_hash(key));
int32_t i, j; int32_t i;
int32_t start[2], end[2]; DstKV *first_bucket = NULL;
DstValue *first_bucket = NULL; /* Higher half */
start[0] = index; end[0] = t->capacity; for (i = index; i < t->capacity; i++) {
start[1] = 0; end[1] = index; DstKV *kv = t->data + i;
for (j = 0; j < 2; ++j) { if (dst_checktype(kv->key, DST_NIL)) {
for (i = start[j]; i < end[j]; i += 2) { if (dst_checktype(kv->value, DST_NIL)) {
if (dst_checktype(t->data[i], DST_NIL)) { return kv;
if (dst_checktype(t->data[i + 1], DST_NIL)) {
/* Empty */
return t->data + i;
} else if (NULL == first_bucket) { } else if (NULL == first_bucket) {
/* Marked deleted and not seen free bucket yet. */ first_bucket = kv;
first_bucket = t->data + i;
} }
} else if (dst_equals(t->data[i], key)) { } else if (dst_equals(kv->key, key)) {
return t->data + i; return t->data + i;
} }
} }
/* Lower half */
for (i = 0; i < index; i++) {
DstKV *kv = t->data + i;
if (dst_checktype(kv->key, DST_NIL)) {
if (dst_checktype(kv->value, DST_NIL)) {
return kv;
} else if (NULL == first_bucket) {
first_bucket = kv;
}
} else if (dst_equals(kv->key, key)) {
return t->data + i;
}
} }
return first_bucket; return first_bucket;
} }
/* Resize the dictionary table. */ /* Resize the dictionary table. */
static void dst_table_rehash(DstTable *t, int32_t size) { static void dst_table_rehash(DstTable *t, int32_t size) {
DstValue *olddata = t->data; DstKV *olddata = t->data;
DstValue *newdata = (DstValue *) dst_memalloc_empty(size); DstKV *newdata = (DstKV *) dst_memalloc_empty(size);
if (NULL == newdata) { if (NULL == newdata) {
DST_OUT_OF_MEMORY; DST_OUT_OF_MEMORY;
} }
@ -90,11 +103,11 @@ static void dst_table_rehash(DstTable *t, int32_t size) {
t->data = newdata; t->data = newdata;
t->capacity = size; t->capacity = size;
t->deleted = 0; t->deleted = 0;
for (i = 0; i < oldcapacity; i += 2) { for (i = 0; i < oldcapacity; i++) {
if (!dst_checktype(olddata[i], DST_NIL)) { DstKV *kv = olddata + i;
DstValue *bucket = dst_table_find(t, olddata[i]); if (!dst_checktype(kv->key, DST_NIL)) {
bucket[0] = olddata[i]; DstKV *newkv = dst_table_find(t, kv->key);
bucket[1] = olddata[i + 1]; *newkv = *kv;
} }
} }
free(olddata); free(olddata);
@ -102,9 +115,9 @@ static void dst_table_rehash(DstTable *t, int32_t size) {
/* Get a value out of the object */ /* Get a value out of the object */
DstValue dst_table_get(DstTable *t, DstValue key) { DstValue dst_table_get(DstTable *t, DstValue key) {
DstValue *bucket = dst_table_find(t, key); DstKV *bucket = dst_table_find(t, key);
if (NULL != bucket && !dst_checktype(bucket[0], DST_NIL)) if (NULL != bucket && !dst_checktype(bucket->key, DST_NIL))
return bucket[1]; return bucket->value;
else else
return dst_wrap_nil(); return dst_wrap_nil();
} }
@ -112,13 +125,13 @@ DstValue dst_table_get(DstTable *t, DstValue key) {
/* Remove an entry from the dictionary. Return the value that /* Remove an entry from the dictionary. Return the value that
* was removed. */ * was removed. */
DstValue dst_table_remove(DstTable *t, DstValue key) { DstValue dst_table_remove(DstTable *t, DstValue key) {
DstValue *bucket = dst_table_find(t, key); DstKV *bucket = dst_table_find(t, key);
if (NULL != bucket && !dst_checktype(bucket[0], DST_NIL)) { if (NULL != bucket && !dst_checktype(bucket->key, DST_NIL)) {
DstValue ret = bucket[1]; DstValue ret = bucket->key;
t->count--; t->count--;
t->deleted++; t->deleted++;
bucket[0] = dst_wrap_nil(); bucket->key = dst_wrap_nil();
bucket[1] = dst_wrap_false(); bucket->value = dst_wrap_false();
return ret; return ret;
} else { } else {
return dst_wrap_nil(); return dst_wrap_nil();
@ -131,18 +144,18 @@ void dst_table_put(DstTable *t, DstValue key, DstValue value) {
if (dst_checktype(value, DST_NIL)) { if (dst_checktype(value, DST_NIL)) {
dst_table_remove(t, key); dst_table_remove(t, key);
} else { } else {
DstValue *bucket = dst_table_find(t, key); DstKV *bucket = dst_table_find(t, key);
if (NULL != bucket && !dst_checktype(bucket[0], DST_NIL)) { if (NULL != bucket && !dst_checktype(bucket->key, DST_NIL)) {
bucket[1] = value; bucket->value = value;
} else { } else {
if (NULL == bucket || 4 * (t->count + t->deleted) >= t->capacity) { if (NULL == bucket || 2 * (t->count + t->deleted + 1) > t->capacity) {
dst_table_rehash(t, 4 * t->count + 6); dst_table_rehash(t, dst_tablen(2 * t->count + 2));
} }
bucket = dst_table_find(t, key); bucket = dst_table_find(t, key);
if (dst_checktype(bucket[1], DST_FALSE)) if (dst_checktype(bucket->value, DST_FALSE))
--t->deleted; --t->deleted;
bucket[0] = key; bucket->key = key;
bucket[1] = value; bucket->value = value;
++t->count; ++t->count;
} }
} }
@ -151,54 +164,35 @@ void dst_table_put(DstTable *t, DstValue key, DstValue value) {
/* Clear a table */ /* Clear a table */
void dst_table_clear(DstTable *t) { void dst_table_clear(DstTable *t) {
int32_t capacity = t->capacity; int32_t capacity = t->capacity;
DstValue *data = t->data; DstKV *data = t->data;
dst_memempty(data, capacity); dst_memempty(data, capacity);
t->count = 0; t->count = 0;
t->deleted = 0; t->deleted = 0;
} }
/* Find next key in an object. Returns nil if no next key. */ /* Find next key in an object. Returns NULL if no next key. */
DstValue dst_table_next(DstTable *t, DstValue key) { const DstKV *dst_table_next(DstTable *t, const DstKV *kv) {
const DstValue *bucket, *end; DstKV *end = t->data + t->capacity;
end = t->data + t->capacity; kv = (kv == NULL) ? t->data : kv + 1;
if (dst_checktype(key, DST_NIL)) { while (kv < end) {
bucket = t->data; if (!dst_checktype(kv->key, DST_NIL))
} else { return kv;
bucket = dst_table_find(t, key); kv++;
if (NULL == bucket || dst_checktype(bucket[0], DST_NIL))
return dst_wrap_nil();
bucket += 2;
} }
for (; bucket < end; bucket += 2) { return NULL;
if (!dst_checktype(bucket[0], DST_NIL))
return bucket[0];
}
return dst_wrap_nil();
} }
/* Convert table to struct */ /* Convert table to struct */
const DstValue *dst_table_to_struct(DstTable *t) { const DstKV *dst_table_to_struct(DstTable *t) {
int32_t i; DstKV *st = dst_struct_begin(t->count);
DstValue *st = dst_struct_begin(t->count); DstKV *kv = t->data;
for (i = 0; i < t->capacity; i += 2) { DstKV *end = t->data + t->capacity;
if (!dst_checktype(t->data[i], DST_NIL)) { while (kv < end) {
dst_struct_put(st, t->data[i], t->data[i + 1]); if (!dst_checktype(kv->key, DST_NIL))
} dst_struct_put(st, kv->key, kv->value);
kv++;
} }
return dst_struct_end(st); return dst_struct_end(st);
} }
/* Merge a struct or another table into a table. */
void dst_table_merge(DstTable *t, DstValue other) {
int32_t count, cap, i;
const DstValue *hmap;
if (dst_hashtable_view(other, &hmap, &count, &cap)) {
for (i = 0; i < cap; i += 2) {
if (!dst_checktype(hmap[i], DST_NIL)) {
dst_table_put(t, hmap[i], hmap[i + 1]);
}
}
}
}
#undef dst_table_maphash #undef dst_table_maphash

View File

@ -59,6 +59,18 @@ int32_t dst_array_calchash(const DstValue *array, int32_t len) {
return (int32_t) hash; return (int32_t) hash;
} }
/* Computes hash of an array of values */
int32_t dst_kv_calchash(const DstKV *kvs, int32_t len) {
const DstKV *end = kvs + len;
uint32_t hash = 5381;
while (kvs < end) {
hash = (hash << 5) + hash + dst_hash(kvs->key);
hash = (hash << 5) + hash + dst_hash(kvs->value);
kvs++;
}
return (int32_t) hash;
}
/* Calculate hash for string */ /* Calculate hash for string */
int32_t dst_string_calchash(const uint8_t *str, int32_t len) { int32_t dst_string_calchash(const uint8_t *str, int32_t len) {
const uint8_t *end = str + len; const uint8_t *end = str + len;
@ -68,6 +80,58 @@ int32_t dst_string_calchash(const uint8_t *str, int32_t len) {
return (int32_t) hash; return (int32_t) hash;
} }
/* Calculate next power of 2. May overflow. If n is 0,
* will return 0. */
int32_t dst_tablen(int32_t n) {
n |= n >> 1;
n |= n >> 2;
n |= n >> 4;
n |= n >> 8;
n |= n >> 16;
return n + 1;
}
/* Compare a dst string with a cstring. more efficient than loading
* c string as a dst string. */
int dst_cstrcmp(const uint8_t *str, const char *other) {
int32_t len = dst_string_length(str);
int32_t index;
for (index = 0; index < len; index++) {
uint8_t c = str[index];
uint8_t k = ((const uint8_t *)other)[index];
if (c < k) return -1;
if (c > k) return 1;
if (k == '\0') break;
}
return (other[index] == '\0') ? 0 : -1;
}
/* Do a binary search on a static array of structs. Each struct must
* have a string as its first element, and the struct must be sorted
* lexogrpahically by that element. */
const void *dst_strbinsearch(
const void *tab,
size_t tabcount,
size_t itemsize,
const uint8_t *key) {
size_t low = 0;
size_t hi = tabcount;
while (low < hi) {
size_t mid = low + ((hi - low) / 2);
const char **item = (const char **)(tab + mid * itemsize);
const char *name = *item;
int comp = dst_cstrcmp(key, name);
if (comp < 0) {
hi = mid;
} else if (comp > 0) {
low = mid + 1;
} else {
return (const void *)item;
}
}
return NULL;
}
/* Read both tuples and arrays as c pointers + int32_t length. Return 1 if the /* Read both tuples and arrays as c pointers + int32_t length. Return 1 if the
* view can be constructed, 0 if an invalid type. */ * view can be constructed, 0 if an invalid type. */
int dst_seq_view(DstValue seq, const DstValue **data, int32_t *len) { int dst_seq_view(DstValue seq, const DstValue **data, int32_t *len) {
@ -76,7 +140,7 @@ int dst_seq_view(DstValue seq, const DstValue **data, int32_t *len) {
*len = dst_unwrap_array(seq)->count; *len = dst_unwrap_array(seq)->count;
return 1; return 1;
} else if (dst_checktype(seq, DST_TUPLE)) { } else if (dst_checktype(seq, DST_TUPLE)) {
*data = dst_unwrap_struct(seq); *data = dst_unwrap_tuple(seq);
*len = dst_tuple_length(dst_unwrap_struct(seq)); *len = dst_tuple_length(dst_unwrap_struct(seq));
return 1; return 1;
} }
@ -101,7 +165,7 @@ int dst_chararray_view(DstValue str, const uint8_t **data, int32_t *len) {
/* Read both structs and tables as the entries of a hashtable with /* Read both structs and tables as the entries of a hashtable with
* identical structure. Returns 1 if the view can be constructed and * identical structure. Returns 1 if the view can be constructed and
* 0 if the type is invalid. */ * 0 if the type is invalid. */
int dst_hashtable_view(DstValue tab, const DstValue **data, int32_t *len, int32_t *cap) { int dst_hashtable_view(DstValue tab, const DstKV **data, int32_t *len, int32_t *cap) {
if (dst_checktype(tab, DST_TABLE)) { if (dst_checktype(tab, DST_TABLE)) {
*data = dst_unwrap_table(tab)->data; *data = dst_unwrap_table(tab)->data;
*cap = dst_unwrap_table(tab)->capacity; *cap = dst_unwrap_table(tab)->capacity;

View File

@ -211,14 +211,14 @@ void dst_put(DstValue ds, DstValue key, DstValue value) {
/* Get the next key in an associative data structure. Used for iterating through an /* Get the next key in an associative data structure. Used for iterating through an
* associative data structure. */ * associative data structure. */
DstValue dst_next(DstValue ds, DstValue key) { const DstKV *dst_next(DstValue ds, const DstKV *kv) {
switch(dst_type(ds)) { switch(dst_type(ds)) {
default: default:
return dst_wrap_nil(); return NULL;
case DST_TABLE: case DST_TABLE:
return dst_table_next(dst_unwrap_table(ds), key); return (const DstKV *) dst_table_next(dst_unwrap_table(ds), kv);
case DST_STRUCT: case DST_STRUCT:
return dst_struct_next(dst_unwrap_struct(ds), key); return dst_struct_next(dst_unwrap_struct(ds), kv);
} }
} }

73
core/vector.c Normal file
View File

@ -0,0 +1,73 @@
/*
* 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 "vector.h"
void *dst_v_grow(void *v, int32_t increment, int32_t itemsize) {
int32_t dbl_cur = (NULL != v) ? 2 * dst_v__cap(v) : 0;
int32_t min_needed = dst_v_count(v) + increment;
int32_t m = dbl_cur > min_needed ? dbl_cur : min_needed;
int32_t *p = (int32_t *) realloc(v ? dst_v__raw(v) : 0, itemsize * m + sizeof(int32_t)*2);
if (NULL != p) {
if (!v) p[1] = 0;
p[0] = m;
return p + 2;
} else {
{
DST_OUT_OF_MEMORY;
}
return (void *) (2 * sizeof(int32_t)); // try to force a NULL pointer exception later
}
}
void *dst_v_copymem(void *v, int32_t itemsize) {
int32_t *p;
if (NULL == v) return NULL;
p = malloc(2 * sizeof(int32_t) + itemsize * dst_v__cap(v));
if (NULL != p) {
memcpy(p, dst_v__raw(v), 2 * sizeof(int32_t) + itemsize * dst_v__cnt(v));
return p + 2;
} else {
{
DST_OUT_OF_MEMORY;
}
return (void *) (2 * sizeof(int32_t)); // try to force a NULL pointer exception later
}
}
void *dst_v_flattenmem(void *v, int32_t itemsize) {
int32_t *p;
int32_t sizen;
if (NULL == v) return NULL;
sizen = itemsize * dst_v__cnt(v);
p = malloc(sizen);
if (NULL != p) {
memcpy(p, v, sizen);
return p;
} else {
{
DST_OUT_OF_MEMORY;
}
return NULL;
}
}

58
core/vector.h Normal file
View File

@ -0,0 +1,58 @@
/*
* 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_VECTOR_H_defined
#define DST_VECTOR_H_defined
/*
* Modified from
* https://github.com/nothings/stb/blob/master/stretchy_buffer.h
*/
/* This is mainly used code such as the assembler or compiler, which
* need vector like data structures that are not garbage collected
* and used only from C */
#include <dst/dst.h>
#define dst_v_free(v) (((v) != NULL) ? (free(dst_v__raw(v)), 0) : 0)
#define dst_v_push(v, x) (dst_v__maybegrow(v, 1), (v)[dst_v__cnt(v)++] = (x))
#define dst_v_pop(v) (dst_v_count(v) ? dst_v__cnt(v)-- : 0)
#define dst_v_count(v) (((v) != NULL) ? dst_v__cnt(v) : 0)
#define dst_v_add(v, n) (dst_v__maybegrow(v, n), dst_v_cnt(v) += (n), &(v)[dst_v__cnt(v) - (n)])
#define dst_v_last(v) ((v)[dst_v__cnt(v) - 1])
#define dst_v_copy(v) (dst_v_copymem((v), sizeof(*(v))))
#define dst_v_flatten(v) (dst_v_flattenmem((v), sizeof(*(v))))
#define dst_v__raw(v) ((int32_t *)(v) - 2)
#define dst_v__cap(v) dst_v__raw(v)[0]
#define dst_v__cnt(v) dst_v__raw(v)[1]
#define dst_v__needgrow(v, n) ((v) == NULL || dst_v__cnt(v) + (n) >= dst_v__cap(v))
#define dst_v__maybegrow(v, n) (dst_v__needgrow((v), (n)) ? dst_v__grow((v), (n)) : 0)
#define dst_v__grow(v, n) ((v) = dst_v_grow((v), (n), sizeof(*(v))))
void *dst_v_grow(void *v, int32_t increment, int32_t itemsize);
void *dst_v_copymem(void *v, int32_t itemsize);
void *dst_v_flattenmem(void *v, int32_t itemsize);
#endif

View File

@ -43,7 +43,7 @@ static int dst_update_fiber() {
return 1; return 1;
} }
} else { } else {
/* The root thread has termiated */ /* The root thread has terminated */
return 1; return 1;
} }
} }
@ -68,7 +68,7 @@ static int dst_continue(DstValue *returnreg) {
* Pulls out unsigned integers */ * Pulls out unsigned integers */
#define oparg(shift, mask) (((*pc) >> ((shift) << 3)) & (mask)) #define oparg(shift, mask) (((*pc) >> ((shift) << 3)) & (mask))
#define vm_throw(e) do { retreg = dst_wrap_string(dst_formatc("%s, %v", (e), dst_asm_decode_instruction(*pc))); goto vm_error; } while (0) #define vm_throw(e) do { retreg = dst_cstringv(e); goto vm_error; } while (0)
#define vm_assert(cond, e) do {if (!(cond)) vm_throw((e)); } while (0) #define vm_assert(cond, e) do {if (!(cond)) vm_throw((e)); } while (0)
#define vm_binop_integer(op) \ #define vm_binop_integer(op) \

View File

@ -31,14 +31,21 @@ void *dst_nanbox_to_pointer(DstValue x) {
* the high bits, and may make the pointer non-canocial on x86. If we switch * the high bits, and may make the pointer non-canocial on x86. If we switch
* to 47 bit pointers (which is what userspace uses on Windows, we can use * to 47 bit pointers (which is what userspace uses on Windows, we can use
* the single mask rather than two shifts. */ * the single mask rather than two shifts. */
#if defined (DST_NANBOX_47) || defined (DST_32)
x.i64 &= DST_NANBOX_POINTERBITS;
#else
x.i64 = (x.i64 << 16) >> 16; x.i64 = (x.i64 << 16) >> 16;
#endif
return x.pointer; return x.pointer;
} }
DstValue dst_nanbox_from_pointer(void *p, uint64_t tagmask) { DstValue dst_nanbox_from_pointer(void *p, uint64_t tagmask) {
DstValue ret; DstValue ret;
ret.pointer = p; ret.pointer = p;
#if defined (DST_NANBOX_47) || defined (DST_32)
#else
ret.u64 &= DST_NANBOX_POINTERBITS; ret.u64 &= DST_NANBOX_POINTERBITS;
#endif
ret.u64 |= tagmask; ret.u64 |= tagmask;
return ret; return ret;
} }
@ -46,7 +53,10 @@ DstValue dst_nanbox_from_pointer(void *p, uint64_t tagmask) {
DstValue dst_nanbox_from_cpointer(const void *p, uint64_t tagmask) { DstValue dst_nanbox_from_cpointer(const void *p, uint64_t tagmask) {
DstValue ret; DstValue ret;
ret.cpointer = p; ret.cpointer = p;
#if defined (DST_NANBOX_47) || defined (DST_32)
#else
ret.u64 &= DST_NANBOX_POINTERBITS; ret.u64 &= DST_NANBOX_POINTERBITS;
#endif
ret.u64 |= tagmask; ret.u64 |= tagmask;
return ret; return ret;
} }
@ -68,18 +78,21 @@ DstValue dst_nanbox_from_bits(uint64_t bits) {
void *dst_nanbox_memalloc_empty(int32_t count) { void *dst_nanbox_memalloc_empty(int32_t count) {
int32_t i; int32_t i;
void *mem = malloc(count * sizeof(DstValue)); void *mem = malloc(count * sizeof(DstKV));
DstValue *mmem = (DstValue *)mem; DstKV *mmem = (DstKV *)mem;
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
mmem[i] = dst_wrap_nil(); DstKV *kv = mmem + i;
kv->key = dst_wrap_nil();
kv->value = dst_wrap_nil();
} }
return mem; return mem;
} }
void dst_nanbox_memempty(DstValue *mem, int32_t count) { void dst_nanbox_memempty(DstKV *mem, int32_t count) {
int32_t i; int32_t i;
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
mem[i] = dst_wrap_nil(); mem[i].key = dst_wrap_nil();
mem[i].value = dst_wrap_nil();
} }
} }
@ -134,8 +147,8 @@ DST_WRAP_DEFINE(string, const uint8_t *, DST_STRING, cpointer)
DST_WRAP_DEFINE(symbol, const uint8_t *, DST_SYMBOL, cpointer) DST_WRAP_DEFINE(symbol, const uint8_t *, DST_SYMBOL, cpointer)
DST_WRAP_DEFINE(array, DstArray *, DST_ARRAY, pointer) DST_WRAP_DEFINE(array, DstArray *, DST_ARRAY, pointer)
DST_WRAP_DEFINE(tuple, const DstValue *, DST_TUPLE, cpointer) DST_WRAP_DEFINE(tuple, const DstValue *, DST_TUPLE, cpointer)
DST_WRAP_DEFINE(struct, const DstValue *, DST_STRUCT, cpointer) DST_WRAP_DEFINE(struct, const DstKV *, DST_STRUCT, cpointer)
DST_WRAP_DEFINE(thread, DstFiber *, DST_FIBER, pointer) DST_WRAP_DEFINE(fiber, DstFiber *, DST_FIBER, pointer)
DST_WRAP_DEFINE(buffer, DstBuffer *, DST_BUFFER, pointer) DST_WRAP_DEFINE(buffer, DstBuffer *, DST_BUFFER, pointer)
DST_WRAP_DEFINE(function, DstFunction *, DST_FUNCTION, pointer) DST_WRAP_DEFINE(function, DstFunction *, DST_FUNCTION, pointer)
DST_WRAP_DEFINE(cfunction, DstCFunction, DST_CFUNCTION, pointer) DST_WRAP_DEFINE(cfunction, DstCFunction, DST_CFUNCTION, pointer)

View File

@ -47,23 +47,49 @@
(assert (>= 6 5 4 4 3 2 1) "greater than or equal to integers") (assert (>= 6 5 4 4 3 2 1) "greater than or equal to integers")
(assert (>= 6.0 5.0 4.0 4.0 3.0 2.0 1.0) "greater than or equal to reals") (assert (>= 6.0 5.0 4.0 4.0 3.0 2.0 1.0) "greater than or equal to reals")
(assert (< nil 1.0 1 false true "hi" (assert (< nil false true
(fiber (fn [x] x))
1 1.0 "hi"
(quote hello) (quote hello)
(array 1 2 3) (array 1 2 3)
(tuple 1 2 3) (tuple 1 2 3)
(table "a" "b" "c" false) (table "a" "b" "c" "d")
(struct 1 2) (struct 1 2 3 4)
(fiber (fn [x] x))
(buffer "hi") (buffer "hi")
(fn [x] (+ x x)) (fn [x] (+ x x))
+) "type ordering") +) "type ordering")
(assert (= (get {} 1) nil) "get nil from empty struct")
(assert (= (get @{} 1) nil) "get nil from empty table")
(assert (= (get {:boop :bap} :boop) :bap) "get non nil from struct")
(assert (= (get @{:boop :bap} :boop) :bap) "get non nil from table")
(assert (put @{} :boop :bap) "can add to empty table")
(assert (put @{1 3} :boop :bap) "can add to non-empty table")
(assert (not false) "false literal") (assert (not false) "false literal")
(assert true "true literal") (assert true "true literal")
(assert (not nil) "nil literal") (assert (not nil) "nil literal")
(assert (= 7 (| 3 4)) "bit or") (assert (= 7 (| 3 4)) "bit or")
(assert (= 0 (& 3 4)) "bit and") (assert (= 0 (& 3 4)) "bit and")
# Set global variables to prevent some compiler optimizations that defeat point of the test
(var zero 0)
(var one 1)
(var two 2)
(var three 3)
(var plus +)
(assert (= 22 (plus one (plus 1 2 two) (plus 8 (plus zero 1) 4 three))) "nested function calls")
# Mcarthy's 91 function
(var f91 nil)
(varset! f91 (fn [n] (if (> n 100) (- n 10) (f91 (f91 (+ n 11))))))
(assert (= 91 (f91 10)), "f91(10) = 91")
(assert (= 91 (f91 100)), "f91(100) = 91")
(assert (= 91 (f91 101)), "f91(101) = 91")
(assert (= 92 (f91 102)), "f91(102) = 92")
(assert (= 93 (f91 103)), "f91(103) = 93")
(assert (= 94 (f91 104)), "f91(104) = 94")
(assert (= "hello" :hello) "keyword syntax for strings") (assert (= "hello" :hello) "keyword syntax for strings")
(assert (= '(1 2 3) (quote (1 2 3)) (tuple 1 2 3)) "quote shorthand") (assert (= '(1 2 3) (quote (1 2 3)) (tuple 1 2 3)) "quote shorthand")

View File

@ -95,18 +95,19 @@ const uint8_t *dst_symbol_gen(const uint8_t *buf, int32_t len);
#define dst_csymbolv(cstr) dst_wrap_symbol(dst_csymbol(cstr)) #define dst_csymbolv(cstr) dst_wrap_symbol(dst_csymbol(cstr))
/* Structs */ /* Structs */
#define dst_struct_raw(t) ((int32_t *)(t) - 2) #define dst_struct_raw(t) ((int32_t *)(t) - 4)
#define dst_struct_length(t) (dst_struct_raw(t)[0]) #define dst_struct_length(t) (dst_struct_raw(t)[0])
#define dst_struct_capacity(t) (dst_struct_length(t) * 4) #define dst_struct_capacity(t) (dst_struct_raw(t)[1])
#define dst_struct_hash(t) ((dst_struct_raw(t)[1])) #define dst_struct_hash(t) (dst_struct_raw(t)[2])
DstValue *dst_struct_begin(int32_t count); /* Do something with the 4th header slot - flags? */
void dst_struct_put(DstValue *st, DstValue key, DstValue value); DstKV *dst_struct_begin(int32_t count);
const DstValue *dst_struct_end(DstValue *st); void dst_struct_put(DstKV *st, DstValue key, DstValue value);
DstValue dst_struct_get(const DstValue *st, DstValue key); const DstKV *dst_struct_end(DstKV *st);
DstValue dst_struct_next(const DstValue *st, DstValue key); DstValue dst_struct_get(const DstKV *st, DstValue key);
DstTable *dst_struct_to_table(const DstValue *st); const DstKV *dst_struct_next(const DstKV *st, const DstKV *kv);
int dst_struct_equal(const DstValue *lhs, const DstValue *rhs); DstTable *dst_struct_to_table(const DstKV *st);
int dst_struct_compare(const DstValue *lhs, const DstValue *rhs); int dst_struct_equal(const DstKV *lhs, const DstKV *rhs);
int dst_struct_compare(const DstKV *lhs, const DstKV *rhs);
/* Table functions */ /* Table functions */
DstTable *dst_table(int32_t capacity); DstTable *dst_table(int32_t capacity);
@ -115,8 +116,8 @@ void dst_table_deinit(DstTable *table);
DstValue dst_table_get(DstTable *t, DstValue key); DstValue dst_table_get(DstTable *t, DstValue key);
DstValue dst_table_remove(DstTable *t, DstValue key); DstValue dst_table_remove(DstTable *t, DstValue key);
void dst_table_put(DstTable *t, DstValue key, DstValue value); void dst_table_put(DstTable *t, DstValue key, DstValue value);
DstValue dst_table_next(DstTable *t, DstValue key); const DstKV *dst_table_next(DstTable *t, const DstKV *kv);
const DstValue *dst_table_to_struct(DstTable *t); const DstKV *dst_table_to_struct(DstTable *t);
void dst_table_merge(DstTable *t, DstValue other); void dst_table_merge(DstTable *t, DstValue other);
/* Fiber */ /* Fiber */
@ -129,15 +130,11 @@ void dst_fiber_push(DstFiber *fiber, DstValue x);
void dst_fiber_push2(DstFiber *fiber, DstValue x, DstValue y); void dst_fiber_push2(DstFiber *fiber, DstValue x, DstValue y);
void dst_fiber_push3(DstFiber *fiber, DstValue x, DstValue y, DstValue z); void dst_fiber_push3(DstFiber *fiber, DstValue x, DstValue y, DstValue z);
void dst_fiber_pushn(DstFiber *fiber, const DstValue *arr, int32_t n); void dst_fiber_pushn(DstFiber *fiber, const DstValue *arr, int32_t n);
DstValue dst_fiber_popvalue(DstFiber *fiber);
void dst_fiber_funcframe(DstFiber *fiber, DstFunction *func); void dst_fiber_funcframe(DstFiber *fiber, DstFunction *func);
void dst_fiber_funcframe_tail(DstFiber *fiber, DstFunction *func); void dst_fiber_funcframe_tail(DstFiber *fiber, DstFunction *func);
void dst_fiber_cframe(DstFiber *fiber); void dst_fiber_cframe(DstFiber *fiber);
void dst_fiber_popframe(DstFiber *fiber); void dst_fiber_popframe(DstFiber *fiber);
/* Functions */
void dst_function_detach(DstFunction *func);
/* Assembly */ /* Assembly */
DstAssembleResult dst_asm(DstAssembleOptions opts); DstAssembleResult dst_asm(DstAssembleOptions opts);
DstFunction *dst_asm_func(DstAssembleResult result); DstFunction *dst_asm_func(DstAssembleResult result);
@ -147,7 +144,7 @@ DstValue dst_asm_decode_instruction(uint32_t instr);
/* 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);
int dst_chararray_view(DstValue str, const uint8_t **data, int32_t *len); int dst_chararray_view(DstValue str, const uint8_t **data, int32_t *len);
int dst_hashtable_view(DstValue tab, const DstValue **data, int32_t *len, int32_t *cap); int dst_hashtable_view(DstValue tab, const DstKV **data, int32_t *len, int32_t *cap);
/* Abstract */ /* Abstract */
#define dst_abstract_header(u) ((DstAbstractHeader *)(u) - 1) #define dst_abstract_header(u) ((DstAbstractHeader *)(u) - 1)
@ -160,7 +157,7 @@ int32_t dst_hash(DstValue x);
int dst_compare(DstValue x, DstValue y); int dst_compare(DstValue x, DstValue y);
DstValue dst_get(DstValue ds, DstValue key); DstValue dst_get(DstValue ds, DstValue key);
void dst_put(DstValue ds, DstValue key, DstValue value); void dst_put(DstValue ds, DstValue key, DstValue value);
DstValue dst_next(DstValue ds, DstValue key); const DstKV *dst_next(DstValue ds, const DstKV *kv);
int32_t dst_length(DstValue x); int32_t dst_length(DstValue x);
int32_t dst_capacity(DstValue x); int32_t dst_capacity(DstValue x);
DstValue dst_getindex(DstValue ds, int32_t index); DstValue dst_getindex(DstValue ds, int32_t index);
@ -169,11 +166,19 @@ void dst_setindex(DstValue ds, DstValue value, int32_t index);
/* Utils */ /* Utils */
extern const char dst_base64[65]; extern const char dst_base64[65];
int32_t dst_array_calchash(const DstValue *array, int32_t len); int32_t dst_array_calchash(const DstValue *array, int32_t len);
int32_t dst_kv_calchash(const DstKV *kvs, int32_t len);
int32_t dst_string_calchash(const uint8_t *str, int32_t len); int32_t dst_string_calchash(const uint8_t *str, int32_t len);
int32_t dst_tablen(int32_t n);
DstValue dst_loadreg(DstReg *regs, size_t count); DstValue dst_loadreg(DstReg *regs, size_t count);
DstValue dst_scan_number(const uint8_t *src, int32_t len); DstValue dst_scan_number(const uint8_t *src, int32_t len);
int32_t dst_scan_integer(const uint8_t *str, int32_t len, int *err); int32_t dst_scan_integer(const uint8_t *str, int32_t len, int *err);
double dst_scan_real(const uint8_t *str, int32_t len, int *err); double dst_scan_real(const uint8_t *str, int32_t len, int *err);
int dst_cstrcmp(const uint8_t *str, const char *other);
const void *dst_strbinsearch(
const void *tab,
size_t tabcount,
size_t itemsize,
const uint8_t *key);
/* Parsing */ /* Parsing */
DstParseResult dst_parse(const uint8_t *src, int32_t len); DstParseResult dst_parse(const uint8_t *src, int32_t len);

View File

@ -28,7 +28,8 @@
/* /*
* Detect OS and endianess. * Detect OS and endianess.
* From webkit source. * From webkit source. There is likely some extreneous
* detection for unsupported platforms
*/ */
/* Check Unix */ /* Check Unix */
@ -116,6 +117,14 @@
#define DST_RECURSION_GUARD 1000 #define DST_RECURSION_GUARD 1000
/* Use nanboxed values - uses 8 bytes per value instead of 12 or 16. */ /* Use nanboxed values - uses 8 bytes per value instead of 12 or 16. */
//#define DST_NANBOX #define DST_NANBOX
#define DST_NANBOX_47
/* Alignment for pointers */
#ifdef DST_32
#define DST_WALIGN 4
#else
#define DST_WALIGN 8
#endif
#endif /* DST_CONFIG_H_defined */ #endif /* DST_CONFIG_H_defined */

View File

@ -44,6 +44,7 @@ typedef struct DstReg DstReg;
typedef struct DstAbstractHeader DstAbstractHeader; typedef struct DstAbstractHeader DstAbstractHeader;
typedef struct DstFuncDef DstFuncDef; typedef struct DstFuncDef DstFuncDef;
typedef struct DstFuncEnv DstFuncEnv; typedef struct DstFuncEnv DstFuncEnv;
typedef struct DstKV DstKV;
typedef struct DstStackFrame DstStackFrame; typedef struct DstStackFrame DstStackFrame;
typedef struct DstAbstractType DstAbstractType; typedef struct DstAbstractType DstAbstractType;
typedef int (*DstCFunction)(int32_t argn, DstValue *argv, DstValue *ret); typedef int (*DstCFunction)(int32_t argn, DstValue *argv, DstValue *ret);
@ -109,11 +110,13 @@ union DstValue {
double real; double real;
}; };
#define dst_u64(x) ((x).u64)
/* This representation uses 48 bit pointers. The trade off vs. the LuaJIT style /* This representation uses 48 bit pointers. The trade off vs. the LuaJIT style
* 47 bit payload representaion is that the type bits are no long contiguous. Type * 47 bit payload representaion is that the type bits are no long contiguous. Type
* checking can still be fast, but typewise polymorphism takes a bit longer. However, * checking can still be fast, but typewise polymorphism takes a bit longer. However,
* hopefully we can avoid some annoying problems that occur when trying to use 47 bit pointers * hopefully we can avoid some annoying problems that occur when trying to use 47 bit pointers
* in a 48 bit address space (Linux on ARM) */ * in a 48 bit address space (Linux on ARM). If DST_NANBOX_47 is set, use 47 bit tagged pointers. */
/* |.......Tag.......|.......................Payload..................| */ /* |.......Tag.......|.......................Payload..................| */
/* Non-double: t|11111111111|1ttt|xxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */ /* Non-double: t|11111111111|1ttt|xxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */
@ -121,44 +124,61 @@ union DstValue {
/* Double (no NaNs): x xxxxxxxxxxx xxxx xxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */ /* Double (no NaNs): x xxxxxxxxxxx xxxx xxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */
/* A simple scheme for nan boxed values */ #if defined (DST_NANBOX_47) || defined (DST_32)
/* normal doubles, denormalized doubles, and infinities are doubles */
/* Quiet nan is nil. Sign bit should be 0. */ #define DST_NANBOX_TAGBITS 0xFFFF800000000000lu
#define DST_NANBOX_PAYLOADBITS 0x00007FFFFFFFFFFFlu
#define dst_nanbox_lowtag(type) \
((uint64_t)(type) | 0x1FFF0)
#define dst_nanbox_tag(type) \
(dst_nanbox_lowtag(type) << 47)
#define dst_type(x) \
(isnan((x).real) \
? (((x).u64 >> 47) & 0xF) \
: DST_REAL)
#else /* defined (DST_NANBOX_47) || defined (DST_32) */
#define DST_NANBOX_TYPEBITS 0x0007000000000000lu
#define DST_NANBOX_TAGBITS 0xFFFF000000000000lu #define DST_NANBOX_TAGBITS 0xFFFF000000000000lu
#define DST_NANBOX_PAYLOADBITS 0x0000FFFFFFFFFFFFlu #define DST_NANBOX_PAYLOADBITS 0x0000FFFFFFFFFFFFlu
#ifdef DST_64
#define DST_NANBOX_POINTERBITS 0x0000FFFFFFFFFFFFlu
#else
#define DST_NANBOX_POINTERBITS 0x00000000FFFFFFFFlu
#endif
#define dst_u64(x) ((x).u64)
#define dst_nanbox_lowtag(type) \ #define dst_nanbox_lowtag(type) \
((((uint64_t)(type) & 0x8) << 12) | 0x7FF8 | (type)) ((((uint64_t)(type) & 0x1) << 15) | 0x7FF8 | ((type) >> 1))
#define dst_nanbox_tag(type) \ #define dst_nanbox_tag(type) \
(dst_nanbox_lowtag(type) << 48) (dst_nanbox_lowtag(type) << 48)
#define dst_type(x) \
(isnan((x).real) \
? (((x).u64 >> 47) & 0xE) | ((x).u64 >> 63) \
: DST_REAL)
#endif /* defined (DST_NANBOX_47) || defined (DST_32) */
/* 32 bit mode will not use the full payload for pointers. */
#ifdef DST_32
#define DST_NANBOX_POINTERBITS 0xFFFFFFFFlu
#else
#define DST_NANBOX_POINTERBITS DST_NANBOX_PAYLOADBITS
#endif
#define dst_nanbox_checkauxtype(x, type) \ #define dst_nanbox_checkauxtype(x, type) \
(((x).u64 & DST_NANBOX_TAGBITS) == dst_nanbox_tag((type))) (((x).u64 & DST_NANBOX_TAGBITS) == dst_nanbox_tag((type)))
/* Check if number is nan or if number is real double */
#define dst_nanbox_isreal(x) \ #define dst_nanbox_isreal(x) \
(!isnan((x).real) || dst_nanbox_checkauxtype((x), DST_REAL)) (!isnan((x).real) || dst_nanbox_checkauxtype((x), DST_REAL))
#define dst_type(x) \
(isnan((x).real) \
? (((x).u64 & DST_NANBOX_TYPEBITS) >> 48) | (((x).u64 >> 60) & 0x8) \
: DST_REAL)
#define dst_checktype(x, t) \ #define dst_checktype(x, t) \
(((t) == DST_REAL) \ (((t) == DST_REAL) \
? dst_nanbox_isreal(x) \ ? dst_nanbox_isreal(x) \
: dst_nanbox_checkauxtype((x), (t))) : dst_nanbox_checkauxtype((x), (t)))
void *dst_nanbox_to_pointer(DstValue x); void *dst_nanbox_to_pointer(DstValue x);
void dst_nanbox_memempty(DstValue *mem, int32_t count); void dst_nanbox_memempty(DstKV *mem, int32_t count);
void *dst_nanbox_memalloc_empty(int32_t count); void *dst_nanbox_memalloc_empty(int32_t count);
DstValue dst_nanbox_from_pointer(void *p, uint64_t tagmask); DstValue dst_nanbox_from_pointer(void *p, uint64_t tagmask);
DstValue dst_nanbox_from_cpointer(const void *p, uint64_t tagmask); DstValue dst_nanbox_from_cpointer(const void *p, uint64_t tagmask);
@ -176,10 +196,10 @@ DstValue dst_nanbox_from_bits(uint64_t bits);
dst_nanbox_from_bits(dst_nanbox_tag(t) | (p)) dst_nanbox_from_bits(dst_nanbox_tag(t) | (p))
#define dst_nanbox_wrap_(p, t) \ #define dst_nanbox_wrap_(p, t) \
dst_nanbox_from_pointer((p), dst_nanbox_tag(t) | 0x7FF8000000000000lu) dst_nanbox_from_pointer((p), dst_nanbox_tag(t))
#define dst_nanbox_wrap_c(p, t) \ #define dst_nanbox_wrap_c(p, t) \
dst_nanbox_from_cpointer((p), dst_nanbox_tag(t) | 0x7FF8000000000000lu) dst_nanbox_from_cpointer((p), dst_nanbox_tag(t))
/* Wrap the simple types */ /* Wrap the simple types */
#define dst_wrap_nil() dst_nanbox_from_payload(DST_NIL, 1) #define dst_wrap_nil() dst_nanbox_from_payload(DST_NIL, 1)
@ -191,7 +211,7 @@ DstValue dst_nanbox_from_bits(uint64_t bits);
/* Unwrap the simple types */ /* Unwrap the simple types */
#define dst_unwrap_boolean(x) \ #define dst_unwrap_boolean(x) \
(((x).u64 >> 48) == dst_nanbox_lowtag(DST_TRUE)) (dst_checktype(x, DST_TRUE))
#define dst_unwrap_integer(x) \ #define dst_unwrap_integer(x) \
((int32_t)((x).u64 & 0xFFFFFFFFlu)) ((int32_t)((x).u64 & 0xFFFFFFFFlu))
#define dst_unwrap_real(x) ((x).real) #define dst_unwrap_real(x) ((x).real)
@ -210,7 +230,7 @@ DstValue dst_nanbox_from_bits(uint64_t bits);
#define dst_wrap_cfunction(s) dst_nanbox_wrap_((s), DST_CFUNCTION) #define dst_wrap_cfunction(s) dst_nanbox_wrap_((s), DST_CFUNCTION)
/* Unwrap the pointer types */ /* Unwrap the pointer types */
#define dst_unwrap_struct(x) ((const DstValue *)dst_nanbox_to_pointer(x)) #define dst_unwrap_struct(x) ((const DstKV *)dst_nanbox_to_pointer(x))
#define dst_unwrap_tuple(x) ((const DstValue *)dst_nanbox_to_pointer(x)) #define dst_unwrap_tuple(x) ((const DstValue *)dst_nanbox_to_pointer(x))
#define dst_unwrap_fiber(x) ((DstFiber *)dst_nanbox_to_pointer(x)) #define dst_unwrap_fiber(x) ((DstFiber *)dst_nanbox_to_pointer(x))
#define dst_unwrap_array(x) ((DstArray *)dst_nanbox_to_pointer(x)) #define dst_unwrap_array(x) ((DstArray *)dst_nanbox_to_pointer(x))
@ -239,14 +259,14 @@ struct DstValue {
}; };
#define dst_u64(x) ((x).as.u64) #define dst_u64(x) ((x).as.u64)
#define dst_memempty(mem, count) memset((mem), 0, sizeof(DstValue) * (count)) #define dst_memempty(mem, count) memset((mem), 0, sizeof(DstKV) * (count))
#define dst_memalloc_empty(count) calloc((count), sizeof(DstValue)) #define dst_memalloc_empty(count) calloc((count), sizeof(DstKV))
#define dst_type(x) ((x).type) #define dst_type(x) ((x).type)
#define dst_checktype(x, t) ((x).type == (t)) #define dst_checktype(x, t) ((x).type == (t))
#define dst_truthy(x) \ #define dst_truthy(x) \
((x).type != DST_NIL && (x).type != DST_FALSE) ((x).type != DST_NIL && (x).type != DST_FALSE)
#define dst_unwrap_struct(x) ((const DstValue *)(x).as.pointer) #define dst_unwrap_struct(x) ((const DstKV *)(x).as.pointer)
#define dst_unwrap_tuple(x) ((const DstValue *)(x).as.pointer) #define dst_unwrap_tuple(x) ((const DstValue *)(x).as.pointer)
#define dst_unwrap_fiber(x) ((DstFiber *)(x).as.pointer) #define dst_unwrap_fiber(x) ((DstFiber *)(x).as.pointer)
#define dst_unwrap_array(x) ((DstArray *)(x).as.pointer) #define dst_unwrap_array(x) ((DstArray *)(x).as.pointer)
@ -272,7 +292,7 @@ DstValue dst_wrap_string(const uint8_t *x);
DstValue dst_wrap_symbol(const uint8_t *x); DstValue dst_wrap_symbol(const uint8_t *x);
DstValue dst_wrap_array(DstArray *x); DstValue dst_wrap_array(DstArray *x);
DstValue dst_wrap_tuple(const DstValue *x); DstValue dst_wrap_tuple(const DstValue *x);
DstValue dst_wrap_struct(const DstValue *x); DstValue dst_wrap_struct(const DstKV *x);
DstValue dst_wrap_fiber(DstFiber *x); DstValue dst_wrap_fiber(DstFiber *x);
DstValue dst_wrap_buffer(DstBuffer *x); DstValue dst_wrap_buffer(DstBuffer *x);
DstValue dst_wrap_function(DstFunction *x); DstValue dst_wrap_function(DstFunction *x);
@ -332,12 +352,18 @@ struct DstBuffer {
/* A mutable associative data type. Backed by a hashtable. */ /* A mutable associative data type. Backed by a hashtable. */
struct DstTable { struct DstTable {
DstValue *data; DstKV *data;
int32_t count; int32_t count;
int32_t capacity; int32_t capacity;
int32_t deleted; int32_t deleted;
}; };
/* A key value pair in a struct or table */
struct DstKV {
DstValue key;
DstValue value;
};
/* Some function defintion flags */ /* Some function defintion flags */
#define DST_FUNCDEF_FLAG_VARARG 1 #define DST_FUNCDEF_FLAG_VARARG 1
#define DST_FUNCDEF_FLAG_NEEDSENV 4 #define DST_FUNCDEF_FLAG_NEEDSENV 4

1
packages/test.c Normal file
View File

@ -0,0 +1 @@
#include <dst/dst.h>