Work on interpreter. adding more opcodes and syscalls.

This commit is contained in:
bakpakin 2017-11-24 23:17:04 -05:00
parent 6ca6949c2d
commit 412d40d09f
17 changed files with 569 additions and 408 deletions

View File

@ -0,0 +1 @@
autocmd BufRead,BufNewFile *.dst,*.dsts setlocal filetype=dst

View File

@ -0,0 +1,25 @@
" Vim filetype plugin file
" Language: DST
" Maintainer: Calvin Rose
if exists("b:did_ftplugin")
finish
endif
let b:did_ftplugin = 1
let s:cpo_save = &cpo
set cpo&vim
setlocal iskeyword+=?,-,*,!,+,/,=,<,>,.,:,$
" There will be false positives, but this is better than missing the whole set
" of user-defined def* definitions.
setlocal define=\\v[(/]def(ault)@!\\S*
" Remove 't' from 'formatoptions' to avoid auto-wrapping code.
setlocal formatoptions-=t
setlocal comments=n:#
setlocal commentstring=#\ %s
let &cpo = s:cpo_save

View File

@ -0,0 +1,17 @@
" Vim filetype plugin file
" Language: DST
" Maintainer: Calvin Rose
if exists("b:did_indent")
finish
endif
let b:did_indent = 1
let s:cpo_save = &cpo
set cpo&vim
setlocal noautoindent nosmartindent
setlocal softtabstop=2 shiftwidth=2 expandtab
setlocal indentkeys=!,o,O
let &cpo = s:cpo_save

View File

@ -0,0 +1,69 @@
" Vim syntax file
" Language: DST
" Maintainer: Calvin Rose
if exists("b:current_syntax")
finish
endif
let s:cpo_sav = &cpo
set cpo&vim
if has("folding") && exists("g:dst_fold") && g:dst_fold > 0
setlocal foldmethod=syntax
endif
syntax keyword DstCommentTodo contained FIXME XXX TODO FIXME: XXX: TODO:
" DST comments
syn match DstComment "#.*$" contains=DstCommentTodo,@Spell
syntax match DstStringEscape '\v\\%([\\btnfr"])' contained
syntax region DstString matchgroup=DstStringDelimiter start=/"/ skip=/\\\\\|\\"/ end=/"/ contains=DstStringEscape,@Spell
" Dst Symbols
syn match DstSymbol '\v<%([a-zA-Z!$&*_+=|<.>?-])+%([a-zA-Z0-9!#$%&*_+=|'<.>/?-])*>'
" DST numbers
syn match DstReal '\v<[-+]?%(\d+|\d+\.\d*)%([eE][-+]?\d+)?>'
syn match DstInteger '\v<[-+]?%(\d+)>'
syn match DstConstant 'nil'
syn match DstConstant 'true'
syn match DstConstant 'false'
" Dst Keywords
syn match DstKeyword '\v<:[a-zA-Z0-9_\-]*>'
syntax match DstQuote "'"
" -*- TOP CLUSTER -*-
syntax cluster DstTop contains=@Spell,DstComment,DstConstant,DstQuote,DstKeyword,DstSymbol,DstInteger,DstReal,DstString,DstTuple,DstArray,DstTable,DstStruct
syntax region DstTuple matchgroup=DstParen start="(" end=")" contains=@DstTop fold
syntax region DstArray matchgroup=DstParen start="\[" end="]" contains=@DstTop fold
syntax region DstTable matchgroup=DstParen start="{" end="}" contains=@DstTop fold
syntax region DstStruct matchgroup=DstParen start="@{" end="}" contains=@DstTop fold
" Highlight superfluous closing parens, brackets and braces.
syntax match DstError "]\|}\|)"
syntax sync fromstart
" Highlighting
hi def link DstComment Comment
hi def link DstSymbol Identifier
hi def link DstInteger Number
hi def link DstReal Type
hi def link DstConstant Constant
hi def link DstKeyword Keyword
hi def link DstString String
hi def link DstStringDelimiter String
hi def link DstQuote SpecialChar
hi def link DstParen Delimiter
let b:current_syntax = "dst"
let &cpo = s:cpo_sav
unlet! s:cpo_sav

View File

