mirror of
https://github.com/janet-lang/janet
synced 2024-12-23 15:00:27 +00:00
Much work on compiler. Fixing bugs and gradually cleaning
up code. Generalized some vector code.
This commit is contained in:
parent
e4735e14d2
commit
2771171658
31
Makefile
31
Makefile
@ -31,7 +31,7 @@ PREFIX=/usr/local
|
||||
DST_TARGET=dst
|
||||
DST_XXD=xxd
|
||||
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)
|
||||
|
||||
#############################
|
||||
@ -48,9 +48,9 @@ all: $(DST_TARGET)
|
||||
|
||||
DST_CORE_SOURCES=$(addprefix core/,\
|
||||
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\
|
||||
value.c vm.c wrap.c)
|
||||
value.c vector.c vm.c wrap.c)
|
||||
|
||||
DST_CLIENT_SOURCES=$(addprefix client/,\
|
||||
main.c)
|
||||
@ -58,29 +58,6 @@ DST_CLIENT_SOURCES=$(addprefix client/,\
|
||||
$(DST_TARGET): $(DST_CORE_SOURCES) $(DST_CLIENT_SOURCES) $(DST_ALL_HEADERS)
|
||||
$(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 #####
|
||||
###################
|
||||
@ -95,7 +72,7 @@ valgrind: $(DST_TARGET)
|
||||
@ valgrind --leak-check=full -v ./$(DST_TARGET)
|
||||
|
||||
test: $(DST_TARGET)
|
||||
@ ./$(DST_TARGET) dsttests/basic.dst
|
||||
@ ./$(DST_TARGET) dsttest/suite0.dst
|
||||
|
||||
valtest: $(DST_TARGET)
|
||||
valgrind --leak-check=full -v ./$(DST_TARGET) dsttests/basic.dst
|
||||
|
@ -66,8 +66,11 @@ void dst_array_setcount(DstArray *array, int32_t count) {
|
||||
if (count < 0)
|
||||
return;
|
||||
if (count > array->count) {
|
||||
int32_t i;
|
||||
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;
|
||||
}
|
||||
|
159
core/asm.c
159
core/asm.c
@ -90,11 +90,12 @@ struct DstAssembler {
|
||||
DstFuncDef *def;
|
||||
jmp_buf on_error;
|
||||
const uint8_t *errmessage;
|
||||
const uint8_t *name;
|
||||
|
||||
int32_t environments_capacity;
|
||||
int32_t defs_capacity;
|
||||
int32_t bytecode_count; /* Used for calculating labels */
|
||||
|
||||
DstValue name;
|
||||
DstTable labels; /* symbol -> bytecode index */
|
||||
DstTable constants; /* symbol -> constant index */
|
||||
DstTable slots; /* symbol -> slot index */
|
||||
@ -166,39 +167,6 @@ static const DstInstructionDef dst_ops[] = {
|
||||
{"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
|
||||
* index of the matching test_string, or -1 if not found. */
|
||||
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.
|
||||
* Returns the index of the environment in the assembler's environments, or -1
|
||||
* if not found. */
|
||||
/*static int32_t dst_asm_addenv(DstAssembler *a, DstValue envname) {*/
|
||||
/*DstValue check;*/
|
||||
/*DstFuncDef *def = a->def;*/
|
||||
/*int32_t oldlen;*/
|
||||
/*int64_t res;*/
|
||||
/*[> Check for memoized value <]*/
|
||||
/*check = dst_table_get(&a->envs, envname);*/
|
||||
/*if (!dst_checktype(check, DST_NIL)) return dst_unwrap_integer(check);*/
|
||||
/*if (NULL == a->parent) return -1;*/
|
||||
/*res = dst_asm_addenv(a->parent, envname);*/
|
||||
/*if (res < 0)*/
|
||||
/*return res;*/
|
||||
/*oldlen = def->environments_length;*/
|
||||
/*dst_table_put(&a->envs, envname, dst_wrap_integer(def->environments_length));*/
|
||||
/*if (oldlen >= a->environments_capacity) {*/
|
||||
/*int32_t newcap = 2 + 2 * oldlen;*/
|
||||
/*def->environments = realloc(def->environments, newcap * sizeof(int32_t));*/
|
||||
/*if (NULL == def->environments) {*/
|
||||
/*DST_OUT_OF_MEMORY;*/
|
||||
/*}*/
|
||||
/*a->environments_capacity = newcap;*/
|
||||
/*}*/
|
||||
/*def->environments[def->environments_length++] = (int32_t) res;*/
|
||||
/*return (int32_t) oldlen;*/
|
||||
/*}*/
|
||||
static int32_t dst_asm_addenv(DstAssembler *a, DstValue envname) {
|
||||
DstValue check;
|
||||
DstFuncDef *def = a->def;
|
||||
int32_t envindex;
|
||||
int32_t res;
|
||||
if (dst_equals(a->name, envname)) {
|
||||
return 0;
|
||||
}
|
||||
/* Check for memoized value */
|
||||
check = dst_table_get(&a->envs, envname);
|
||||
if (dst_checktype(check, DST_INTEGER)) return dst_unwrap_integer(check);
|
||||
if (NULL == a->parent) return -1;
|
||||
res = dst_asm_addenv(a->parent, envname);
|
||||
if (res < 0)
|
||||
return res;
|
||||
envindex = def->environments_length;
|
||||
if (envindex == 0) envindex = 1;
|
||||
dst_table_put(&a->envs, envname, dst_wrap_integer(envindex));
|
||||
if (envindex >= a->environments_capacity) {
|
||||
int32_t newcap = 2 * envindex;
|
||||
def->environments = realloc(def->environments, newcap * sizeof(int32_t));
|
||||
if (NULL == def->environments) {
|
||||
DST_OUT_OF_MEMORY;
|
||||
}
|
||||
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
|
||||
* integer. This integer will need to be bounds checked. */
|
||||
@ -348,6 +321,13 @@ static int32_t doarg_1(
|
||||
} else {
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -530,14 +510,15 @@ static DstAssembleResult dst_asm1(DstAssembler *parent, DstAssembleOptions opts)
|
||||
a.def = def;
|
||||
a.parent = parent;
|
||||
a.errmessage = NULL;
|
||||
a.name = NULL;
|
||||
a.environments_capacity = 0;
|
||||
a.bytecode_count = 0;
|
||||
dst_table_init(&a.labels, 10);
|
||||
dst_table_init(&a.constants, 10);
|
||||
dst_table_init(&a.slots, 10);
|
||||
dst_table_init(&a.envs, 10);
|
||||
dst_table_init(&a.defs, 10);
|
||||
a.defs_capacity = 0;
|
||||
a.name = dst_wrap_nil();
|
||||
dst_table_init(&a.labels, 0);
|
||||
dst_table_init(&a.constants, 0);
|
||||
dst_table_init(&a.slots, 0);
|
||||
dst_table_init(&a.envs, 0);
|
||||
dst_table_init(&a.defs, 0);
|
||||
|
||||
/* Set error jump */
|
||||
if (setjmp(a.on_error)) {
|
||||
@ -557,8 +538,7 @@ static DstAssembleResult dst_asm1(DstAssembler *parent, DstAssembleOptions opts)
|
||||
"expected struct or table for assembly source");
|
||||
|
||||
/* Check for function name */
|
||||
x = dst_get(s, dst_csymbolv("name"));
|
||||
if (dst_checktype(x, DST_SYMBOL)) a.name = dst_unwrap_symbol(x);
|
||||
a.name = dst_get(s, dst_csymbolv("name"));
|
||||
|
||||
/* Set function 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);
|
||||
int32_t tcount = dst_tuple_length(t);
|
||||
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];
|
||||
} else if (tcount == 3 &&
|
||||
dst_checktype(t[1], DST_SYMBOL) &&
|
||||
0 == dst_strcompare(macro, "def")) {
|
||||
0 == dst_cstrcmp(macro, "def")) {
|
||||
def->constants[i] = t[2];
|
||||
dst_table_put(&a.constants, t[1], dst_wrap_integer(i));
|
||||
} else {
|
||||
@ -633,10 +613,37 @@ static DstAssembleResult dst_asm1(DstAssembler *parent, DstAssembleOptions opts)
|
||||
}
|
||||
|
||||
/* Parse sub funcdefs */
|
||||
/*x = dst_get(s, dst_csymbolv("closures"));*/
|
||||
/*if (dst_seq_view(x, &arr, &count)) {*/
|
||||
|
||||
/*}*/
|
||||
x = dst_get(s, dst_csymbolv("closures"));
|
||||
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 */
|
||||
x = dst_get(s, dst_csymbolv("bytecode"));
|
||||
@ -675,7 +682,11 @@ static DstAssembleResult dst_asm1(DstAssembler *parent, DstAssembleOptions opts)
|
||||
} else {
|
||||
dst_asm_assert(&a, dst_checktype(t[0], DST_SYMBOL),
|
||||
"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)
|
||||
dst_asm_errorv(&a, dst_formatc("unknown instruction %v", instr));
|
||||
op = read_instruction(&a, idef, t);
|
||||
|
1352
core/compile.c
1352
core/compile.c
File diff suppressed because it is too large
Load Diff
@ -53,8 +53,6 @@ struct DstSlot {
|
||||
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)
|
||||
@ -72,55 +70,42 @@ struct DstSlot {
|
||||
#define DST_SCOPE_TOP 4
|
||||
#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 */
|
||||
struct DstScope {
|
||||
|
||||
/* Constants for this funcdef */
|
||||
int32_t ccount;
|
||||
int32_t ccap;
|
||||
DstValue *consts;
|
||||
|
||||
/* Map of symbols to slots. Use a simple linear scan for symbols. */
|
||||
int32_t symcap;
|
||||
int32_t symcount;
|
||||
struct {
|
||||
const uint8_t *sym;
|
||||
DstSlot slot;
|
||||
} *syms;
|
||||
SymPair *syms;
|
||||
|
||||
/* Bit vector with allocated slot indices. Used to allocate new slots */
|
||||
uint32_t *slots;
|
||||
int32_t scap;
|
||||
int32_t smax;
|
||||
|
||||
/* FuncDefs */
|
||||
int32_t dcount;
|
||||
int32_t dcap;
|
||||
DstFuncDef **defs;
|
||||
|
||||
/* 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. */
|
||||
int32_t *envs;
|
||||
int32_t envcount;
|
||||
int32_t envcap;
|
||||
|
||||
int32_t bytecode_start;
|
||||
int flags;
|
||||
};
|
||||
|
||||
#define dst_compile_topscope(c) ((c)->scopes + (c)->scopecount - 1)
|
||||
|
||||
/* Compilation state */
|
||||
struct DstCompiler {
|
||||
jmp_buf on_error;
|
||||
int recursion_guard;
|
||||
int32_t scopecount;
|
||||
int32_t scopecap;
|
||||
DstScope *scopes;
|
||||
|
||||
int32_t buffercap;
|
||||
int32_t buffercount;
|
||||
uint32_t *buffer;
|
||||
int32_t *mapbuffer;
|
||||
|
||||
@ -156,32 +141,32 @@ typedef struct DstSpecial {
|
||||
} DstSpecial;
|
||||
|
||||
/* An array of optimizers sorted by key */
|
||||
extern DstCFunctionOptimizer dst_compiler_optimizers[255];
|
||||
extern DstCFunctionOptimizer dstcr_optimizers[255];
|
||||
|
||||
/* 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 dst_compile_cerror(DstCompiler *c, const DstValue *sourcemap, const char *m);
|
||||
void dstc_error(DstCompiler *c, const DstValue *sourcemap, const uint8_t *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
|
||||
* 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);
|
||||
DstFormOptions dstc_getindex(DstFormOptions opts, int32_t index);
|
||||
DstFormOptions dstc_getkey(DstFormOptions opts, DstValue key);
|
||||
DstFormOptions dstc_getvalue(DstFormOptions opts, DstValue key);
|
||||
|
||||
void dst_compile_scope(DstCompiler *c, int newfn);
|
||||
void dst_compile_popscope(DstCompiler *c);
|
||||
void dstc_scope(DstCompiler *c, int newfn);
|
||||
void dstc_popscope(DstCompiler *c);
|
||||
|
||||
DstSlot dst_compile_constantslot(DstValue x);
|
||||
void dst_compile_freeslot(DstCompiler *c, DstSlot slot);
|
||||
DstSlot dstc_cslot(DstValue x);
|
||||
void dstc_freeslot(DstCompiler *c, DstSlot slot);
|
||||
|
||||
/* 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. */
|
||||
void dst_compile_emit(DstCompiler *c, const DstValue *sourcemap, uint32_t instr);
|
||||
void dstc_emit(DstCompiler *c, const DstValue *sourcemap, uint32_t instr);
|
||||
|
||||
#endif
|
||||
|
28
core/fiber.c
28
core/fiber.c
@ -101,17 +101,6 @@ void dst_fiber_pushn(DstFiber *fiber, const DstValue *arr, int32_t n) {
|
||||
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 */
|
||||
static void funcframe_helper(DstFiber *fiber, DstFunction *func) {
|
||||
/* 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 */
|
||||
void dst_fiber_funcframe_tail(DstFiber *fiber, DstFunction *func) {
|
||||
int32_t i;
|
||||
|
40
core/func.c
40
core/func.c
@ -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;
|
||||
}
|
||||
}
|
42
core/gc.c
42
core/gc.c
@ -40,7 +40,7 @@ static void dst_mark_funcdef(DstFuncDef *def);
|
||||
static void dst_mark_function(DstFunction *func);
|
||||
static void dst_mark_array(DstArray *array);
|
||||
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_buffer(DstBuffer *buffer);
|
||||
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) {
|
||||
if (dst_gc_reachable(array))
|
||||
return;
|
||||
@ -96,14 +106,14 @@ static void dst_mark_table(DstTable *table) {
|
||||
if (dst_gc_reachable(table))
|
||||
return;
|
||||
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)))
|
||||
return;
|
||||
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) {
|
||||
@ -197,7 +207,7 @@ static void dst_deinit_block(DstGCMemoryHeader *block) {
|
||||
dst_table_deinit((DstTable*) mem);
|
||||
break;
|
||||
case DST_MEMORY_FIBER:
|
||||
free(((DstFiber *) mem)->data);
|
||||
free(((DstFiber *)mem)->data);
|
||||
break;
|
||||
case DST_MEMORY_BUFFER:
|
||||
dst_buffer_deinit((DstBuffer *) mem);
|
||||
@ -220,6 +230,7 @@ static void dst_deinit_block(DstGCMemoryHeader *block) {
|
||||
{
|
||||
DstFuncDef *def = (DstFuncDef *)mem;
|
||||
/* TODO - get this all with one alloc and one free */
|
||||
free(def->defs);
|
||||
free(def->environments);
|
||||
free(def->constants);
|
||||
free(def->bytecode);
|
||||
@ -241,7 +252,6 @@ void dst_sweep() {
|
||||
previous = current;
|
||||
current->flags &= ~DST_MEM_REACHABLE;
|
||||
} else {
|
||||
/*printf("freeing block %p\n", current);*/
|
||||
dst_deinit_block(current);
|
||||
if (NULL != previous) {
|
||||
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 */
|
||||
void *dst_gcalloc(DstMemoryType type, size_t size) {
|
||||
DstGCMemoryHeader *mdata;
|
||||
@ -294,8 +288,6 @@ void *dst_gcalloc(DstMemoryType type, size_t size) {
|
||||
mdata->next = dst_vm_blocks;
|
||||
dst_vm_blocks = mdata;
|
||||
|
||||
/*printf("created block %p of size %lu, type %s\n", mem, size, memtypes[type]);*/
|
||||
|
||||
return mem + sizeof(DstGCMemoryHeader);
|
||||
}
|
||||
|
||||
@ -361,7 +353,7 @@ int dst_gcunrootall(DstValue root) {
|
||||
/* Free all allocated memory */
|
||||
void dst_clear_memory() {
|
||||
DstGCMemoryHeader *current = dst_vm_blocks;
|
||||
while (current) {
|
||||
while (NULL != current) {
|
||||
dst_deinit_block(current);
|
||||
DstGCMemoryHeader *next = current->next;
|
||||
free(current);
|
||||
|
14
core/parse.c
14
core/parse.c
@ -237,11 +237,13 @@ static const uint8_t *parse_recur(
|
||||
default:
|
||||
atom:
|
||||
{
|
||||
int ascii = 1;
|
||||
DstValue numcheck;
|
||||
const uint8_t *tokenend = src;
|
||||
if (!is_symbol_char(*src)) goto unexpected_character;
|
||||
while (tokenend < end && is_symbol_char(*tokenend))
|
||||
tokenend++;
|
||||
while (tokenend < end && is_symbol_char(*tokenend)) {
|
||||
if (*tokenend++ > 127) ascii = 0;
|
||||
}
|
||||
numcheck = dst_scan_number(src, tokenend - src);
|
||||
if (!dst_checktype(numcheck, DST_NIL)) {
|
||||
ret = numcheck;
|
||||
@ -255,7 +257,9 @@ static const uint8_t *parse_recur(
|
||||
if (*src >= '0' && *src <= '9') {
|
||||
goto sym_nodigits;
|
||||
} 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;
|
||||
if (*src == ':') {
|
||||
ret = dst_stringv(src + 1, tokenend - src - 1);
|
||||
@ -415,8 +419,8 @@ static const uint8_t *parse_recur(
|
||||
ret = dst_wrap_table(t);
|
||||
submapping = dst_wrap_table(subt);
|
||||
} else {
|
||||
DstValue *st = dst_struct_begin(n >> 1);
|
||||
DstValue *subst = dst_struct_begin(n >> 1);
|
||||
DstKV *st = dst_struct_begin(n >> 1);
|
||||
DstKV *subst = dst_struct_begin(n >> 1);
|
||||
for (i = n; i > 0; i -= 2) {
|
||||
DstValue val = dst_array_pop(&args->stack);
|
||||
DstValue key = dst_array_pop(&args->stack);
|
||||
|
50
core/stl.c
50
core/stl.c
@ -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) {
|
||||
int32_t i;
|
||||
DstTable *table = dst_table(argn/2);
|
||||
DstTable *table = dst_table(argn >> 1);
|
||||
if (argn & 1) {
|
||||
*ret = dst_cstringv("expected even number of arguments");
|
||||
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) {
|
||||
int32_t i;
|
||||
DstValue *st = dst_struct_begin(argn >> 1);
|
||||
DstKV *st = dst_struct_begin(argn >> 1);
|
||||
if (argn & 1) {
|
||||
*ret = dst_cstringv("expected even number of arguments");
|
||||
return 1;
|
||||
@ -126,6 +126,49 @@ int dst_stl_struct(int32_t argn, DstValue *argv, DstValue *ret) {
|
||||
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) {
|
||||
int32_t i;
|
||||
DstValue ds;
|
||||
@ -213,6 +256,9 @@ static DstReg stl[] = {
|
||||
{"array", dst_stl_array},
|
||||
{"tuple", dst_stl_tuple},
|
||||
{"struct", dst_stl_struct},
|
||||
{"fiber", dst_stl_fiber},
|
||||
{"buffer", dst_stl_buffer},
|
||||
{"gensym", dst_stl_gensym},
|
||||
{"asm", dst_stl_asm},
|
||||
{"disasm", dst_stl_disasm},
|
||||
{"get", dst_stl_get},
|
||||
|
@ -410,13 +410,15 @@ static const char *dst_type_colors[16] = {
|
||||
static void dst_description_helper(DstPrinter *p, DstValue x);
|
||||
|
||||
/* 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;
|
||||
int doindent = 0;
|
||||
if (p->flags & DST_PRINTFLAG_INDENT) {
|
||||
if (len <= p->token_line_limit) {
|
||||
for (i = 0; i < cap; i += 2) {
|
||||
if (is_print_ds(data[i]) || is_print_ds(data[i + 1])) {
|
||||
for (i = 0; i < cap; i++) {
|
||||
const DstKV *kv = data + i;
|
||||
if (is_print_ds(kv->key) ||
|
||||
is_print_ds(kv->value)) {
|
||||
doindent = 1;
|
||||
break;
|
||||
}
|
||||
@ -428,12 +430,13 @@ static void dst_print_hashtable_inner(DstPrinter *p, const DstValue *data, int32
|
||||
if (doindent) {
|
||||
dst_buffer_push_u8(p->buffer, '\n');
|
||||
p->indent++;
|
||||
for (i = 0; i < cap; i += 2) {
|
||||
if (!dst_checktype(data[i], DST_NIL)) {
|
||||
for (i = 0; i < cap; i++) {
|
||||
const DstKV *kv = data + i;
|
||||
if (!dst_checktype(kv->key, DST_NIL)) {
|
||||
dst_print_indent(p);
|
||||
dst_description_helper(p, data[i]);
|
||||
dst_description_helper(p, kv->key);
|
||||
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');
|
||||
}
|
||||
}
|
||||
@ -441,15 +444,16 @@ static void dst_print_hashtable_inner(DstPrinter *p, const DstValue *data, int32
|
||||
dst_print_indent(p);
|
||||
} else {
|
||||
int isfirst = 1;
|
||||
for (i = 0; i < cap; i += 2) {
|
||||
if (!dst_checktype(data[i], DST_NIL)) {
|
||||
for (i = 0; i < cap; i++) {
|
||||
const DstKV *kv = data + i;
|
||||
if (!dst_checktype(kv->key, DST_NIL)) {
|
||||
if (isfirst)
|
||||
isfirst = 0;
|
||||
else
|
||||
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_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;
|
||||
int32_t len, cap;
|
||||
const DstValue *data;
|
||||
const DstKV *kvs;
|
||||
DstValue check;
|
||||
p->depth--;
|
||||
switch (dst_type(x)) {
|
||||
@ -537,8 +542,8 @@ static void dst_description_helper(DstPrinter *p, DstValue x) {
|
||||
dst_buffer_push_cstring(p->buffer, open);
|
||||
if (p->depth == 0) {
|
||||
dst_buffer_push_cstring(p->buffer, "...");
|
||||
} else if (dst_hashtable_view(x, &data, &len, &cap)) {
|
||||
dst_print_hashtable_inner(p, data, len, cap);
|
||||
} else if (dst_hashtable_view(x, &kvs, &len, &cap)) {
|
||||
dst_print_hashtable_inner(p, kvs, len, cap);
|
||||
} else if (dst_seq_view(x, &data, &len)) {
|
||||
dst_print_seq_inner(p, data, len);
|
||||
}
|
||||
|
148
core/struct.c
148
core/struct.c
@ -23,40 +23,35 @@
|
||||
#include <dst/dst.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 */
|
||||
DstValue *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
|
||||
* key value pairs. The minimum it could be is
|
||||
* sizeof(int32_t) * 2 + 2 * count * sizeof(DstValue). Adding more space
|
||||
* 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 */
|
||||
int32_t capacity = 4 * count;
|
||||
size_t s = sizeof(int32_t) * 2 + (capacity * sizeof(DstValue));
|
||||
DstKV *dst_struct_begin(int32_t count) {
|
||||
|
||||
/* Calculate capacity as power of 2 after 2 * count. */
|
||||
int32_t capacity = dst_tablen(2 * count);
|
||||
if (capacity < 0) capacity = dst_tablen(count);
|
||||
|
||||
size_t s = sizeof(int32_t) * 4 + (capacity * sizeof(DstKV));
|
||||
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_struct_length(st) = count;
|
||||
/* Use the hash storage space as a counter to see how many items
|
||||
* 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_capacity(st) = capacity;
|
||||
dst_struct_hash(st) = 0;
|
||||
return st;
|
||||
}
|
||||
|
||||
/* 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 index = dst_struct_maphash(cap, dst_hash(key));
|
||||
int32_t i;
|
||||
for (i = index; i < cap; i += 2)
|
||||
if (dst_checktype(st[i], DST_NIL) || dst_equals(st[i], key))
|
||||
for (i = index; i < cap; i++)
|
||||
if (dst_checktype(st[i].key, DST_NIL) || dst_equals(st[i].key, key))
|
||||
return st + i;
|
||||
for (i = 0; i < index; i += 2)
|
||||
if (dst_checktype(st[i], DST_NIL) || dst_equals(st[i], key))
|
||||
for (i = 0; i < index; i++)
|
||||
if (dst_checktype(st[i].key, DST_NIL) || dst_equals(st[i].key, key))
|
||||
return st + i;
|
||||
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.
|
||||
* Nil keys and values are ignored, extra keys are ignore, and duplicate keys are
|
||||
* 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 hash = dst_hash(key);
|
||||
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 */
|
||||
if (dst_struct_hash(st) == dst_struct_length(st)) return;
|
||||
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;
|
||||
int32_t otherhash;
|
||||
int32_t otherindex, otherdist;
|
||||
DstKV *kv = st + i;
|
||||
/* We found an empty slot, so just add key and value */
|
||||
if (dst_checktype(st[i], DST_NIL)) {
|
||||
st[i] = key;
|
||||
st[i + 1] = value;
|
||||
if (dst_checktype(kv->key, DST_NIL)) {
|
||||
kv->key = key;
|
||||
kv->value = value;
|
||||
/* Update the temporary count */
|
||||
dst_struct_hash(st)++;
|
||||
return;
|
||||
@ -91,9 +87,9 @@ void dst_struct_put(DstValue *st, DstValue key, DstValue value) {
|
||||
* hashing to ensure that equivalent structs that are contsructed
|
||||
* 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}. */
|
||||
otherhash = dst_hash(st[i]);
|
||||
otherhash = dst_hash(kv->key);
|
||||
otherindex = dst_struct_maphash(cap, otherhash);
|
||||
otherdist = (i + cap - otherindex) % cap;
|
||||
otherdist = (i + cap - otherindex) & (cap - 1);
|
||||
if (dist < otherdist)
|
||||
status = -1;
|
||||
else if (otherdist < dist)
|
||||
@ -103,95 +99,89 @@ void dst_struct_put(DstValue *st, DstValue key, DstValue value) {
|
||||
else if (otherhash < hash)
|
||||
status = 1;
|
||||
else
|
||||
status = dst_compare(key, st[i]);
|
||||
status = dst_compare(key, kv->key);
|
||||
/* If other is closer to their ideal slot */
|
||||
if (status == 1) {
|
||||
/* Swap current kv pair with pair in slot */
|
||||
DstValue t1, t2;
|
||||
t1 = st[i];
|
||||
t2 = st[i + 1];
|
||||
st[i] = key;
|
||||
st[i + 1] = value;
|
||||
key = t1;
|
||||
value = t2;
|
||||
DstKV temp = *kv;
|
||||
kv->key = key;
|
||||
kv->value = value;
|
||||
key = temp.key;
|
||||
value = temp.value;
|
||||
/* Save dist and hash of new kv pair */
|
||||
dist = otherdist;
|
||||
hash = otherhash;
|
||||
} else if (status == 0) {
|
||||
/* This should not happen - it means
|
||||
* than a key was added to the struct more than once */
|
||||
dst_exit("struct double put fail");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 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)) {
|
||||
/* Error building struct, probably duplicate values. We need to rebuild
|
||||
* the struct using only the values that went in. The second creation should always
|
||||
* succeed. */
|
||||
int32_t i, realCount;
|
||||
DstValue *newst;
|
||||
DstKV *newst;
|
||||
realCount = 0;
|
||||
for (i = 0; i < dst_struct_capacity(st); i += 2) {
|
||||
realCount += dst_checktype(st[i], DST_NIL) ? 1 : 0;
|
||||
for (i = 0; i < dst_struct_capacity(st); i++) {
|
||||
DstKV *kv = st + i;
|
||||
realCount += dst_checktype(kv->key, DST_NIL) ? 1 : 0;
|
||||
}
|
||||
newst = dst_struct_begin(realCount);
|
||||
for (i = 0; i < dst_struct_capacity(st); i += 2) {
|
||||
if (!dst_checktype(st[i], DST_NIL)) {
|
||||
dst_struct_put(newst, st[i], st[i + 1]);
|
||||
for (i = 0; i < dst_struct_capacity(st); i++) {
|
||||
DstKV *kv = st + i;
|
||||
if (!dst_checktype(kv->key, DST_NIL)) {
|
||||
dst_struct_put(newst, kv->key, kv->value);
|
||||
}
|
||||
}
|
||||
st = newst;
|
||||
}
|
||||
dst_struct_hash(st) = dst_array_calchash(st, dst_struct_capacity(st));
|
||||
return (const DstValue *)st;
|
||||
dst_struct_hash(st) = dst_kv_calchash(st, dst_struct_capacity(st));
|
||||
return (const DstKV *)st;
|
||||
}
|
||||
|
||||
/* Get an item from a struct */
|
||||
DstValue dst_struct_get(const DstValue *st, DstValue key) {
|
||||
const DstValue *bucket = dst_struct_find(st, key);
|
||||
if (NULL == bucket || dst_checktype(*bucket, DST_NIL)) {
|
||||
DstValue dst_struct_get(const DstKV *st, DstValue key) {
|
||||
const DstKV *kv = dst_struct_find(st, key);
|
||||
if (NULL == kv || dst_checktype(kv->key, DST_NIL)) {
|
||||
return dst_wrap_nil();
|
||||
} else {
|
||||
return bucket[1];
|
||||
return kv->value;
|
||||
}
|
||||
}
|
||||
|
||||
/* Get the next key in a struct */
|
||||
DstValue dst_struct_next(const DstValue *st, DstValue key) {
|
||||
const DstValue *bucket, *end;
|
||||
end = st + dst_struct_capacity(st);
|
||||
if (dst_checktype(key, DST_NIL)) {
|
||||
bucket = st;
|
||||
} else {
|
||||
bucket = dst_struct_find(st, key);
|
||||
if (NULL == bucket || dst_checktype(*bucket, DST_NIL))
|
||||
return dst_wrap_nil();
|
||||
bucket += 2;
|
||||
const DstKV *dst_struct_next(const DstKV *st, const DstKV *kv) {
|
||||
const DstKV *end = st + dst_struct_capacity(st);
|
||||
kv = (kv == NULL) ? st : kv + 1;
|
||||
while (kv < end) {
|
||||
if (!dst_checktype(kv->key, DST_NIL)) return kv;
|
||||
kv++;
|
||||
}
|
||||
for (; bucket < end; bucket += 2) {
|
||||
if (!dst_checktype(bucket[0], DST_NIL))
|
||||
return bucket[0];
|
||||
}
|
||||
return dst_wrap_nil();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* 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));
|
||||
int32_t i;
|
||||
for (i = 0; i < dst_struct_capacity(st); i += 2) {
|
||||
if (!dst_checktype(st[i], DST_NIL)) {
|
||||
dst_table_put(table, st[i], st[i + 1]);
|
||||
for (i = 0; i < dst_struct_capacity(st); i++) {
|
||||
const DstKV *kv = st + i;
|
||||
if (!dst_checktype(kv->key, DST_NIL)) {
|
||||
dst_table_put(table, kv->key, kv->value);
|
||||
}
|
||||
}
|
||||
return table;
|
||||
}
|
||||
|
||||
/* 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 llen = dst_struct_capacity(lhs);
|
||||
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);
|
||||
if (llen != rlen)
|
||||
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)
|
||||
return 0;
|
||||
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 1;
|
||||
}
|
||||
|
||||
/* 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 lhash = dst_struct_hash(lhs);
|
||||
int32_t rhash = dst_struct_hash(rhs);
|
||||
@ -223,16 +213,16 @@ int dst_struct_compare(const DstValue *lhs, const DstValue *rhs) {
|
||||
return -1;
|
||||
if (llen > rlen)
|
||||
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)
|
||||
return -1;
|
||||
if (lhash > rhash)
|
||||
return 1;
|
||||
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;
|
||||
}
|
||||
return 0;
|
||||
|
152
core/table.c
152
core/table.c
@ -23,18 +23,23 @@
|
||||
#include <dst/dst.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 */
|
||||
DstTable *dst_table_init(DstTable *table, int32_t capacity) {
|
||||
DstValue *data;
|
||||
if (capacity < 2) capacity = 2;
|
||||
data = (DstValue *) dst_memalloc_empty(capacity);
|
||||
DstKV *data;
|
||||
capacity = dst_tablen(capacity);
|
||||
if (capacity) {
|
||||
data = (DstKV *) dst_memalloc_empty(capacity);
|
||||
if (NULL == data) {
|
||||
DST_OUT_OF_MEMORY;
|
||||
}
|
||||
table->data = data;
|
||||
table->capacity = capacity;
|
||||
} else {
|
||||
table->data = NULL;
|
||||
table->capacity = 0;
|
||||
}
|
||||
table->count = 0;
|
||||
table->deleted = 0;
|
||||
return table;
|
||||
@ -53,35 +58,43 @@ DstTable *dst_table(int32_t capacity) {
|
||||
|
||||
/* Find the bucket that contains the given key. Will also return
|
||||
* 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 i, j;
|
||||
int32_t start[2], end[2];
|
||||
DstValue *first_bucket = NULL;
|
||||
start[0] = index; end[0] = t->capacity;
|
||||
start[1] = 0; end[1] = index;
|
||||
for (j = 0; j < 2; ++j) {
|
||||
for (i = start[j]; i < end[j]; i += 2) {
|
||||
if (dst_checktype(t->data[i], DST_NIL)) {
|
||||
if (dst_checktype(t->data[i + 1], DST_NIL)) {
|
||||
/* Empty */
|
||||
return t->data + i;
|
||||
int32_t i;
|
||||
DstKV *first_bucket = NULL;
|
||||
/* Higher half */
|
||||
for (i = index; i < t->capacity; 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) {
|
||||
/* Marked deleted and not seen free bucket yet. */
|
||||
first_bucket = t->data + i;
|
||||
first_bucket = kv;
|
||||
}
|
||||
} else if (dst_equals(t->data[i], key)) {
|
||||
} else if (dst_equals(kv->key, key)) {
|
||||
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;
|
||||
}
|
||||
|
||||
/* Resize the dictionary table. */
|
||||
static void dst_table_rehash(DstTable *t, int32_t size) {
|
||||
DstValue *olddata = t->data;
|
||||
DstValue *newdata = (DstValue *) dst_memalloc_empty(size);
|
||||
DstKV *olddata = t->data;
|
||||
DstKV *newdata = (DstKV *) dst_memalloc_empty(size);
|
||||
if (NULL == newdata) {
|
||||
DST_OUT_OF_MEMORY;
|
||||
}
|
||||
@ -90,11 +103,11 @@ static void dst_table_rehash(DstTable *t, int32_t size) {
|
||||
t->data = newdata;
|
||||
t->capacity = size;
|
||||
t->deleted = 0;
|
||||
for (i = 0; i < oldcapacity; i += 2) {
|
||||
if (!dst_checktype(olddata[i], DST_NIL)) {
|
||||
DstValue *bucket = dst_table_find(t, olddata[i]);
|
||||
bucket[0] = olddata[i];
|
||||
bucket[1] = olddata[i + 1];
|
||||
for (i = 0; i < oldcapacity; i++) {
|
||||
DstKV *kv = olddata + i;
|
||||
if (!dst_checktype(kv->key, DST_NIL)) {
|
||||
DstKV *newkv = dst_table_find(t, kv->key);
|
||||
*newkv = *kv;
|
||||
}
|
||||
}
|
||||
free(olddata);
|
||||
@ -102,9 +115,9 @@ static void dst_table_rehash(DstTable *t, int32_t size) {
|
||||
|
||||
/* Get a value out of the object */
|
||||
DstValue dst_table_get(DstTable *t, DstValue key) {
|
||||
DstValue *bucket = dst_table_find(t, key);
|
||||
if (NULL != bucket && !dst_checktype(bucket[0], DST_NIL))
|
||||
return bucket[1];
|
||||
DstKV *bucket = dst_table_find(t, key);
|
||||
if (NULL != bucket && !dst_checktype(bucket->key, DST_NIL))
|
||||
return bucket->value;
|
||||
else
|
||||
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
|
||||
* was removed. */
|
||||
DstValue dst_table_remove(DstTable *t, DstValue key) {
|
||||
DstValue *bucket = dst_table_find(t, key);
|
||||
if (NULL != bucket && !dst_checktype(bucket[0], DST_NIL)) {
|
||||
DstValue ret = bucket[1];
|
||||
DstKV *bucket = dst_table_find(t, key);
|
||||
if (NULL != bucket && !dst_checktype(bucket->key, DST_NIL)) {
|
||||
DstValue ret = bucket->key;
|
||||
t->count--;
|
||||
t->deleted++;
|
||||
bucket[0] = dst_wrap_nil();
|
||||
bucket[1] = dst_wrap_false();
|
||||
bucket->key = dst_wrap_nil();
|
||||
bucket->value = dst_wrap_false();
|
||||
return ret;
|
||||
} else {
|
||||
return dst_wrap_nil();
|
||||
@ -131,18 +144,18 @@ void dst_table_put(DstTable *t, DstValue key, DstValue value) {
|
||||
if (dst_checktype(value, DST_NIL)) {
|
||||
dst_table_remove(t, key);
|
||||
} else {
|
||||
DstValue *bucket = dst_table_find(t, key);
|
||||
if (NULL != bucket && !dst_checktype(bucket[0], DST_NIL)) {
|
||||
bucket[1] = value;
|
||||
DstKV *bucket = dst_table_find(t, key);
|
||||
if (NULL != bucket && !dst_checktype(bucket->key, DST_NIL)) {
|
||||
bucket->value = value;
|
||||
} else {
|
||||
if (NULL == bucket || 4 * (t->count + t->deleted) >= t->capacity) {
|
||||
dst_table_rehash(t, 4 * t->count + 6);
|
||||
if (NULL == bucket || 2 * (t->count + t->deleted + 1) > t->capacity) {
|
||||
dst_table_rehash(t, dst_tablen(2 * t->count + 2));
|
||||
}
|
||||
bucket = dst_table_find(t, key);
|
||||
if (dst_checktype(bucket[1], DST_FALSE))
|
||||
if (dst_checktype(bucket->value, DST_FALSE))
|
||||
--t->deleted;
|
||||
bucket[0] = key;
|
||||
bucket[1] = value;
|
||||
bucket->key = key;
|
||||
bucket->value = value;
|
||||
++t->count;
|
||||
}
|
||||
}
|
||||
@ -151,54 +164,35 @@ void dst_table_put(DstTable *t, DstValue key, DstValue value) {
|
||||
/* Clear a table */
|
||||
void dst_table_clear(DstTable *t) {
|
||||
int32_t capacity = t->capacity;
|
||||
DstValue *data = t->data;
|
||||
DstKV *data = t->data;
|
||||
dst_memempty(data, capacity);
|
||||
t->count = 0;
|
||||
t->deleted = 0;
|
||||
}
|
||||
|
||||
/* Find next key in an object. Returns nil if no next key. */
|
||||
DstValue dst_table_next(DstTable *t, DstValue key) {
|
||||
const DstValue *bucket, *end;
|
||||
end = t->data + t->capacity;
|
||||
if (dst_checktype(key, DST_NIL)) {
|
||||
bucket = t->data;
|
||||
} else {
|
||||
bucket = dst_table_find(t, key);
|
||||
if (NULL == bucket || dst_checktype(bucket[0], DST_NIL))
|
||||
return dst_wrap_nil();
|
||||
bucket += 2;
|
||||
/* Find next key in an object. Returns NULL if no next key. */
|
||||
const DstKV *dst_table_next(DstTable *t, const DstKV *kv) {
|
||||
DstKV *end = t->data + t->capacity;
|
||||
kv = (kv == NULL) ? t->data : kv + 1;
|
||||
while (kv < end) {
|
||||
if (!dst_checktype(kv->key, DST_NIL))
|
||||
return kv;
|
||||
kv++;
|
||||
}
|
||||
for (; bucket < end; bucket += 2) {
|
||||
if (!dst_checktype(bucket[0], DST_NIL))
|
||||
return bucket[0];
|
||||
}
|
||||
return dst_wrap_nil();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Convert table to struct */
|
||||
const DstValue *dst_table_to_struct(DstTable *t) {
|
||||
int32_t i;
|
||||
DstValue *st = dst_struct_begin(t->count);
|
||||
for (i = 0; i < t->capacity; i += 2) {
|
||||
if (!dst_checktype(t->data[i], DST_NIL)) {
|
||||
dst_struct_put(st, t->data[i], t->data[i + 1]);
|
||||
}
|
||||
const DstKV *dst_table_to_struct(DstTable *t) {
|
||||
DstKV *st = dst_struct_begin(t->count);
|
||||
DstKV *kv = t->data;
|
||||
DstKV *end = t->data + t->capacity;
|
||||
while (kv < end) {
|
||||
if (!dst_checktype(kv->key, DST_NIL))
|
||||
dst_struct_put(st, kv->key, kv->value);
|
||||
kv++;
|
||||
}
|
||||
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
|
||||
|
68
core/util.c
68
core/util.c
@ -59,6 +59,18 @@ int32_t dst_array_calchash(const DstValue *array, int32_t len) {
|
||||
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 */
|
||||
int32_t dst_string_calchash(const uint8_t *str, int32_t 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;
|
||||
}
|
||||
|
||||
/* 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
|
||||
* view can be constructed, 0 if an invalid type. */
|
||||
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;
|
||||
return 1;
|
||||
} 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));
|
||||
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
|
||||
* identical structure. Returns 1 if the view can be constructed and
|
||||
* 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)) {
|
||||
*data = dst_unwrap_table(tab)->data;
|
||||
*cap = dst_unwrap_table(tab)->capacity;
|
||||
|
@ -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
|
||||
* associative data structure. */
|
||||
DstValue dst_next(DstValue ds, DstValue key) {
|
||||
const DstKV *dst_next(DstValue ds, const DstKV *kv) {
|
||||
switch(dst_type(ds)) {
|
||||
default:
|
||||
return dst_wrap_nil();
|
||||
return NULL;
|
||||
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:
|
||||
return dst_struct_next(dst_unwrap_struct(ds), key);
|
||||
return dst_struct_next(dst_unwrap_struct(ds), kv);
|
||||
}
|
||||
}
|
||||
|
||||
|
73
core/vector.c
Normal file
73
core/vector.c
Normal 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
58
core/vector.h
Normal 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
|
@ -43,7 +43,7 @@ static int dst_update_fiber() {
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
/* The root thread has termiated */
|
||||
/* The root thread has terminated */
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@ -68,7 +68,7 @@ static int dst_continue(DstValue *returnreg) {
|
||||
* Pulls out unsigned integers */
|
||||
#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_binop_integer(op) \
|
||||
|
27
core/wrap.c
27
core/wrap.c
@ -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
|
||||
* to 47 bit pointers (which is what userspace uses on Windows, we can use
|
||||
* 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;
|
||||
#endif
|
||||
return x.pointer;
|
||||
}
|
||||
|
||||
DstValue dst_nanbox_from_pointer(void *p, uint64_t tagmask) {
|
||||
DstValue ret;
|
||||
ret.pointer = p;
|
||||
#if defined (DST_NANBOX_47) || defined (DST_32)
|
||||
#else
|
||||
ret.u64 &= DST_NANBOX_POINTERBITS;
|
||||
#endif
|
||||
ret.u64 |= tagmask;
|
||||
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 ret;
|
||||
ret.cpointer = p;
|
||||
#if defined (DST_NANBOX_47) || defined (DST_32)
|
||||
#else
|
||||
ret.u64 &= DST_NANBOX_POINTERBITS;
|
||||
#endif
|
||||
ret.u64 |= tagmask;
|
||||
return ret;
|
||||
}
|
||||
@ -68,18 +78,21 @@ DstValue dst_nanbox_from_bits(uint64_t bits) {
|
||||
|
||||
void *dst_nanbox_memalloc_empty(int32_t count) {
|
||||
int32_t i;
|
||||
void *mem = malloc(count * sizeof(DstValue));
|
||||
DstValue *mmem = (DstValue *)mem;
|
||||
void *mem = malloc(count * sizeof(DstKV));
|
||||
DstKV *mmem = (DstKV *)mem;
|
||||
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;
|
||||
}
|
||||
|
||||
void dst_nanbox_memempty(DstValue *mem, int32_t count) {
|
||||
void dst_nanbox_memempty(DstKV *mem, int32_t count) {
|
||||
int32_t 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(array, DstArray *, DST_ARRAY, pointer)
|
||||
DST_WRAP_DEFINE(tuple, const DstValue *, DST_TUPLE, cpointer)
|
||||
DST_WRAP_DEFINE(struct, const DstValue *, DST_STRUCT, cpointer)
|
||||
DST_WRAP_DEFINE(thread, DstFiber *, DST_FIBER, pointer)
|
||||
DST_WRAP_DEFINE(struct, const DstKV *, DST_STRUCT, cpointer)
|
||||
DST_WRAP_DEFINE(fiber, DstFiber *, DST_FIBER, pointer)
|
||||
DST_WRAP_DEFINE(buffer, DstBuffer *, DST_BUFFER, pointer)
|
||||
DST_WRAP_DEFINE(function, DstFunction *, DST_FUNCTION, pointer)
|
||||
DST_WRAP_DEFINE(cfunction, DstCFunction, DST_CFUNCTION, pointer)
|
||||
|
@ -47,23 +47,49 @@
|
||||
(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 (< nil 1.0 1 false true "hi"
|
||||
(assert (< nil false true
|
||||
(fiber (fn [x] x))
|
||||
1 1.0 "hi"
|
||||
(quote hello)
|
||||
(array 1 2 3)
|
||||
(tuple 1 2 3)
|
||||
(table "a" "b" "c" false)
|
||||
(struct 1 2)
|
||||
(fiber (fn [x] x))
|
||||
(table "a" "b" "c" "d")
|
||||
(struct 1 2 3 4)
|
||||
(buffer "hi")
|
||||
(fn [x] (+ x x))
|
||||
+) "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 true "true literal")
|
||||
(assert (not nil) "nil literal")
|
||||
(assert (= 7 (| 3 4)) "bit or")
|
||||
(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 (= '(1 2 3) (quote (1 2 3)) (tuple 1 2 3)) "quote shorthand")
|
||||
|
||||
|
@ -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))
|
||||
|
||||
/* 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_capacity(t) (dst_struct_length(t) * 4)
|
||||
#define dst_struct_hash(t) ((dst_struct_raw(t)[1]))
|
||||
DstValue *dst_struct_begin(int32_t count);
|
||||
void dst_struct_put(DstValue *st, DstValue key, DstValue value);
|
||||
const DstValue *dst_struct_end(DstValue *st);
|
||||
DstValue dst_struct_get(const DstValue *st, DstValue key);
|
||||
DstValue dst_struct_next(const DstValue *st, DstValue key);
|
||||
DstTable *dst_struct_to_table(const DstValue *st);
|
||||
int dst_struct_equal(const DstValue *lhs, const DstValue *rhs);
|
||||
int dst_struct_compare(const DstValue *lhs, const DstValue *rhs);
|
||||
#define dst_struct_capacity(t) (dst_struct_raw(t)[1])
|
||||
#define dst_struct_hash(t) (dst_struct_raw(t)[2])
|
||||
/* Do something with the 4th header slot - flags? */
|
||||
DstKV *dst_struct_begin(int32_t count);
|
||||
void dst_struct_put(DstKV *st, DstValue key, DstValue value);
|
||||
const DstKV *dst_struct_end(DstKV *st);
|
||||
DstValue dst_struct_get(const DstKV *st, DstValue key);
|
||||
const DstKV *dst_struct_next(const DstKV *st, const DstKV *kv);
|
||||
DstTable *dst_struct_to_table(const DstKV *st);
|
||||
int dst_struct_equal(const DstKV *lhs, const DstKV *rhs);
|
||||
int dst_struct_compare(const DstKV *lhs, const DstKV *rhs);
|
||||
|
||||
/* Table functions */
|
||||
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_remove(DstTable *t, DstValue key);
|
||||
void dst_table_put(DstTable *t, DstValue key, DstValue value);
|
||||
DstValue dst_table_next(DstTable *t, DstValue key);
|
||||
const DstValue *dst_table_to_struct(DstTable *t);
|
||||
const DstKV *dst_table_next(DstTable *t, const DstKV *kv);
|
||||
const DstKV *dst_table_to_struct(DstTable *t);
|
||||
void dst_table_merge(DstTable *t, DstValue other);
|
||||
|
||||
/* 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_push3(DstFiber *fiber, DstValue x, DstValue y, DstValue z);
|
||||
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_tail(DstFiber *fiber, DstFunction *func);
|
||||
void dst_fiber_cframe(DstFiber *fiber);
|
||||
void dst_fiber_popframe(DstFiber *fiber);
|
||||
|
||||
/* Functions */
|
||||
void dst_function_detach(DstFunction *func);
|
||||
|
||||
/* Assembly */
|
||||
DstAssembleResult dst_asm(DstAssembleOptions opts);
|
||||
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 */
|
||||
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_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 */
|
||||
#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);
|
||||
DstValue dst_get(DstValue ds, DstValue key);
|
||||
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_capacity(DstValue x);
|
||||
DstValue dst_getindex(DstValue ds, int32_t index);
|
||||
@ -169,11 +166,19 @@ void dst_setindex(DstValue ds, DstValue value, int32_t index);
|
||||
/* Utils */
|
||||
extern const char dst_base64[65];
|
||||
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_tablen(int32_t n);
|
||||
DstValue dst_loadreg(DstReg *regs, size_t count);
|
||||
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);
|
||||
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 */
|
||||
DstParseResult dst_parse(const uint8_t *src, int32_t len);
|
||||
|
@ -28,7 +28,8 @@
|
||||
|
||||
/*
|
||||
* Detect OS and endianess.
|
||||
* From webkit source.
|
||||
* From webkit source. There is likely some extreneous
|
||||
* detection for unsupported platforms
|
||||
*/
|
||||
|
||||
/* Check Unix */
|
||||
@ -116,6 +117,14 @@
|
||||
#define DST_RECURSION_GUARD 1000
|
||||
|
||||
/* 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 */
|
||||
|
@ -44,6 +44,7 @@ typedef struct DstReg DstReg;
|
||||
typedef struct DstAbstractHeader DstAbstractHeader;
|
||||
typedef struct DstFuncDef DstFuncDef;
|
||||
typedef struct DstFuncEnv DstFuncEnv;
|
||||
typedef struct DstKV DstKV;
|
||||
typedef struct DstStackFrame DstStackFrame;
|
||||
typedef struct DstAbstractType DstAbstractType;
|
||||
typedef int (*DstCFunction)(int32_t argn, DstValue *argv, DstValue *ret);
|
||||
@ -109,11 +110,13 @@ union DstValue {
|
||||
double real;
|
||||
};
|
||||
|
||||
#define dst_u64(x) ((x).u64)
|
||||
|
||||
/* 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
|
||||
* 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
|
||||
* 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..................| */
|
||||
/* Non-double: t|11111111111|1ttt|xxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */
|
||||
@ -121,44 +124,61 @@ union DstValue {
|
||||
|
||||
/* Double (no NaNs): x xxxxxxxxxxx xxxx xxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */
|
||||
|
||||
/* A simple scheme for nan boxed values */
|
||||
/* normal doubles, denormalized doubles, and infinities are doubles */
|
||||
/* Quiet nan is nil. Sign bit should be 0. */
|
||||
#if defined (DST_NANBOX_47) || defined (DST_32)
|
||||
|
||||
#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_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) \
|
||||
((((uint64_t)(type) & 0x8) << 12) | 0x7FF8 | (type))
|
||||
((((uint64_t)(type) & 0x1) << 15) | 0x7FF8 | ((type) >> 1))
|
||||
|
||||
#define dst_nanbox_tag(type) \
|
||||
(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) \
|
||||
(((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) \
|
||||
(!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) \
|
||||
(((t) == DST_REAL) \
|
||||
? dst_nanbox_isreal(x) \
|
||||
: dst_nanbox_checkauxtype((x), (t)))
|
||||
|
||||
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);
|
||||
DstValue dst_nanbox_from_pointer(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))
|
||||
|
||||
#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) \
|
||||
dst_nanbox_from_cpointer((p), dst_nanbox_tag(t) | 0x7FF8000000000000lu)
|
||||
dst_nanbox_from_cpointer((p), dst_nanbox_tag(t))
|
||||
|
||||
/* Wrap the simple types */
|
||||
#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 */
|
||||
#define dst_unwrap_boolean(x) \
|
||||
(((x).u64 >> 48) == dst_nanbox_lowtag(DST_TRUE))
|
||||
(dst_checktype(x, DST_TRUE))
|
||||
#define dst_unwrap_integer(x) \
|
||||
((int32_t)((x).u64 & 0xFFFFFFFFlu))
|
||||
#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)
|
||||
|
||||
/* 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_fiber(x) ((DstFiber *)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_memempty(mem, count) memset((mem), 0, sizeof(DstValue) * (count))
|
||||
#define dst_memalloc_empty(count) calloc((count), sizeof(DstValue))
|
||||
#define dst_memempty(mem, count) memset((mem), 0, sizeof(DstKV) * (count))
|
||||
#define dst_memalloc_empty(count) calloc((count), sizeof(DstKV))
|
||||
#define dst_type(x) ((x).type)
|
||||
#define dst_checktype(x, t) ((x).type == (t))
|
||||
#define dst_truthy(x) \
|
||||
((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_fiber(x) ((DstFiber *)(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_array(DstArray *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_buffer(DstBuffer *x);
|
||||
DstValue dst_wrap_function(DstFunction *x);
|
||||
@ -332,12 +352,18 @@ struct DstBuffer {
|
||||
|
||||
/* A mutable associative data type. Backed by a hashtable. */
|
||||
struct DstTable {
|
||||
DstValue *data;
|
||||
DstKV *data;
|
||||
int32_t count;
|
||||
int32_t capacity;
|
||||
int32_t deleted;
|
||||
};
|
||||
|
||||
/* A key value pair in a struct or table */
|
||||
struct DstKV {
|
||||
DstValue key;
|
||||
DstValue value;
|
||||
};
|
||||
|
||||
/* Some function defintion flags */
|
||||
#define DST_FUNCDEF_FLAG_VARARG 1
|
||||
#define DST_FUNCDEF_FLAG_NEEDSENV 4
|
||||
|
1
packages/test.c
Normal file
1
packages/test.c
Normal file
@ -0,0 +1 @@
|
||||
#include <dst/dst.h>
|
Loading…
Reference in New Issue
Block a user