mirror of
https://github.com/janet-lang/janet
synced 2024-11-24 17:27:18 +00:00
Work on interpreter. adding more opcodes and syscalls.
This commit is contained in:
parent
6ca6949c2d
commit
412d40d09f
1
contrib/vim/ftdetect/dst.vim
Normal file
1
contrib/vim/ftdetect/dst.vim
Normal file
@ -0,0 +1 @@
|
||||
autocmd BufRead,BufNewFile *.dst,*.dsts setlocal filetype=dst
|
25
contrib/vim/ftplugin/dst.vim
Normal file
25
contrib/vim/ftplugin/dst.vim
Normal 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
|
17
contrib/vim/indent/dst.vim
Normal file
17
contrib/vim/indent/dst.vim
Normal 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
|
69
contrib/vim/syntax/dst.vim
Normal file
69
contrib/vim/syntax/dst.vim
Normal 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
|
57
core/asm.c
57
core/asm.c
@ -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++;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
};
|
||||
|
@ -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]);
|
||||
|
11
core/util.c
11
core/util.c
@ -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);
|
||||
}
|
||||
|
179
core/value.c
179
core/value.c
@ -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
199
core/vm.c
@ -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
0
dsts/compile.dsts
Normal 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
24
dsts/minimal.dsts
Normal 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")
|
||||
]
|
||||
}
|
285
junkyard/ds.c
285
junkyard/ds.c
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user