@ -72,6 +72,7 @@ enum DstInstructionType {
DIT_SU, /* Unsigned */
DIT_SSS,
DIT_SSI,
DIT_SSU,
DIT_SES,
DIT_SC
};
@ -117,9 +118,6 @@ static const DstInstructionDef dst_ops[] = {
{"bitxor", DIT_SSS, DOP_BXOR},
{"call", DIT_SS, DOP_CALL},
{"closure", DIT_SC, DOP_CLOSURE},
{"coerce-integer", DIT_SS, DOP_COERCE_INTEGER},
{"coerce-real", DIT_SS, DOP_COERCE_REAL},
{"coerce-string", DIT_SS, DOP_COERCE_STRING},
{"compare", DIT_SSS, DOP_COMPARE},
{"divide", DIT_SSS, DOP_DIVIDE},
{"divide-immediate", DIT_SSI, DOP_DIVIDE_IMMEDIATE},
@ -127,9 +125,13 @@ static const DstInstructionDef dst_ops[] = {
{"divide-real", DIT_SSS, DOP_DIVIDE_REAL},
{"equals", DIT_SSS, DOP_EQUALS},
{"error", DIT_S, DOP_ERROR},
{"get", DIT_SSS, DOP_GET},
{"get-index", DIT_SSU, DOP_GET_INDEX},
{"greater-than", DIT_SSS, DOP_GREATER_THAN},
{"jump", DIT_L, DOP_JUMP},
{"jump-if", DIT_SL, DOP_JUMP_IF},
{"jump-if-not", DIT_SL, DOP_JUMP_IF_NOT},
{"less-than", DIT_SSS, DOP_LESS_THAN},
{"load-boolean", DIT_S, DOP_LOAD_BOOLEAN},
{"load-constant", DIT_SC, DOP_LOAD_CONSTANT},
{"load-integer", DIT_SI, DOP_LOAD_INTEGER},
@ -143,9 +145,11 @@ static const DstInstructionDef dst_ops[] = {
{"multiply-real", DIT_SSS, DOP_MULTIPLY_REAL},
{"noop", DIT_0, DOP_NOOP},
{"push", DIT_S, DOP_PUSH},
{"push-array", DIT_S, DOP_PUSH_ARRAY},
{"push2", DIT_SS, DOP_PUSH_2},
{"push3", DIT_SSS, DOP_PUSH_3},
{"push-array", DIT_S, DOP_PUSH_ARRAY},
{"put", DIT_SSS, DOP_PUT},
{"put-index", DIT_SSU, DOP_PUT_INDEX},
{"return", DIT_S, DOP_RETURN},
{"return-nil", DIT_0, DOP_RETURN_NIL},
{"set-upvalue", DIT_SES, DOP_SET_UPVALUE},
@ -240,6 +244,7 @@ static void dst_asm_errorv(DstAssembler *a, const uint8_t *m) {
/* Parse an argument to an assembly instruction, and return the result as an
* integer. This integer will need to be trimmed and bound checked. */
static int64_t doarg_1(DstAssembler *a, DstOpArgType argtype, DstValue x) {
int64_t ret = -1;
DstTable *c;
switch (argtype) {
case DST_OAT_SLOT:
@ -264,44 +269,58 @@ static int64_t doarg_1(DstAssembler *a, DstOpArgType argtype, DstValue x) {
}
switch (x.type) {
default:
goto error;
break;
case DST_INTEGER:
return x.as.integer;
ret = x.as.integer;
break;
case DST_TUPLE:
{
if (argtype == DST_OAT_TYPE) {
int64_t result = 0;
ret = 0;
uint32_t i = 0;
for (i = 0; i < dst_tuple_length(x.as.tuple); i++) {
result |= doarg_1(a, DST_OAT_SIMPLETYPE, x.as.tuple[i]);
ret |= doarg_1(a, DST_OAT_SIMPLETYPE, x.as.tuple[i]);
}
return result;
} else {
goto error;
}
break;
}
case DST_SYMBOL:
case DST_STRING:
{
x.type = DST_SYMBOL;
if (NULL != c) {
DstValue result = dst_table_get(c, x);
if (result.type == DST_INTEGER) {
if (argtype == DST_OAT_LABEL)
return result.as.integer - a->bytecode_count;
return result.as.integer;
if (argtype == DST_OAT_LABEL) {
ret = result.as.integer - a->bytecode_count;
} else {
ret = result.as.integer;
}
} else {
dst_asm_errorv(a, dst_formatc("unknown name %q", x));
}
} else if (argtype == DST_OAT_TYPE || argtype == DST_OAT_SIMPLETYPE) {
int index = strsearch(x.as.string, dst_type_names);
if (index != -1) {
return (int64_t) index;
ret = (int64_t) index;
} else {
dst_asm_errorv(a, dst_formatc("unknown type %q", x));
}
} else {
goto error;
}
break;
}
}
dst_asm_errorv(a, dst_formatc("unexpected type %t parsing instruction argument", x.type));
if (argtype == DST_OAT_SLOT && ret >= a->def->slotcount)
a->def->slotcount = (uint32_t) ret + 1;
return ret;
error:
dst_asm_errorv(a, dst_formatc("error parsing instruction argument %v", x));
return 0;
}
@ -395,12 +414,13 @@ static uint32_t read_instruction(DstAssembler *a, const DstInstructionDef *idef,
break;
}
case DIT_SSI:
case DIT_SSU:
{
if (dst_tuple_length(argt) != 4)
dst_asm_error(a, "expected 3 arguments: (op, slot, slot, integer)");
instr |= doarg(a, DST_OAT_SLOT, 1, 1, 0, argt[1]);
instr |= doarg(a, DST_OAT_SLOT, 2, 1, 0, argt[2]);
instr |= doarg(a, DST_OAT_INTEGER, 3, 1, 1, argt[3]);
instr |= doarg(a, DST_OAT_INTEGER, 3, 1, idef->type == DIT_SSI, argt[3]);
break;
}
case DIT_SES:
@ -410,7 +430,7 @@ static uint32_t read_instruction(DstAssembler *a, const DstInstructionDef *idef,
if (dst_tuple_length(argt) != 4)
dst_asm_error(a, "expected 3 arguments: (op, slot, environment, envslot)");
instr |= doarg(a, DST_OAT_SLOT, 1, 1, 0, argt[1]);
env = doarg(a, DST_OAT_ENVIRONMENT, 2, 1, 0, argt[2]);
env = doarg(a, DST_OAT_ENVIRONMENT, 0, 1, 0, argt[2]);
instr |= env << 16;
for (env += 1; env > 0; env--) {
b = b->parent;
@ -519,7 +539,6 @@ static DstAssembleResult dst_asm1(DstAssembler *parent, DstAssembleOptions opts)
/* Create slot aliases */
x = dst_struct_get(st, dst_wrap_symbol(dst_cstring("slots")));
if (dst_seq_view(x, &arr, &count)) {
def->slotcount = count;
for (i = 0; i < count; i++) {
DstValue v = arr[i];
if (v.type == DST_TUPLE) {
@ -535,13 +554,8 @@ static DstAssembleResult dst_asm1(DstAssembler *parent, DstAssembleOptions opts)
dst_asm_error(&a, "slot names must be symbols or tuple of symbols");
}
}
} else if (x.type == DST_INTEGER) {
def->slotcount = (uint32_t) x.as.integer;
} else {
dst_asm_error(&a, "slots must be specified");
}
/* Create environment aliases */
x = dst_struct_get(st, dst_wrap_symbol(dst_cstring("environments")));
if (dst_seq_view(x, &arr, &count)) {
@ -596,6 +610,7 @@ static DstAssembleResult dst_asm1(DstAssembler *parent, DstAssembleOptions opts)
for (i = 0; i < count; ++i) {
DstValue instr = arr[i];
if (instr.type == DST_STRING) {
instr.type = DST_SYMBOL;
dst_table_put(&a.labels, instr, dst_wrap_integer(blength));
} else if (instr.type == DST_TUPLE) {
blength++;

View File

@ -30,9 +30,6 @@ enum DstOpCode {
DOP_TYPECHECK,
DOP_RETURN,
DOP_RETURN_NIL,
DOP_COERCE_INTEGER,
DOP_COERCE_REAL,
DOP_COERCE_STRING,
DOP_ADD_INTEGER,
DOP_ADD_IMMEDIATE,
DOP_ADD_REAL,
@ -61,7 +58,9 @@ enum DstOpCode {
DOP_MOVE,
DOP_JUMP,
DOP_JUMP_IF,
DOP_JUMP_IF_NOT,
DOP_GREATER_THAN,
DOP_LESS_THAN,
DOP_EQUALS,
DOP_COMPARE,
DOP_LOAD_NIL,
@ -79,7 +78,12 @@ enum DstOpCode {
DOP_TAILCALL,
DOP_SYSCALL,
DOP_LOAD_SYSCALL,
DOP_TRANSFER
DOP_TRANSFER,
DOP_GET,
DOP_PUT,
DOP_GET_INDEX,
DOP_PUT_INDEX,
DOP_LENGTH
};
#endif

View File

@ -141,7 +141,7 @@ static int is_symbol_char(uint8_t c) {
if (c >= '0' && c <= ':') return 1;
if (c >= '<' && c <= '@') return 1;
if (c >= '*' && c <= '/') return 1;
if (c >= '#' && c <= '&') return 1;
if (c >= '$' && c <= '&') return 1;
if (c == '_') return 1;
if (c == '^') return 1;
if (c == '!') return 1;

View File

@ -24,7 +24,7 @@
#include <dst/dst.h>
#include <stdio.h>
int dst_print(DstValue *argv, uint32_t argn) {
int dst_sys_print(DstValue *argv, uint32_t argn) {
uint32_t i;
for (i = 0; i < argn; ++i) {
uint32_t j, len;
@ -38,6 +38,91 @@ int dst_print(DstValue *argv, uint32_t argn) {
return 0;
}
int dst_sys_asm(DstValue *argv, uint32_t argn) {
DstAssembleOptions opts;
DstAssembleResult res;
if (argn < 1) {
dst_vm_fiber->ret = dst_cstringv("expected assembly source");
return 1;
}
opts.source = argv[0];
opts.parsemap = argn >= 2 ? argv[1] : dst_wrap_nil();
opts.flags = 0;
res = dst_asm(opts);
if (res.status == DST_ASSEMBLE_OK) {
dst_vm_fiber->ret = dst_wrap_function(dst_asm_func(res));
return 0;
} else {
dst_vm_fiber->ret = dst_wrap_string(res.result.error);
return 1;
}
}
int dst_sys_tuple(DstValue *argv, uint32_t argn) {
dst_vm_fiber->ret = dst_wrap_tuple(dst_tuple_n(argv, argn));
return 0;
}
int dst_sys_array(DstValue *argv, uint32_t argn) {
DstArray *array = dst_array(argn);
array->count = argn;
memcpy(array->data, argv, argn * sizeof(DstValue));
dst_vm_fiber->ret = dst_wrap_array(array);
return 0;
}
int dst_sys_table(DstValue *argv, uint32_t argn) {
uint32_t i;
DstTable *table = dst_table(argn/2);
if (argn & 1) {
dst_vm_fiber->ret = dst_cstringv("expected even number of arguments");
return 1;
}
for (i = 0; i < argn; i += 2) {
dst_table_put(table, argv[i], argv[i + 1]);
}
dst_vm_fiber->ret = dst_wrap_table(table);
return 0;
}
int dst_sys_struct(DstValue *argv, uint32_t argn) {
uint32_t i;
DstValue *st = dst_struct_begin(argn/2);
if (argn & 1) {
dst_vm_fiber->ret = dst_cstringv("expected even number of arguments");
return 1;
}
for (i = 0; i < argn; i += 2) {
dst_struct_put(st, argv[i], argv[i + 1]);
}
dst_vm_fiber->ret = dst_wrap_struct(dst_struct_end(st));
return 0;
}
int dst_sys_get(DstValue *argv, uint32_t argn) {
uint32_t i;
if (argn < 2) {
dst_vm_fiber->ret = dst_cstringv("expected at least 1 argument");
return 1;
}
DstValue ds = argv[0];
for (i = 1; i < argn; i++) {
const char *err = dst_try_get(ds, argv[i], &ds);
if (NULL != err) {
dst_vm_fiber->ret = dst_cstringv(err);
return 1;
}
}
dst_vm_fiber->ret = ds;
return 0;
}
DstCFunction dst_vm_syscalls[256] = {
dst_print
dst_sys_print,
dst_sys_asm,
dst_sys_tuple,
dst_sys_array,
dst_sys_struct,
dst_sys_table,
NULL
};

View File

@ -174,8 +174,7 @@ DstValue dst_table_next(DstTable *t, DstValue key) {
/* Convert table to struct */
const DstValue *dst_table_to_struct(DstTable *t) {
uint32_t i;
const DstValue *st;
st = dst_struct_begin(t->count);
DstValue *st = dst_struct_begin(t->count);
for (i = 0; i < t->capacity; i++) {
if (t->data[i].type != DST_NIL)
dst_struct_put(st, t->data[i], t->data[i + 1]);

View File

@ -102,14 +102,3 @@ double dst_integer_to_real(int64_t integer) {
/* TODO - consider c undefined behavior */
return (double) integer;
}
/* Convert an index used by the capi to an absolute index */
uint32_t dst_startrange(int64_t index, uint32_t modulo) {
if (index < 0) index += modulo;
return ((index >= 0 && index < modulo)) ? ((uint32_t) index) : 0;
}
/* Convert an index used by the capi to an absolute index */
uint32_t dst_endrange(int64_t index, uint32_t modulo) {
return dst_startrange(index, modulo + 1);
}

View File

@ -192,3 +192,182 @@ int dst_compare(DstValue x, DstValue y) {
}
return 1;
}
/* Get a value out af an associated data structure.
* Returns possible c error message, and NULL for no error. The
* useful return value is written to out on success */
const char *dst_try_get(DstValue ds, DstValue key, DstValue *out) {
int64_t index;
DstValue ret;
switch (ds.type) {
case DST_ARRAY:
if (key.type != DST_INTEGER) return "expected integer key";
index = key.as.integer;
if (index < 0 || index >= ds.as.array->count)
return "invalid array access";
ret = ds.as.array->data[index];
break;
case DST_TUPLE:
if (key.type != DST_INTEGER) return "expected integer key";
index = key.as.integer;
if (index < 0 || index >= dst_tuple_length(ds.as.tuple))
return "invalid tuple access";
ret = ds.as.tuple[index];
break;
case DST_BUFFER:
if (key.type != DST_INTEGER) return "expected integer key";
index = key.as.integer;
if (index < 0 || index >= ds.as.buffer->count)
return "invalid buffer access";
ret.type = DST_INTEGER;
ret.as.integer = ds.as.buffer->data[index];
break;
case DST_STRING:
case DST_SYMBOL:
if (key.type != DST_INTEGER) return "expected integer key";
index = key.as.integer;
if (index < 0 || index >= dst_string_length(ds.as.string))
return "invalid string access";
ret.type = DST_INTEGER;
ret.as.integer = ds.as.string[index];
break;
case DST_STRUCT:
ret = dst_struct_get(ds.as.st, key);
break;
case DST_TABLE:
ret = dst_table_get(ds.as.table, key);
break;
default:
return "cannot get";
}
*out = ret;
return NULL;
}
/* Set a value in an associative data structure. Returns possible
* error message, and NULL if no error. */
const char *dst_try_put(DstValue ds, DstValue key, DstValue value) {
int64_t index;
switch (ds.type) {
case DST_ARRAY:
if (key.type != DST_INTEGER) return "expected integer key";
index = key.as.integer;
if (index < 0 || index >= ds.as.array->count)
return "invalid array access";
ds.as.array->data[index] = value;
break;
case DST_BUFFER:
if (key.type != DST_INTEGER) return "expected integer key";
index = key.as.integer;
if (value.type != DST_INTEGER) return "expected integer value";
if (index < 0 || index >= ds.as.buffer->count)
return "invalid buffer access";
ds.as.buffer->data[index] = (uint8_t) value.as.integer;
break;
case DST_TABLE:
dst_table_put(ds.as.table, key, value);
break;
default:
return "cannot set";
}
return NULL;
}
/* Get the next key in an associative data structure. Used for iterating through an
* associative data structure. */
const char *dst_try_next(DstValue ds, DstValue key, DstValue *out) {
switch(ds.type) {
default:
return "expected table or struct";
case DST_TABLE:
*out = dst_table_next(ds.as.table, key);
return NULL;
case DST_STRUCT:
*out = dst_struct_next(ds.as.st, key);
return NULL;
}
}
/* Get the length of an object. Returns errors for invalid types */
uint32_t dst_length(DstValue x) {
switch (x.type) {
default:
return 0;
case DST_STRING:
return dst_string_length(x.as.string);
case DST_ARRAY:
return x.as.array->count;
case DST_BUFFER:
return x.as.buffer->count;
case DST_TUPLE:
return dst_tuple_length(x.as.tuple);
case DST_STRUCT:
return dst_struct_length(x.as.st);
case DST_TABLE:
return x.as.table->count;
}
}
/* Get the capacity of an object. Returns 0 for invalid types */
uint32_t dst_capacity(DstValue x) {
switch (x.type) {
default:
return 0;
case DST_STRING:
return dst_string_length(x.as.string);
case DST_ARRAY:
return x.as.array->capacity;
case DST_BUFFER:
return x.as.buffer->capacity;
case DST_TUPLE:
return dst_tuple_length(x.as.tuple);
case DST_STRUCT:
return dst_struct_length(x.as.st);
case DST_TABLE:
return x.as.table->capacity;
}
}
/* Index into a data structure. Returns nil for out of bounds or invliad data structure */
DstValue dst_getindex(DstValue ds, uint32_t index) {
switch (ds.type) {
default:
return dst_wrap_nil();
case DST_STRING:
if (index >= dst_string_length(ds.as.string)) return dst_wrap_nil();
return dst_wrap_integer(ds.as.string[index]);
case DST_ARRAY:
if (index >= ds.as.array->count) return dst_wrap_nil();
return ds.as.array->data[index];
case DST_BUFFER:
if (index >= ds.as.buffer->count) return dst_wrap_nil();
return dst_wrap_integer(ds.as.buffer->data[index]);
case DST_TUPLE:
if (index >= dst_tuple_length(ds.as.tuple)) return dst_wrap_nil();
return ds.as.tuple[index];
}
}
/* Set an index in a linear data structure. Does nothing if data structure
* is invalid */
void dst_setindex(DstValue ds, DstValue value, uint32_t index) {
switch (ds.type) {
default:
return;
case DST_ARRAY:
if (index >= ds.as.array->count) {
dst_array_ensure(ds.as.array, 2 * index);
ds.as.array->count = index + 1;
}
ds.as.array->data[index] = value;
return;
case DST_BUFFER:
if (value.type != DST_INTEGER) return;
if (index >= ds.as.buffer->count) {
dst_buffer_ensure(ds.as.buffer, 2 * index);
ds.as.buffer->count = index + 1;
}
ds.as.buffer->data[index] = value.as.integer;
return;
}
}

199
core/vm.c
View File

@ -26,6 +26,29 @@
/* VM State */
DstFiber *dst_vm_fiber;
/* Helper to ensure proper fiber is activated after returning */
static int dst_update_fiber() {
if (dst_vm_fiber->frame == 0) {
dst_vm_fiber->status = DST_FIBER_DEAD;
}
while (dst_vm_fiber->status == DST_FIBER_DEAD ||
dst_vm_fiber->status == DST_FIBER_ERROR) {
if (NULL != dst_vm_fiber->parent) {
dst_vm_fiber = dst_vm_fiber->parent;
if (dst_vm_fiber->status == DST_FIBER_ALIVE) {
/* If the parent thread is still alive,
we are inside a cfunction */
return 1;
}
} else {
/* The root thread has termiated */
return 1;
}
}
dst_vm_fiber->status = DST_FIBER_ALIVE;
return 0;
}
/* Start running the VM from where it left off. */
int dst_continue() {
@ -122,37 +145,6 @@ int dst_continue() {
dst_vm_fiber->ret.type = DST_NIL;
goto vm_return;
case DOP_COERCE_INTEGER:
{
DstValue input = stack[oparg(2, 0xFFFF)];
if (input.type == DST_INTEGER) {
stack[oparg(1, 0xFF)] = input;
} else if (input.type == DST_REAL) {
stack[oparg(1, 0xFF)] = dst_wrap_integer(dst_real_to_integer(input.as.real));
} else {
vm_throw("expected number");
}
continue;
}
case DOP_COERCE_REAL:
{
DstValue input = stack[oparg(2, 0xFFFF)];
if (input.type == DST_INTEGER) {
stack[oparg(1, 0xFF)] = dst_wrap_real(dst_integer_to_real(input.as.integer));
} else if (input.type == DST_REAL) {
stack[oparg(1, 0xFF)] = input;
} else {
vm_throw("expected number");
}
continue;
}
case DOP_COERCE_STRING:
stack[oparg(1, 0xFF)] = dst_wrap_string(dst_to_string(stack[oparg(2, 0xFFFF)]));
pc++;
break;
case DOP_ADD_INTEGER:
vm_binop_integer(+);
@ -269,7 +261,7 @@ int dst_continue() {
case DOP_SHIFT_RIGHT_IMMEDIATE:
stack[oparg(1, 0xFF)] = dst_wrap_integer(
stack[oparg(2, 0xFF)].as.uinteger >> oparg(3, 0xFF)
(int64_t)(stack[oparg(2, 0xFF)].as.uinteger >> oparg(3, 0xFF))
);
pc++;
continue;
@ -277,6 +269,13 @@ int dst_continue() {
case DOP_SHIFT_LEFT:
vm_binop_integer(<<);
case DOP_SHIFT_LEFT_IMMEDIATE:
stack[oparg(1, 0xFF)] = dst_wrap_integer(
stack[oparg(2, 0xFF)].as.integer << oparg(3, 0xFF)
);
pc++;
continue;
case DOP_MOVE:
stack[oparg(1, 0xFF)] = stack[oparg(2, 0xFFFF)];
pc++;
@ -294,11 +293,28 @@ int dst_continue() {
}
continue;
case DOP_JUMP_IF_NOT:
if (dst_truthy(stack[oparg(1, 0xFF)])) {
pc++;
} else {
pc += (*(int32_t *)pc) >> 16;
}
continue;
case DOP_LESS_THAN:
stack[oparg(1, 0xFF)].type = DST_BOOLEAN;
stack[oparg(1, 0xFF)].as.boolean = dst_compare(
stack[oparg(2, 0xFF)],
stack[oparg(3, 0xFF)]
) < 0;
pc++;
continue;
case DOP_GREATER_THAN:
stack[oparg(1, 0xFF)].type = DST_BOOLEAN;
stack[oparg(1, 0xFF)].as.boolean = dst_compare(
stack[oparg(2, 0xFF)],
stack[oparg(3 ,0xFF)]
stack[oparg(3, 0xFF)]
) > 0;
pc++;
continue;
@ -307,7 +323,7 @@ int dst_continue() {
stack[oparg(1, 0xFF)].type = DST_BOOLEAN;
stack[oparg(1, 0xFF)].as.boolean = dst_equals(
stack[oparg(2, 0xFF)],
stack[oparg(3 ,0xFF)]
stack[oparg(3, 0xFF)]
);
pc++;
continue;
@ -316,7 +332,7 @@ int dst_continue() {
stack[oparg(1, 0xFF)].type = DST_INTEGER;
stack[oparg(1, 0xFF)].as.integer = dst_compare(
stack[oparg(2, 0xFF)],
stack[oparg(3 ,0xFF)]
stack[oparg(3, 0xFF)]
);
pc++;
continue;
@ -454,14 +470,13 @@ int dst_continue() {
break;
} else if (callee.type == DST_CFUNCTION) {
dst_fiber_cframe(dst_vm_fiber);
stack = dst_vm_fiber->data + dst_vm_fiber->frame;
dst_vm_fiber->ret.type = DST_NIL;
if (callee.as.cfunction(stack, dst_vm_fiber->frametop - dst_vm_fiber->frame)) {
dst_fiber_popframe(dst_vm_fiber);
if (callee.as.cfunction(
dst_vm_fiber->data + dst_vm_fiber->frame,
dst_vm_fiber->frametop - dst_vm_fiber->frame)) {
goto vm_error;
} else {
dst_fiber_popframe(dst_vm_fiber);
goto vm_return;
goto vm_return_cfunc;
}
} else {
vm_throw("cannot call non-function type");
@ -480,14 +495,13 @@ int dst_continue() {
break;
} else if (callee.type == DST_CFUNCTION) {
dst_fiber_cframe_tail(dst_vm_fiber);
stack = dst_vm_fiber->data + dst_vm_fiber->frame;
dst_vm_fiber->ret.type = DST_NIL;
if (callee.as.cfunction(stack, dst_vm_fiber->frametop - dst_vm_fiber->frame)) {
dst_fiber_popframe(dst_vm_fiber);
if (callee.as.cfunction(
dst_vm_fiber->data + dst_vm_fiber->frame,
dst_vm_fiber->frametop - dst_vm_fiber->frame)) {
goto vm_error;
} else {
dst_fiber_popframe(dst_vm_fiber);
goto vm_return;
goto vm_return_cfunc;
}
} else {
vm_throw("expected function");
@ -500,14 +514,12 @@ int dst_continue() {
DstCFunction f = dst_vm_syscalls[oparg(2, 0xFF)];
vm_assert(NULL != f, "invalid syscall");
dst_fiber_cframe(dst_vm_fiber);
stack = dst_vm_fiber->data + dst_vm_fiber->frame;
dst_vm_fiber->ret.type = DST_NIL;
if (f(stack, dst_vm_fiber->frametop - dst_vm_fiber->frame)) {
dst_fiber_popframe(dst_vm_fiber);
if (f(dst_vm_fiber->data + dst_vm_fiber->frame,
dst_vm_fiber->frametop - dst_vm_fiber->frame)) {
goto vm_error;
} else {
dst_fiber_popframe(dst_vm_fiber);
goto vm_return;
goto vm_return_cfunc;
}
continue;
}
@ -548,28 +560,66 @@ int dst_continue() {
continue;
}
case DOP_PUT:
{
const char *err = dst_try_put(
stack[oparg(1, 0xFF)],
stack[oparg(2, 0xFF)],
stack[oparg(3, 0xFF)]);
if (NULL != err) {
vm_throw(err);
}
++pc;
}
continue;
case DOP_PUT_INDEX:
dst_setindex(
stack[oparg(1, 0xFF)],
stack[oparg(3, 0xFF)],
oparg(3, 0xFF));
++pc;
continue;
case DOP_GET:
{
const char *err = dst_try_get(
stack[oparg(2, 0xFF)],
stack[oparg(3, 0xFF)],
stack + oparg(1, 0xFF));
if (NULL != err) {
vm_throw(err);
}
++pc;
}
continue;
case DOP_GET_INDEX:
stack[oparg(1, 0xFF)] = dst_getindex(
stack[oparg(2, 0xFF)],
oparg(3, 0xFF));
++pc;
continue;
/* Return from c function. Simpler than retuning from dst function */
vm_return_cfunc:
{
DstValue ret = dst_vm_fiber->ret;
dst_fiber_popframe(dst_vm_fiber);
if (dst_update_fiber())
return 0;
stack[oparg(1, 0xFF)] = ret;
pc++;
continue;
}
/* Handle returning from stack frame. Expect return value in fiber->ret */
vm_return:
{
DstValue ret = dst_vm_fiber->ret;
dst_fiber_popframe(dst_vm_fiber);
while (!dst_vm_fiber->frame ||
dst_vm_fiber->status == DST_FIBER_DEAD ||
dst_vm_fiber->status == DST_FIBER_ERROR) {
dst_vm_fiber->status = DST_FIBER_DEAD;
if (NULL != dst_vm_fiber->parent) {
dst_vm_fiber = dst_vm_fiber->parent;
if (dst_vm_fiber->status == DST_FIBER_ALIVE) {
/* If the parent thread is still alive,
we are inside a cfunction */
return 0;
}
stack = dst_vm_fiber->data + dst_vm_fiber->frame;
} else {
return 0;
}
}
dst_vm_fiber->status = DST_FIBER_ALIVE;
if (dst_update_fiber())
return 0;
stack = dst_vm_fiber->data + dst_vm_fiber->frame;
pc = dst_stack_frame(stack)->pc;
stack[oparg(1, 0xFF)] = ret;
@ -582,19 +632,8 @@ int dst_continue() {
{
DstValue ret = dst_vm_fiber->ret;
dst_vm_fiber->status = DST_FIBER_ERROR;
while (!dst_vm_fiber->frame ||
dst_vm_fiber->status == DST_FIBER_DEAD ||
dst_vm_fiber->status == DST_FIBER_ERROR) {
if (dst_vm_fiber->parent == NULL)
return 1;
dst_vm_fiber = dst_vm_fiber->parent;
if (dst_vm_fiber->status == DST_FIBER_ALIVE) {
/* If the parent thread is still alive,
we are inside a cfunction */
return 1;
}
}
dst_vm_fiber->status = DST_FIBER_ALIVE;
if (dst_update_fiber())
return 1;
stack = dst_vm_fiber->data + dst_vm_fiber->frame;
pc = dst_stack_frame(stack)->pc;
stack[oparg(1, 0xFF)] = ret;

0
dsts/compile.dsts Normal file
View File

View File

@ -51,7 +51,7 @@
# from their number
# Literal FuncEnvs and Functions may be possible later
constants [
"hello"
:hello
(def bork 123)
(def bip 456)
'(1 2 3)

24
dsts/minimal.dsts Normal file
View File

@ -0,0 +1,24 @@
{
bytecode [
(load-integer 0 10000)
(load-integer 1 0)
(load-constant 3 lookup)
:label
(equals 2 1 0)
(jump-if 2 :done)
(push 0)
(shift-right-immediate 0 0 1)
(syscall 2 0)
(get 2 3 0)
(push3 2 3 0)
(syscall 2 0)
(jump :label)
:done
(return-nil)
]
constants [
(def lookup "0123456789abcdef")
]
}

View File

@ -1,285 +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 "cache.h"
#include <dst/dst.h>
/* Get a value out af an associated data structure.
* Returns possible c error message, and NULL for no error. The
* useful return value is written to out on success */
const char *dst_value_get(DstValue ds, DstValue key, DstValue *out) {
int64_t index;
DstValue ret;
switch (ds.type) {
case DST_ARRAY:
if (key.type != DST_INTEGER) return "expected integer key";
index = dst_startrange(key.as.integer, ds.as.array->count);
if (index < 0) return "invalid array access";
ret = ds.as.array->data[index];
break;
case DST_TUPLE:
if (key.type != DST_INTEGER) return "expected integer key";
index = dst_startrange(key.as.integer, dst_tuple_length(ds.as.tuple));
if (index < 0) return "invalid tuple access";
ret = ds.as.tuple[index];
break;
case DST_BUFFER:
if (key.type != DST_INTEGER) return "expected integer key";
index = dst_startrange(key.as.integer, ds.as.buffer->count);
if (index < 0) return "invalid buffer access";
ret.type = DST_INTEGER;
ret.as.integer = ds.as.buffer->data[index];
break;
case DST_STRING:
case DST_SYMBOL:
if (key.type != DST_INTEGER) return "expected integer key";
index = dst_startrange(key.as.integer, dst_string_length(ds.as.string));
if (index < 0) return "invalid string access";
ret.type = DST_INTEGER;
ret.as.integer = ds.as.string[index];
break;
case DST_STRUCT:
ret = dst_struct_get(ds.as.st, key);
break;
case DST_TABLE:
ret = dst_table_get(ds.as.table, key);
break;
default:
return "cannot get";
}
*out = ret;
return NULL;
}
int dst_get(Dst *vm) {
DstValue ds = dst_popv(vm);
DstValue key = dst_popv(vm);
DstValue ret;
const char *err = dst_value_get(ds, key, &ret);
if (err) {
vm->flags = 1;
dst_cstring(vm, err);
} else {
dst_pushv(vm, ret);
}
}
/* Set a value in an associative data structure. Returns possible
* error message, and NULL if no error. */
const char *dst_value_set(Dst *vm, DstValue ds, DstValue key, DstValue value) {
int64_t index;
switch (ds.type) {
case DST_ARRAY:
if (key.type != DST_INTEGER) return "expected integer key";
index = dst_startrange(key.as.integer, ds.as.array->count);
if (index < 0) return "invalid array access";
ds.as.array->data[index] = value;
break;
case DST_BUFFER:
if (key.type != DST_INTEGER) return "expected integer key";
if (value.type != DST_INTEGER) return "expected integer value";
index = dst_startrange(key.as.integer, ds.as.buffer->count);
if (index < 0) return "invalid buffer access";
ds.as.buffer->data[index] = (uint8_t) value.as.integer;
break;
case DST_TABLE:
dst_table_put(vm, ds.as.table, key, value);
break;
default:
return "cannot set";
}
return NULL;
}
void dst_set(Dst *vm) {
DstValue ds = dst_popv(vm);
DstValue key = dst_popv(vm);
DstValue value = dst_popv(vm);
const char *err = dst_value_set(vm, ds, key, value);
if (err) {
vm->flags = 1;
vm->ret = dst_string_cv(vm, err);
}
}
/* Get the next key in an associative data structure. Used for iterating through an
* associative data structure. */
int dst_next(Dst *vm) {
DstValue dsv = dst_popv(vm);
DstValue keyv = dst_popv(vm);
DstValue ret = keyv;
switch(dsv.type) {
default:
dst_cerr(vm, "expected table or struct");
return 0;
case DST_TABLE:
ret = dst_table_next(dsv.as.table, keyv);
break;
case DST_STRUCT:
ret = dst_struct_next(dsv.as.st, keyv);
break;
}
dst_pushv(vm, ret);
return ret.type != DST_NIL;
}
/* Ensure capacity in a datastructure */
void dst_ensure(Dst *vm, int64_t index, uint32_t capacity) {
DstValue x = dst_getv(vm, index);
switch (x.type) {
default:
dst_cerr(vm, "could not ensure capacity");
break;
case DST_ARRAY:
dst_array_ensure_(vm, x.as.array, capacity);
break;
case DST_BUFFER:
dst_buffer_ensure_(vm, x.as.buffer, capacity);
break;
}
}
/* Get the length of an object. Returns errors for invalid types */
uint32_t dst_length(Dst *vm, int64_t index) {
DstValue x = dst_getv(vm, index);
uint32_t length;
switch (x.type) {
default:
dst_cerr(vm, "cannot get length");
return 0;
case DST_STRING:
length = dst_string_length(x.as.string);
break;
case DST_ARRAY:
length = x.as.array->count;
break;
case DST_BUFFER:
length = x.as.buffer->count;
break;
case DST_TUPLE:
length = dst_tuple_length(x.as.tuple);
break;
case DST_STRUCT:
length = dst_struct_length(x.as.st);
break;
case DST_TABLE:
length = x.as.table->count;
break;
}
return length;
}
/* Get the capacity of an object. Returns errors for invalid types */
uint32_t dst_capacity(Dst *vm, int64_t index) {
DstValue x = dst_getv(vm, index);
uint32_t cap;
switch (x.type) {
default:
dst_cerr(vm, "cannot get capacity");
return 0;
case DST_STRING:
cap = dst_string_length(x.as.string);
break;
case DST_ARRAY:
cap = x.as.array->capacity;
break;
case DST_BUFFER:
cap = x.as.buffer->capacity;
break;
case DST_TUPLE:
cap = dst_tuple_length(x.as.tuple);
break;
case DST_STRUCT:
cap = dst_struct_length(x.as.st);
break;
case DST_TABLE:
cap = x.as.table->capacity;
break;
}
return cap;
}
/* Sequence functions */
const char *dst_getindex_value(DstValue ds, uint32_t index, DstValue *out) {
switch (ds.type) {
default:
return "expected sequence type";
case DST_STRING:
if (index >= dst_string_length(ds.as.string)) return "index out of bounds";
*out = dst_wrap_integer(ds.as.string[index]);
break;
case DST_ARRAY:
if (index >= ds.as.array->count) return "index out of bounds";
*out = ds.as.array->data[index];
break;
case DST_BUFFER:
if (index >= ds.as.buffer->count) return "index out of bounds";
*out = dst_wrap_integer(ds.as.buffer->data[index]);
break;
case DST_TUPLE:
if (index >= dst_tuple_length(ds.as.tuple)) return "index out of bounds";
*out = ds.as.tuple[index];
break;
}
return NULL;
}
void dst_getindex(Dst *vm, uint32_t index) {
DstValue out;
DstValue ds = dst_popv(vm);
const char *e = dst_getindex_value(ds, index, &out);
if (e == NULL) {
dst_pushv(vm, out);
} else {
dst_cstring(vm, e);
vm->flags = 1;
}
}
const char *dst_setindex_value(Dst *vm, DstValue ds, uint32_t index, DstValue value) {
switch (ds.type) {
default:
return "expected mutable sequence type";
case DST_ARRAY:
if (index >= ds.as.array->count) {
dst_array_ensure_(vm, ds.as.array, index + 1);
}
ds.as.array->data[index] = value;
break;
case DST_BUFFER:
if (value.type != DST_INTEGER) return "expected integer type";
if (index >= ds.as.buffer->count) {
dst_buffer_ensure_(vm, ds.as.buffer, index + 1);
}
ds.as.buffer->data[index] = value.as.integer;
break;
}
return NULL;
}
void dst_setindex(Dst *vm, uint32_t index) {
DstValue ds = dst_popv(vm);
DstValue value = dst_popv(vm);
const char *e = dst_setindex_value(vm, ds, index, value);
if (e != NULL) {
dst_cstring(vm, e);
vm->flags = 1;
}
}

View File

@ -7,7 +7,7 @@ int main() {
DstAssembleResult ares;
DstFunction *func;
FILE *f = fopen("./unittests/sample.dsts", "rb");
FILE *f = fopen("./dsts/minimal.dsts", "rb");
fseek(f, 0, SEEK_END);
long fsize = ftell(f);
fseek(f, 0, SEEK_SET); //same as rewind(f);