mirror of
https://github.com/janet-lang/janet
synced 2024-12-29 09:50:27 +00:00
Redo parser as a FSM. Again.
This commit is contained in:
parent
8e6ed707e7
commit
0531866954
4
Makefile
4
Makefile
@ -32,7 +32,7 @@ PREFIX=/usr/local
|
||||
DST_TARGET=dst
|
||||
DEBUGGER=lldb
|
||||
DST_INTERNAL_HEADERS=$(addprefix core/,symcache.h opcodes.h compile.h gc.h util.h)
|
||||
DST_HEADERS=$(addprefix include/dst/,dst.h dstconfig.h dsttypes.h dststate.h dststl.h)
|
||||
DST_HEADERS=$(addprefix include/dst/,dst.h dstconfig.h dstcontext.h dsttypes.h dststate.h dststl.h)
|
||||
DST_C_LIBS=$(addprefix libs/,testlib.so)
|
||||
|
||||
#############################
|
||||
@ -81,7 +81,7 @@ valgrind: $(DST_TARGET)
|
||||
@ valgrind --leak-check=full -v ./$(DST_TARGET)
|
||||
|
||||
test: $(DST_TARGET)
|
||||
@ ./$(DST_TARGET) --gcinterval=0 dsttest/suite0.dst
|
||||
@ ./$(DST_TARGET) --gcinterval=0x10000 dsttest/suite0.dst
|
||||
|
||||
valtest: $(DST_TARGET)
|
||||
valgrind --leak-check=full -v ./$(DST_TARGET) dsttests/basic.dst
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <dst/dst.h>
|
||||
#include <dst/dstcontext.h>
|
||||
|
||||
#define DST_CLIENT_HELP 1
|
||||
#define DST_CLIENT_VERBOSE 2
|
||||
@ -30,8 +31,6 @@
|
||||
#define DST_CLIENT_REPL 8
|
||||
#define DST_CLIENT_UNKNOWN 16
|
||||
|
||||
static Dst env;
|
||||
|
||||
static int client_strequal(const char *a, const char *b) {
|
||||
while (*a) if (*a++ != *b++) return 0;
|
||||
return *a == *b;
|
||||
@ -42,78 +41,13 @@ static int client_strequal_witharg(const char *a, const char *b) {
|
||||
return *a == '=';
|
||||
}
|
||||
|
||||
/* Load source from a file */
|
||||
static const uint8_t *loadsource(const char *fpath, int32_t *len) {
|
||||
FILE *f = fopen(fpath, "rb");
|
||||
long fsize;
|
||||
size_t fsizet;
|
||||
uint8_t *source = NULL;
|
||||
if (fseek(f, 0, SEEK_END)) goto error;
|
||||
fsize = ftell(f);
|
||||
if (fsize > INT32_MAX || fsize < 0) goto error;
|
||||
fsizet = fsize;
|
||||
if (fseek(f, 0, SEEK_SET)) goto error;
|
||||
if (!fsize) goto error;
|
||||
source = malloc(fsize);
|
||||
if (fread(source, 1, fsize, f) != fsizet) goto error;
|
||||
if (fclose(f)) goto error;
|
||||
*len = (int32_t) fsizet;
|
||||
return source;
|
||||
|
||||
error:
|
||||
free(source);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Run file */
|
||||
static void runfile(const uint8_t *src, int32_t len) {
|
||||
DstCompileOptions opts;
|
||||
DstCompileResult cres;
|
||||
DstParseResult res;
|
||||
const uint8_t *s = src;
|
||||
const uint8_t *end = src + len;
|
||||
while (s < end) {
|
||||
res = dst_parse(s, end - s, DST_PARSEFLAG_SOURCEMAP);
|
||||
switch (res.status) {
|
||||
case DST_PARSE_NODATA:
|
||||
return;
|
||||
case DST_PARSE_UNEXPECTED_EOS:
|
||||
case DST_PARSE_ERROR:
|
||||
dst_puts(dst_formatc("syntax error at %d: %S\n",
|
||||
s - src + res.bytes_read + 1, res.error));
|
||||
if (res.bytes_read == 0) {
|
||||
s++;
|
||||
}
|
||||
break;
|
||||
case DST_PARSE_OK:
|
||||
{
|
||||
opts.source = res.value;
|
||||
opts.flags = 0;
|
||||
opts.env = env;
|
||||
cres = dst_compile(opts);
|
||||
if (cres.status == DST_COMPILE_OK) {
|
||||
Dst ret = dst_wrap_nil();
|
||||
DstFunction *f = dst_compile_func(cres);
|
||||
if (dst_run(dst_wrap_function(f), &ret)) {
|
||||
dst_puts(dst_formatc("runtime error: %v\n", ret));
|
||||
}
|
||||
} else {
|
||||
dst_puts(dst_formatc("compile error at %d: %S\n",
|
||||
s - src + cres.error_start + 1, cres.error));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
s += res.bytes_read;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int status = 0;
|
||||
int i;
|
||||
int fileRead = 0;
|
||||
uint32_t gcinterval = 0x10000;
|
||||
uint64_t flags = 0;
|
||||
DstTable *env;
|
||||
|
||||
/* Read the arguments. Ignore files. */
|
||||
for (i = 1; i < argc; ++i) {
|
||||
@ -192,20 +126,19 @@ int main(int argc, char **argv) {
|
||||
dst_init();
|
||||
dst_vm_gc_interval = gcinterval;
|
||||
env = dst_stl_env();
|
||||
dst_gcroot(env);
|
||||
dst_gcroot(dst_wrap_table(env));
|
||||
|
||||
/* Read the arguments. Only process files. */
|
||||
for (i = 1; i < argc; ++i) {
|
||||
const char *arg = argv[i];
|
||||
if (*arg != '-') {
|
||||
DstContext ctxt;
|
||||
fileRead = 1;
|
||||
int32_t len;
|
||||
const uint8_t *s = loadsource(arg, &len);
|
||||
if (NULL == s) {
|
||||
printf("could not load file %s\n", arg);
|
||||
} else {
|
||||
runfile(s, len);
|
||||
if (dst_context_file(&ctxt, env, arg)) {
|
||||
printf("file %s not found\n", arg);
|
||||
continue;
|
||||
}
|
||||
status = dst_context_run(&ctxt, DST_PARSEFLAG_SOURCEMAP);
|
||||
}
|
||||
}
|
||||
|
||||
@ -213,7 +146,7 @@ int main(int argc, char **argv) {
|
||||
if (!fileRead || (flags & DST_CLIENT_REPL)) {
|
||||
DstContext ctxt;
|
||||
dst_context_repl(&ctxt, env);
|
||||
status = dst_context_run(&ctxt);
|
||||
status = dst_context_run(&ctxt, DST_PARSEFLAG_SOURCEMAP);
|
||||
}
|
||||
|
||||
dst_deinit();
|
||||
|
55
core/array.c
55
core/array.c
@ -102,3 +102,58 @@ Dst dst_array_peek(DstArray *array) {
|
||||
return dst_wrap_nil();
|
||||
}
|
||||
}
|
||||
|
||||
/* C Functions */
|
||||
|
||||
static int cfun_pop(DstArgs args) {
|
||||
if (args.n != 1 || !dst_checktype(args.v[0], DST_ARRAY)) return dst_throw(args, "expected array");
|
||||
return dst_return(args, dst_array_pop(dst_unwrap_array(args.v[0])));
|
||||
}
|
||||
|
||||
static int cfun_peek(DstArgs args) {
|
||||
if (args.n != 1 || !dst_checktype(args.v[0], DST_ARRAY)) return dst_throw(args, "expected array");
|
||||
return dst_return(args, dst_array_peek(dst_unwrap_array(args.v[0])));
|
||||
}
|
||||
|
||||
static int cfun_push(DstArgs args) {
|
||||
DstArray *array;
|
||||
int32_t newcount;
|
||||
if (args.n < 1 || !dst_checktype(args.v[0], DST_ARRAY)) return dst_throw(args, "expected array");
|
||||
array = dst_unwrap_array(args.v[0]);
|
||||
newcount = array->count - 1 + args.n;
|
||||
dst_array_ensure(array, newcount);
|
||||
if (args.n > 1) memcpy(array->data + array->count, args.v + 1, (args.n - 1) * sizeof(Dst));
|
||||
array->count = newcount;
|
||||
return dst_return(args, args.v[0]);
|
||||
}
|
||||
|
||||
static int cfun_setcount(DstArgs args) {
|
||||
int32_t newcount;
|
||||
if (args.n != 2 || !dst_checktype(args.v[0], DST_ARRAY)) return dst_throw(args, "expected array");
|
||||
if (!dst_checktype(args.v[1], DST_INTEGER)) return dst_throw(args, "expected positive integer");
|
||||
newcount = dst_unwrap_integer(args.v[1]);
|
||||
if (newcount < 0) return dst_throw(args, "expected positive integer");
|
||||
dst_array_setcount(dst_unwrap_array(args.v[0]), newcount);
|
||||
return dst_return(args, args.v[0]);
|
||||
}
|
||||
|
||||
static int cfun_ensure(DstArgs args) {
|
||||
int32_t newcount;
|
||||
if (args.n != 2 || !dst_checktype(args.v[0], DST_ARRAY)) return dst_throw(args, "expected array");
|
||||
if (!dst_checktype(args.v[1], DST_INTEGER)) return dst_throw(args, "expected positive integer");
|
||||
newcount = dst_unwrap_integer(args.v[1]);
|
||||
if (newcount < 0) return dst_throw(args, "expected positive integer");
|
||||
dst_array_ensure(dst_unwrap_array(args.v[0]), newcount);
|
||||
return dst_return(args, args.v[0]);
|
||||
}
|
||||
|
||||
/* Load the array module */
|
||||
int dst_lib_array(DstArgs args) {
|
||||
DstTable *env = dst_env_arg(args);
|
||||
dst_env_def(env, "array-pop", dst_wrap_cfunction(cfun_pop));
|
||||
dst_env_def(env, "array-peek", dst_wrap_cfunction(cfun_peek));
|
||||
dst_env_def(env, "array-push", dst_wrap_cfunction(cfun_push));
|
||||
dst_env_def(env, "array-setcount", dst_wrap_cfunction(cfun_setcount));
|
||||
dst_env_def(env, "array-ensure", dst_wrap_cfunction(cfun_ensure));
|
||||
return 0;
|
||||
}
|
||||
|
19
core/asm.c
19
core/asm.c
@ -481,14 +481,15 @@ static uint32_t read_instruction(
|
||||
}
|
||||
|
||||
/* Helper to assembly. Return the assembly result */
|
||||
static DstAssembleResult dst_asm1(DstAssembler *parent, DstAssembleOptions opts) {
|
||||
static DstAssembleResult dst_asm1(DstAssembler *parent, Dst source, int flags) {
|
||||
DstAssembleResult result;
|
||||
DstAssembler a;
|
||||
Dst s = opts.source;
|
||||
Dst s = source;
|
||||
DstFuncDef *def;
|
||||
int32_t count, i;
|
||||
const Dst *arr;
|
||||
Dst x;
|
||||
(void) flags;
|
||||
|
||||
/* Initialize funcdef */
|
||||
def = dst_gcalloc(DST_MEMORY_FUNCDEF, sizeof(DstFuncDef));
|
||||
@ -619,12 +620,9 @@ static DstAssembleResult dst_asm1(DstAssembler *parent, DstAssembleOptions opts)
|
||||
int32_t i;
|
||||
for (i = 0; i < count; i++) {
|
||||
DstAssembleResult subres;
|
||||
DstAssembleOptions subopts;
|
||||
Dst subname;
|
||||
int32_t newlen;
|
||||
subopts.source = arr[i];
|
||||
subopts.flags = opts.flags;
|
||||
subres = dst_asm1(&a, subopts);
|
||||
subres = dst_asm1(&a, arr[i], flags);
|
||||
if (subres.status != DST_ASSEMBLE_OK) {
|
||||
dst_asm_errorv(&a, subres.error);
|
||||
}
|
||||
@ -730,8 +728,8 @@ static DstAssembleResult dst_asm1(DstAssembler *parent, DstAssembleOptions opts)
|
||||
}
|
||||
|
||||
/* Assemble a function */
|
||||
DstAssembleResult dst_asm(DstAssembleOptions opts) {
|
||||
return dst_asm1(NULL, opts);
|
||||
DstAssembleResult dst_asm(Dst source, int flags) {
|
||||
return dst_asm1(NULL, source, flags);
|
||||
}
|
||||
|
||||
/* Build a function from the result */
|
||||
@ -915,12 +913,9 @@ Dst dst_disasm(DstFuncDef *def) {
|
||||
|
||||
/* C Function for assembly */
|
||||
int dst_asm_cfun(DstArgs args) {
|
||||
DstAssembleOptions opts;
|
||||
DstAssembleResult res;
|
||||
if (args.n < 1) return dst_throw(args, "expected assembly source");
|
||||
opts.source = args.v[0];
|
||||
opts.flags = 0;
|
||||
res = dst_asm(opts);
|
||||
res = dst_asm(args.v[0], 0);
|
||||
if (res.status == DST_ASSEMBLE_OK) {
|
||||
return dst_return(args, dst_wrap_function(dst_asm_func(res)));
|
||||
} else {
|
||||
|
@ -139,3 +139,50 @@ int dst_buffer_push_u64(DstBuffer *buffer, uint64_t x) {
|
||||
buffer->count += 8;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* C functions */
|
||||
static int cfun_u8(DstArgs args) {
|
||||
int32_t i;
|
||||
DstBuffer *buffer;
|
||||
if (args.n < 1 || !dst_checktype(args.v[0], DST_BUFFER)) return dst_throw(args, "expected buffer");
|
||||
buffer = dst_unwrap_buffer(args.v[0]);
|
||||
for (i = 1; i < args.n; i++) {
|
||||
if (!dst_checktype(args.v[i], DST_INTEGER)) return dst_throw(args, "expected integer");
|
||||
if (dst_buffer_push_u8(buffer, (uint8_t) (dst_unwrap_integer(args.v[i]) & 0xFF))) return dst_throw(args, "buffer overflow");
|
||||
}
|
||||
return dst_return(args, args.v[0]);
|
||||
}
|
||||
|
||||
static int cfun_int(DstArgs args) {
|
||||
int32_t i;
|
||||
DstBuffer *buffer;
|
||||
if (args.n < 1 || !dst_checktype(args.v[0], DST_BUFFER)) return dst_throw(args, "expected buffer");
|
||||
buffer = dst_unwrap_buffer(args.v[0]);
|
||||
for (i = 1; i < args.n; i++) {
|
||||
if (!dst_checktype(args.v[i], DST_INTEGER)) return dst_throw(args, "expected integer");
|
||||
if (dst_buffer_push_u32(buffer, (uint32_t) dst_unwrap_integer(args.v[i]))) return dst_throw(args, "buffer overflow");
|
||||
}
|
||||
return dst_return(args, args.v[0]);
|
||||
}
|
||||
|
||||
static int cfun_chars(DstArgs args) {
|
||||
int32_t i;
|
||||
DstBuffer *buffer;
|
||||
if (args.n < 1 || !dst_checktype(args.v[0], DST_BUFFER)) return dst_throw(args, "expected buffer");
|
||||
buffer = dst_unwrap_buffer(args.v[0]);
|
||||
for (i = 1; i < args.n; i++) {
|
||||
int32_t len;
|
||||
const uint8_t *str;
|
||||
if (!dst_chararray_view(args.v[i], &str, &len)) return dst_throw(args, "expected string/buffer");
|
||||
if (dst_buffer_push_bytes(buffer, str, len)) return dst_throw(args, "buffer overflow");
|
||||
}
|
||||
return dst_return(args, args.v[0]);
|
||||
}
|
||||
|
||||
int dst_lib_buffer(DstArgs args) {
|
||||
DstTable *env = dst_env_arg(args);
|
||||
dst_env_def(env, "buffer-push-byte", dst_wrap_cfunction(cfun_u8));
|
||||
dst_env_def(env, "buffer-push-integer", dst_wrap_cfunction(cfun_int));
|
||||
dst_env_def(env, "buffer-push-string", dst_wrap_cfunction(cfun_chars));
|
||||
return 0;
|
||||
}
|
||||
|
@ -235,7 +235,7 @@ DstSlot dstc_resolve(
|
||||
|
||||
/* Symbol not found - check for global */
|
||||
{
|
||||
Dst check = dst_get(c->env, dst_wrap_symbol(sym));
|
||||
Dst check = dst_table_get(c->env, dst_wrap_symbol(sym));
|
||||
Dst ref;
|
||||
if (!(dst_checktype(check, DST_STRUCT) || dst_checktype(check, DST_TABLE))) {
|
||||
dstc_error(c, ast, dst_formatc("unknown symbol %q", sym));
|
||||
@ -846,7 +846,7 @@ DstFuncDef *dstc_pop_funcdef(DstCompiler *c) {
|
||||
|
||||
|
||||
/* Initialize a compiler */
|
||||
static void dstc_init(DstCompiler *c, Dst env) {
|
||||
static void dstc_init(DstCompiler *c, DstTable *env) {
|
||||
c->scopes = NULL;
|
||||
c->buffer = NULL;
|
||||
c->mapbuffer = NULL;
|
||||
@ -866,15 +866,16 @@ static void dstc_deinit(DstCompiler *c) {
|
||||
dst_v_free(c->scopes);
|
||||
dst_v_free(c->buffer);
|
||||
dst_v_free(c->mapbuffer);
|
||||
c->env = dst_wrap_nil();
|
||||
c->env = NULL;
|
||||
}
|
||||
|
||||
/* Compile a form. */
|
||||
DstCompileResult dst_compile(DstCompileOptions opts) {
|
||||
DstCompileResult dst_compile(Dst source, DstTable *env, int flags) {
|
||||
DstCompiler c;
|
||||
DstFopts fopts;
|
||||
(void) flags;
|
||||
|
||||
dstc_init(&c, opts.env);
|
||||
dstc_init(&c, env);
|
||||
|
||||
/* Push a function scope */
|
||||
dstc_scope(&c, DST_SCOPE_FUNCTION | DST_SCOPE_TOP);
|
||||
@ -885,7 +886,7 @@ DstCompileResult dst_compile(DstCompileOptions opts) {
|
||||
fopts.hint = dstc_cslot(dst_wrap_nil());
|
||||
|
||||
/* Compile the value */
|
||||
dstc_value(fopts, opts.source);
|
||||
dstc_value(fopts, source);
|
||||
|
||||
if (c.result.status == DST_COMPILE_OK) {
|
||||
c.result.funcdef = dstc_pop_funcdef(&c);
|
||||
@ -916,15 +917,18 @@ DstFunction *dst_compile_func(DstCompileResult res) {
|
||||
|
||||
/* C Function for compiling */
|
||||
int dst_compile_cfun(DstArgs args) {
|
||||
DstCompileOptions opts;
|
||||
DstCompileResult res;
|
||||
DstTable *t;
|
||||
DstTable *env;
|
||||
if (args.n < 1)
|
||||
return dst_throw(args, "expected at least one argument");
|
||||
opts.source = args.v[0];
|
||||
opts.env = args.n >= 2 ? args.v[1] : dst_stl_env();
|
||||
opts.flags = 0;
|
||||
res = dst_compile(opts);
|
||||
if (args.n >= 2) {
|
||||
if (!dst_checktype(args.v[1], DST_TABLE)) return dst_throw(args, "expected table as environment");
|
||||
env = dst_unwrap_table(args.v[1]);
|
||||
} else {
|
||||
env = dst_stl_env();
|
||||
}
|
||||
res = dst_compile(args.v[0], env, 0);
|
||||
if (res.status == DST_COMPILE_OK) {
|
||||
DstFunction *fun = dst_compile_func(res);
|
||||
return dst_return(args, dst_wrap_function(fun));
|
||||
|
@ -104,7 +104,7 @@ struct DstCompiler {
|
||||
int32_t *mapbuffer;
|
||||
|
||||
/* Hold the environment */
|
||||
Dst env;
|
||||
DstTable *env;
|
||||
|
||||
DstCompileResult result;
|
||||
};
|
||||
|
@ -103,7 +103,7 @@ DstSlot dstc_var(DstFopts opts, DstAst *ast, int32_t argn, const Dst *argv) {
|
||||
dst_array_push(ref, dst_wrap_nil());
|
||||
dst_table_put(reftab, dst_csymbolv("ref"), dst_wrap_array(ref));
|
||||
handleattr(c, argn, argv, reftab);
|
||||
dst_put(c->env, head, dst_wrap_table(reftab));
|
||||
dst_table_put(c->env, head, dst_wrap_table(reftab));
|
||||
refslot = dstc_cslot(dst_wrap_array(ref));
|
||||
refarrayslot = refslot;
|
||||
refslot.flags |= DST_SLOT_REF | DST_SLOT_NAMED | DST_SLOT_MUTABLE;
|
||||
@ -163,7 +163,7 @@ DstSlot dstc_def(DstFopts opts, DstAst *ast, int32_t argn, const Dst *argv) {
|
||||
|
||||
/* Add env entry to env */
|
||||
handleattr(c, argn, argv, tab);
|
||||
dst_put(c->env, head, dst_wrap_table(tab));
|
||||
dst_table_put(c->env, head, dst_wrap_table(tab));
|
||||
|
||||
/* Put value in table when evaulated */
|
||||
tableindex = dstc_preread(c, ast, 0xFF, 1, tabslot);
|
||||
|
189
core/context.c
189
core/context.c
@ -21,14 +21,12 @@
|
||||
*/
|
||||
|
||||
#include <dst/dst.h>
|
||||
#include <dst/dstcontext.h>
|
||||
|
||||
/*static void deinit_file(DstContext *c) {*/
|
||||
/*FILE *f = (FILE *) (c->user);*/
|
||||
/*fclose(f);*/
|
||||
/*}*/
|
||||
#define CHUNKSIZE 1024
|
||||
|
||||
/* Read input for a repl */
|
||||
static void replread(DstContext *c) {
|
||||
static int replread(DstContext *c) {
|
||||
if (c->buffer.count == 0)
|
||||
printf("> ");
|
||||
else
|
||||
@ -43,18 +41,18 @@ static void replread(DstContext *c) {
|
||||
dst_buffer_push_u8(&c->buffer, x);
|
||||
if (x == '\n') break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Output for a repl */
|
||||
static void replonvalue(DstContext *c, Dst value) {
|
||||
(void) c;
|
||||
dst_puts(dst_formatc("%v\n", value));
|
||||
if (dst_checktype(c->env, DST_TABLE))
|
||||
dst_module_def(dst_unwrap_table(c->env), "_", value);
|
||||
dst_env_def(c->env, "_", value);
|
||||
}
|
||||
|
||||
/* Handle errors on repl */
|
||||
static void replerror(DstContext *c, DstContextErrorType type, Dst err, size_t start, size_t end) {
|
||||
static void simpleerror(DstContext *c, DstContextErrorType type, Dst err, size_t start, size_t end) {
|
||||
const char *errtype;
|
||||
(void) c;
|
||||
(void) start;
|
||||
@ -70,49 +68,63 @@ static void replerror(DstContext *c, DstContextErrorType type, Dst err, size_t s
|
||||
errtype = "compile";
|
||||
break;
|
||||
}
|
||||
dst_puts(dst_formatc("%s error: %v\n", errtype, err));
|
||||
dst_puts(dst_formatc("%s error: %s\n", errtype, dst_to_string(err)));
|
||||
}
|
||||
|
||||
void dst_context_init(DstContext *c, Dst env) {
|
||||
dst_buffer_init(&c->buffer, 1024);
|
||||
static void filedeinit(DstContext *c) {
|
||||
fclose((FILE *) (c->user));
|
||||
}
|
||||
|
||||
static int fileread(DstContext *c) {
|
||||
size_t nread;
|
||||
FILE *f = (FILE *) c->user;
|
||||
dst_buffer_ensure(&c->buffer, CHUNKSIZE);
|
||||
nread = fread(c->buffer.data, 1, CHUNKSIZE, f);
|
||||
if (nread != CHUNKSIZE && ferror(f)) {
|
||||
return -1;
|
||||
}
|
||||
c->buffer.count = (int32_t) nread;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dst_context_init(DstContext *c, DstTable *env) {
|
||||
dst_buffer_init(&c->buffer, CHUNKSIZE);
|
||||
c->env = env;
|
||||
dst_gcroot(env);
|
||||
c->flushed_bytes = 0;
|
||||
dst_gcroot(dst_wrap_table(env));
|
||||
c->index = 0;
|
||||
c->read_chunk = NULL;
|
||||
c->on_error = NULL;
|
||||
c->on_value = NULL;
|
||||
c->deinit = NULL;
|
||||
}
|
||||
|
||||
void dst_context_deinit(DstContext *c) {
|
||||
dst_buffer_deinit(&c->buffer);
|
||||
if (c->deinit) c->deinit(c);
|
||||
dst_gcunroot(c->env);
|
||||
dst_gcunroot(dst_wrap_table(c->env));
|
||||
}
|
||||
|
||||
void dst_context_repl(DstContext *c, Dst env) {
|
||||
dst_buffer_init(&c->buffer, 1024);
|
||||
c->env = env;
|
||||
dst_gcroot(env);
|
||||
c->flushed_bytes = 0;
|
||||
int dst_context_repl(DstContext *c, DstTable *env) {
|
||||
dst_context_init(c, env);
|
||||
c->user = NULL;
|
||||
if (dst_checktype(c->env, DST_TABLE))
|
||||
dst_module_def(dst_unwrap_table(c->env), "_", dst_wrap_nil());
|
||||
dst_env_def(c->env, "_", dst_wrap_nil());
|
||||
c->read_chunk = replread;
|
||||
c->on_error = replerror;
|
||||
c->on_error = simpleerror;
|
||||
c->on_value = replonvalue;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Remove everything in the current buffer */
|
||||
static void flushcontext(DstContext *c) {
|
||||
c->flushed_bytes += c->buffer.count;
|
||||
c->buffer.count = 0;
|
||||
}
|
||||
|
||||
/* Shift bytes in buffer down */
|
||||
/* TODO Make parser online so there is no need to
|
||||
* do too much book keeping with the buffer. */
|
||||
static void bshift(DstContext *c, int32_t delta) {
|
||||
c->buffer.count -= delta;
|
||||
if (delta) {
|
||||
memmove(c->buffer.data, c->buffer.data + delta, c->buffer.count);
|
||||
int dst_context_file(DstContext *c, DstTable *env, const char *path) {
|
||||
FILE *f = fopen(path, "r");
|
||||
if (!f) {
|
||||
return -1;
|
||||
}
|
||||
dst_context_init(c, env);
|
||||
c->user = f;
|
||||
c->read_chunk = fileread;
|
||||
c->on_error = simpleerror;
|
||||
c->deinit = filedeinit;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Do something on an error. Return flags to or with current flags. */
|
||||
@ -125,72 +137,69 @@ static int doerror(
|
||||
if (c->on_error) {
|
||||
c->on_error(c, type,
|
||||
err,
|
||||
c->flushed_bytes + bstart,
|
||||
c->flushed_bytes + bend);
|
||||
bstart,
|
||||
bend);
|
||||
}
|
||||
return 1 << type;
|
||||
}
|
||||
|
||||
/* Start a context */
|
||||
int dst_context_run(DstContext *c) {
|
||||
int dst_context_run(DstContext *c, int flags) {
|
||||
int done = 0;
|
||||
int flags = 0;
|
||||
int errflags = 0;
|
||||
DstParser parser;
|
||||
dst_parser_init(&parser, flags);
|
||||
while (!done) {
|
||||
DstCompileResult cres;
|
||||
DstCompileOptions opts;
|
||||
DstParseResult res = dst_parse(c->buffer.data, c->buffer.count, DST_PARSEFLAG_SOURCEMAP);
|
||||
switch (res.status) {
|
||||
case DST_PARSE_NODATA:
|
||||
flushcontext(c);
|
||||
case DST_PARSE_UNEXPECTED_EOS:
|
||||
{
|
||||
int32_t countbefore = c->buffer.count;
|
||||
c->read_chunk(c);
|
||||
/* If the last chunk was empty, finish */
|
||||
if (c->buffer.count == countbefore) {
|
||||
done = 1;
|
||||
flags |= doerror(c, DST_CONTEXT_ERROR_PARSE,
|
||||
dst_cstringv("unexpected end of source"),
|
||||
res.bytes_read,
|
||||
res.bytes_read);
|
||||
int bufferdone = 0;
|
||||
while (!bufferdone) {
|
||||
DstParserStatus status = dst_parser_status(&parser);
|
||||
switch (status) {
|
||||
case DST_PARSE_FULL:
|
||||
{
|
||||
DstCompileResult cres = dst_compile(dst_parser_produce(&parser), c->env, flags);
|
||||
if (cres.status == DST_COMPILE_OK) {
|
||||
DstFunction *f = dst_compile_func(cres);
|
||||
Dst ret;
|
||||
if (dst_run(dst_wrap_function(f), &ret)) {
|
||||
/* Get location from stacktrace? */
|
||||
errflags |= doerror(c, DST_CONTEXT_ERROR_RUNTIME, ret, -1, -1);
|
||||
} else {
|
||||
if (c->on_value) {
|
||||
c->on_value(c, ret);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
errflags |= doerror(c, DST_CONTEXT_ERROR_COMPILE,
|
||||
dst_wrap_string(cres.error),
|
||||
cres.error_start,
|
||||
cres.error_end);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DST_PARSE_ERROR:
|
||||
flags |= doerror(c, DST_CONTEXT_ERROR_PARSE,
|
||||
dst_wrap_string(res.error),
|
||||
res.bytes_read,
|
||||
res.bytes_read);
|
||||
bshift(c, res.bytes_read);
|
||||
break;
|
||||
case DST_PARSE_OK:
|
||||
{
|
||||
opts.source = res.value;
|
||||
opts.flags = 0;
|
||||
opts.env = c->env;
|
||||
cres = dst_compile(opts);
|
||||
if (cres.status == DST_COMPILE_OK) {
|
||||
DstFunction *f = dst_compile_func(cres);
|
||||
Dst ret;
|
||||
if (dst_run(dst_wrap_function(f), &ret)) {
|
||||
/* Get location from stacktrace? */
|
||||
flags |= doerror(c, DST_CONTEXT_ERROR_RUNTIME, ret, -1, -1);
|
||||
} else {
|
||||
if (c->on_value) {
|
||||
c->on_value(c, ret);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
flags |= doerror(c, DST_CONTEXT_ERROR_COMPILE,
|
||||
dst_wrap_string(cres.error),
|
||||
cres.error_start,
|
||||
cres.error_end);
|
||||
case DST_PARSE_ERROR:
|
||||
doerror(c, DST_CONTEXT_ERROR_PARSE,
|
||||
dst_cstringv(dst_parser_error(&parser)),
|
||||
parser.index,
|
||||
parser.index);
|
||||
break;
|
||||
case DST_PARSE_PENDING:
|
||||
case DST_PARSE_ROOT:
|
||||
if (c->index >= c->buffer.count) {
|
||||
bufferdone = 1;
|
||||
break;
|
||||
}
|
||||
bshift(c, res.bytes_read);
|
||||
}
|
||||
break;
|
||||
dst_parser_consume(&parser, c->buffer.data[c->index++]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Refill the buffer */
|
||||
c->buffer.count = 0;
|
||||
c->index = 0;
|
||||
if (c->read_chunk(c) || c->buffer.count == 0) {
|
||||
done = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return flags;
|
||||
dst_parser_deinit(&parser);
|
||||
return errflags;
|
||||
}
|
||||
|
22
core/io.c
22
core/io.c
@ -227,28 +227,28 @@ static int dst_io_fclose(DstArgs args) {
|
||||
|
||||
/* Define the entry point of the library */
|
||||
#ifdef DST_LIB
|
||||
#define dst_io_init _dst_init
|
||||
#define dst_lib_io _dst_init
|
||||
#endif
|
||||
|
||||
/* Module entry point */
|
||||
int dst_io_init(DstArgs args) {
|
||||
DstTable *module = dst_get_module(args);
|
||||
dst_module_def(module, "fopen", dst_wrap_cfunction(dst_io_fopen));
|
||||
dst_module_def(module, "fclose", dst_wrap_cfunction(dst_io_fclose));
|
||||
dst_module_def(module, "fread", dst_wrap_cfunction(dst_io_fread));
|
||||
dst_module_def(module, "fwrite", dst_wrap_cfunction(dst_io_fwrite));
|
||||
dst_module_def(module, "fflush", dst_wrap_cfunction(dst_io_fflush));
|
||||
int dst_lib_io(DstArgs args) {
|
||||
DstTable *env = dst_env_arg(args);
|
||||
dst_env_def(env, "fopen", dst_wrap_cfunction(dst_io_fopen));
|
||||
dst_env_def(env, "fclose", dst_wrap_cfunction(dst_io_fclose));
|
||||
dst_env_def(env, "fread", dst_wrap_cfunction(dst_io_fread));
|
||||
dst_env_def(env, "fwrite", dst_wrap_cfunction(dst_io_fwrite));
|
||||
dst_env_def(env, "fflush", dst_wrap_cfunction(dst_io_fflush));
|
||||
|
||||
/* stdout */
|
||||
dst_module_def(module, "stdout",
|
||||
dst_env_def(env, "stdout",
|
||||
makef(stdout, IO_APPEND | IO_NOT_CLOSEABLE | IO_SERIALIZABLE));
|
||||
|
||||
/* stderr */
|
||||
dst_module_def(module, "stderr",
|
||||
dst_env_def(env, "stderr",
|
||||
makef(stderr, IO_APPEND | IO_NOT_CLOSEABLE | IO_SERIALIZABLE));
|
||||
|
||||
/* stdin */
|
||||
dst_module_def(module, "stdin",
|
||||
dst_env_def(env, "stdin",
|
||||
makef(stdin, IO_READ | IO_NOT_CLOSEABLE | IO_SERIALIZABLE));
|
||||
|
||||
return 0;
|
||||
|
85
core/math.c
85
core/math.c
@ -343,52 +343,45 @@ static int dst_math_not(DstArgs args) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* CMath entry point */
|
||||
|
||||
/* Define the entry point of the library */
|
||||
#ifdef DST_LIB
|
||||
#define dst_math_init _dst_init
|
||||
#endif
|
||||
|
||||
/* Module entry point */
|
||||
int dst_math_init(DstArgs args) {
|
||||
DstTable *module = dst_get_module(args);
|
||||
dst_module_def(module, "int", dst_wrap_cfunction(dst_int));
|
||||
dst_module_def(module, "real", dst_wrap_cfunction(dst_real));
|
||||
dst_module_def(module, "+", dst_wrap_cfunction(dst_add));
|
||||
dst_module_def(module, "-", dst_wrap_cfunction(dst_subtract));
|
||||
dst_module_def(module, "*", dst_wrap_cfunction(dst_multiply));
|
||||
dst_module_def(module, "/", dst_wrap_cfunction(dst_divide));
|
||||
dst_module_def(module, "%", dst_wrap_cfunction(dst_modulo));
|
||||
dst_module_def(module, "=", dst_wrap_cfunction(dst_math_equal));
|
||||
dst_module_def(module, "not=", dst_wrap_cfunction(dst_math_notequal));
|
||||
dst_module_def(module, "<", dst_wrap_cfunction(dst_math_ascending));
|
||||
dst_module_def(module, ">", dst_wrap_cfunction(dst_math_descending));
|
||||
dst_module_def(module, "<=", dst_wrap_cfunction(dst_math_notdescending));
|
||||
dst_module_def(module, ">=", dst_wrap_cfunction(dst_math_notascending));
|
||||
dst_module_def(module, "|", dst_wrap_cfunction(dst_bor));
|
||||
dst_module_def(module, "&", dst_wrap_cfunction(dst_band));
|
||||
dst_module_def(module, "^", dst_wrap_cfunction(dst_bxor));
|
||||
dst_module_def(module, "~", dst_wrap_cfunction(dst_bnot));
|
||||
dst_module_def(module, ">>", dst_wrap_cfunction(dst_lshift));
|
||||
dst_module_def(module, "<<", dst_wrap_cfunction(dst_rshift));
|
||||
dst_module_def(module, ">>>", dst_wrap_cfunction(dst_lshiftu));
|
||||
dst_module_def(module, "not", dst_wrap_cfunction(dst_math_not));
|
||||
dst_module_def(module, "cos", dst_wrap_cfunction(dst_cos));
|
||||
dst_module_def(module, "sin", dst_wrap_cfunction(dst_sin));
|
||||
dst_module_def(module, "tan", dst_wrap_cfunction(dst_tan));
|
||||
dst_module_def(module, "acos", dst_wrap_cfunction(dst_acos));
|
||||
dst_module_def(module, "asin", dst_wrap_cfunction(dst_asin));
|
||||
dst_module_def(module, "atan", dst_wrap_cfunction(dst_atan));
|
||||
dst_module_def(module, "exp", dst_wrap_cfunction(dst_exp));
|
||||
dst_module_def(module, "log", dst_wrap_cfunction(dst_log));
|
||||
dst_module_def(module, "log10", dst_wrap_cfunction(dst_log10));
|
||||
dst_module_def(module, "sqrt", dst_wrap_cfunction(dst_sqrt));
|
||||
dst_module_def(module, "floor", dst_wrap_cfunction(dst_floor));
|
||||
dst_module_def(module, "ceil", dst_wrap_cfunction(dst_ceil));
|
||||
dst_module_def(module, "pow", dst_wrap_cfunction(dst_pow));
|
||||
dst_module_def(module, "pi", dst_wrap_real(M_PI));
|
||||
dst_module_def(module, "\xCF\x80", dst_wrap_real(M_PI));
|
||||
dst_module_def(module, "e", dst_wrap_real(M_E));
|
||||
int dst_lib_math(DstArgs args) {
|
||||
DstTable *env = dst_env_arg(args);
|
||||
dst_env_def(env, "int", dst_wrap_cfunction(dst_int));
|
||||
dst_env_def(env, "real", dst_wrap_cfunction(dst_real));
|
||||
dst_env_def(env, "+", dst_wrap_cfunction(dst_add));
|
||||
dst_env_def(env, "-", dst_wrap_cfunction(dst_subtract));
|
||||
dst_env_def(env, "*", dst_wrap_cfunction(dst_multiply));
|
||||
dst_env_def(env, "/", dst_wrap_cfunction(dst_divide));
|
||||
dst_env_def(env, "%", dst_wrap_cfunction(dst_modulo));
|
||||
dst_env_def(env, "=", dst_wrap_cfunction(dst_math_equal));
|
||||
dst_env_def(env, "not=", dst_wrap_cfunction(dst_math_notequal));
|
||||
dst_env_def(env, "<", dst_wrap_cfunction(dst_math_ascending));
|
||||
dst_env_def(env, ">", dst_wrap_cfunction(dst_math_descending));
|
||||
dst_env_def(env, "<=", dst_wrap_cfunction(dst_math_notdescending));
|
||||
dst_env_def(env, ">=", dst_wrap_cfunction(dst_math_notascending));
|
||||
dst_env_def(env, "|", dst_wrap_cfunction(dst_bor));
|
||||
dst_env_def(env, "&", dst_wrap_cfunction(dst_band));
|
||||
dst_env_def(env, "^", dst_wrap_cfunction(dst_bxor));
|
||||
dst_env_def(env, "~", dst_wrap_cfunction(dst_bnot));
|
||||
dst_env_def(env, ">>", dst_wrap_cfunction(dst_lshift));
|
||||
dst_env_def(env, "<<", dst_wrap_cfunction(dst_rshift));
|
||||
dst_env_def(env, ">>>", dst_wrap_cfunction(dst_lshiftu));
|
||||
dst_env_def(env, "not", dst_wrap_cfunction(dst_math_not));
|
||||
dst_env_def(env, "cos", dst_wrap_cfunction(dst_cos));
|
||||
dst_env_def(env, "sin", dst_wrap_cfunction(dst_sin));
|
||||
dst_env_def(env, "tan", dst_wrap_cfunction(dst_tan));
|
||||
dst_env_def(env, "acos", dst_wrap_cfunction(dst_acos));
|
||||
dst_env_def(env, "asin", dst_wrap_cfunction(dst_asin));
|
||||
dst_env_def(env, "atan", dst_wrap_cfunction(dst_atan));
|
||||
dst_env_def(env, "exp", dst_wrap_cfunction(dst_exp));
|
||||
dst_env_def(env, "log", dst_wrap_cfunction(dst_log));
|
||||
dst_env_def(env, "log10", dst_wrap_cfunction(dst_log10));
|
||||
dst_env_def(env, "sqrt", dst_wrap_cfunction(dst_sqrt));
|
||||
dst_env_def(env, "floor", dst_wrap_cfunction(dst_floor));
|
||||
dst_env_def(env, "ceil", dst_wrap_cfunction(dst_ceil));
|
||||
dst_env_def(env, "pow", dst_wrap_cfunction(dst_pow));
|
||||
dst_env_def(env, "pi", dst_wrap_real(3.1415926535897931));
|
||||
dst_env_def(env, "\xCF\x80", dst_wrap_real(3.1415926535897931));
|
||||
dst_env_def(env, "e", dst_wrap_real(2.7182818284590451));
|
||||
return 0;
|
||||
}
|
||||
|
756
core/parse.c
756
core/parse.c
@ -21,16 +21,7 @@
|
||||
*/
|
||||
|
||||
#include <dst/dst.h>
|
||||
|
||||
/* Checks if a string slice is equal to a string constant */
|
||||
static int check_str_const(const char *ref, const uint8_t *start, const uint8_t *end) {
|
||||
while (*ref && start < end) {
|
||||
if (*ref != *(char *)start) return 0;
|
||||
++ref;
|
||||
++start;
|
||||
}
|
||||
return !*ref && start == end;
|
||||
}
|
||||
#include "util.h"
|
||||
|
||||
/* Quote a value */
|
||||
static Dst quote(Dst x) {
|
||||
@ -155,381 +146,404 @@ static int to_hex(uint8_t c) {
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
DstArray stack;
|
||||
const uint8_t *srcstart;
|
||||
const uint8_t *end;
|
||||
const char *errmsg;
|
||||
DstParseStatus status;
|
||||
typedef int (*Consumer)(DstParser *p, DstParseState *state, uint8_t c);
|
||||
struct DstParseState {
|
||||
int32_t qcount;
|
||||
int32_t argn;
|
||||
int flags;
|
||||
} ParseArgs;
|
||||
size_t start;
|
||||
Consumer consumer;
|
||||
};
|
||||
|
||||
#define PFLAG_CONTAINER 1
|
||||
|
||||
/* Entry point of the recursive descent parser */
|
||||
static const uint8_t *parse_recur(
|
||||
ParseArgs *args,
|
||||
const uint8_t *src,
|
||||
int32_t recur) {
|
||||
|
||||
const uint8_t *end = args->end;
|
||||
const uint8_t *mapstart;
|
||||
int32_t qcount = 0;
|
||||
Dst ret;
|
||||
|
||||
/* Prevent stack overflow */
|
||||
if (recur == 0) goto too_much_recur;
|
||||
|
||||
/* try parsing again */
|
||||
begin:
|
||||
|
||||
/* Trim leading whitespace and count quotes */
|
||||
while (src < end && (is_whitespace(*src) || *src == '\'')) {
|
||||
if (*src == '\'') {
|
||||
++qcount;
|
||||
}
|
||||
++src;
|
||||
}
|
||||
|
||||
/* Check for end of source */
|
||||
if (src >= end) {
|
||||
if (qcount || recur != DST_RECURSION_GUARD) {
|
||||
goto unexpected_eos;
|
||||
} else {
|
||||
goto nodata;
|
||||
}
|
||||
}
|
||||
|
||||
/* Open mapping */
|
||||
mapstart = src;
|
||||
|
||||
/* Detect token type based on first character */
|
||||
switch (*src) {
|
||||
|
||||
/* Numbers, symbols, simple literals */
|
||||
default:
|
||||
atom:
|
||||
{
|
||||
int ascii = 1;
|
||||
Dst numcheck;
|
||||
const uint8_t *tokenend = src;
|
||||
if (!is_symbol_char(*src)) {
|
||||
src++;
|
||||
goto unexpected_character;
|
||||
}
|
||||
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;
|
||||
} else if (check_str_const("nil", src, tokenend)) {
|
||||
ret = dst_wrap_nil();
|
||||
} else if (check_str_const("false", src, tokenend)) {
|
||||
ret = dst_wrap_boolean(0);
|
||||
} else if (check_str_const("true", src, tokenend)) {
|
||||
ret = dst_wrap_boolean(1);
|
||||
} else {
|
||||
if (*src >= '0' && *src <= '9') {
|
||||
goto sym_nodigits;
|
||||
} else {
|
||||
/* 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);
|
||||
} else {
|
||||
ret = dst_symbolv(src, tokenend - src);
|
||||
}
|
||||
}
|
||||
}
|
||||
src = tokenend;
|
||||
break;
|
||||
}
|
||||
|
||||
case '#':
|
||||
{
|
||||
/* Jump to next newline */
|
||||
while (src < end && *src != '\n')
|
||||
++src;
|
||||
goto begin;
|
||||
}
|
||||
|
||||
/* String literals */
|
||||
case '"':
|
||||
{
|
||||
const uint8_t *strend = ++src;
|
||||
const uint8_t *strstart = strend;
|
||||
int32_t len = 0;
|
||||
int containsEscape = 0;
|
||||
/* Preprocess string to check for escapes and string end */
|
||||
while (strend < end && *strend != '"') {
|
||||
len++;
|
||||
if (*strend++ == '\\') {
|
||||
containsEscape = 1;
|
||||
if (strend >= end) goto unexpected_eos;
|
||||
if (*strend == 'h') {
|
||||
strend += 3;
|
||||
if (strend >= end) goto unexpected_eos;
|
||||
} else {
|
||||
strend++;
|
||||
if (strend >= end) goto unexpected_eos;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (containsEscape) {
|
||||
uint8_t *buf = dst_string_begin(len);
|
||||
uint8_t *write = buf;
|
||||
while (src < strend) {
|
||||
if (*src == '\\') {
|
||||
src++;
|
||||
switch (*src++) {
|
||||
case 'n': *write++ = '\n'; break;
|
||||
case 'r': *write++ = '\r'; break;
|
||||
case 't': *write++ = '\t'; break;
|
||||
case 'f': *write++ = '\f'; break;
|
||||
case '0': *write++ = '\0'; break;
|
||||
case '"': *write++ = '"'; break;
|
||||
case '\'': *write++ = '\''; break;
|
||||
case 'z': *write++ = '\0'; break;
|
||||
case 'e': *write++ = 27; break;
|
||||
case 'h': {
|
||||
int d1 = to_hex(*src++);
|
||||
int d2 = to_hex(*src++);
|
||||
if (d1 < 0 || d2 < 0) goto invalid_hex;
|
||||
*write++ = 16 * d1 + d2;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
goto unknown_strescape;
|
||||
}
|
||||
} else {
|
||||
*write++ = *src++;
|
||||
}
|
||||
}
|
||||
ret = dst_wrap_string(dst_string_end(buf));
|
||||
} else {
|
||||
ret = dst_wrap_string(dst_string(strstart, strend - strstart));
|
||||
}
|
||||
src = strend + 1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Data Structure literals */
|
||||
case '@':
|
||||
if (src[1] != '{')
|
||||
goto atom;
|
||||
case '(':
|
||||
case '[':
|
||||
case '{':
|
||||
{
|
||||
int32_t n = 0, i = 0;
|
||||
int32_t istable = 0;
|
||||
uint8_t close;
|
||||
switch (*src++) {
|
||||
case '[': close = ']'; break;
|
||||
case '{': close = '}'; break;
|
||||
case '@': close = '}'; src++; istable = 1; break;
|
||||
default: close = ')'; break;
|
||||
}
|
||||
/* Trim trailing whitespace */
|
||||
while (src < end && (is_whitespace(*src)))
|
||||
++src;
|
||||
/* Recursively parse inside literal */
|
||||
while (*src != close) {
|
||||
src = parse_recur(args, src, recur - 1);
|
||||
if (args->errmsg || !src) return src;
|
||||
n++;
|
||||
/* Trim trailing whitespace */
|
||||
while (src < end && (is_whitespace(*src)))
|
||||
++src;
|
||||
}
|
||||
src++;
|
||||
switch (close) {
|
||||
case ')':
|
||||
{
|
||||
Dst *tup = dst_tuple_begin(n);
|
||||
for (i = n; i > 0; i--) {
|
||||
tup[i - 1] = dst_array_pop(&args->stack);
|
||||
}
|
||||
ret = dst_wrap_tuple(dst_tuple_end(tup));
|
||||
break;
|
||||
}
|
||||
case ']':
|
||||
{
|
||||
DstArray *arr = dst_array(n);
|
||||
for (i = n; i > 0; i--) {
|
||||
arr->data[i - 1] = dst_array_pop(&args->stack);
|
||||
}
|
||||
arr->count = n;
|
||||
ret = dst_wrap_array(arr);
|
||||
break;
|
||||
}
|
||||
case '}':
|
||||
{
|
||||
if (n & 1) {
|
||||
if (istable)
|
||||
goto table_oddargs;
|
||||
goto struct_oddargs;
|
||||
}
|
||||
if (istable) {
|
||||
DstTable *t = dst_table(n);
|
||||
for (i = n; i > 0; i -= 2) {
|
||||
Dst val = dst_array_pop(&args->stack);
|
||||
Dst key = dst_array_pop(&args->stack);
|
||||
dst_table_put(t, key, val);
|
||||
}
|
||||
ret = dst_wrap_table(t);
|
||||
} else {
|
||||
DstKV *st = dst_struct_begin(n >> 1);
|
||||
for (i = n; i > 0; i -= 2) {
|
||||
Dst val = dst_array_pop(&args->stack);
|
||||
Dst key = dst_array_pop(&args->stack);
|
||||
dst_struct_put(st, key, val);
|
||||
}
|
||||
ret = dst_wrap_struct(dst_struct_end(st));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Quote the returned value qcount times */
|
||||
while (qcount--) {
|
||||
if (args->flags & DST_PARSEFLAG_SOURCEMAP)
|
||||
ret = dst_ast_wrap(ret, mapstart - args->srcstart, src - args->srcstart);
|
||||
ret = quote(ret);
|
||||
}
|
||||
|
||||
/* Ast wrap */
|
||||
if (args->flags & DST_PARSEFLAG_SOURCEMAP)
|
||||
ret = dst_ast_wrap(ret, mapstart - args->srcstart, src - args->srcstart);
|
||||
|
||||
/* Push the result to the stack */
|
||||
dst_array_push(&args->stack, ret);
|
||||
|
||||
/* Return the new source position for further calls */
|
||||
return src;
|
||||
|
||||
/* Errors below */
|
||||
|
||||
nodata:
|
||||
args->status = DST_PARSE_NODATA;
|
||||
return NULL;
|
||||
|
||||
unexpected_eos:
|
||||
args->errmsg = "unexpected end of source";
|
||||
args->status = DST_PARSE_UNEXPECTED_EOS;
|
||||
return NULL;
|
||||
|
||||
unexpected_character:
|
||||
args->errmsg = "unexpected character";
|
||||
args->status = DST_PARSE_ERROR;
|
||||
return src;
|
||||
|
||||
sym_nodigits:
|
||||
args->errmsg = "symbols cannot start with digits";
|
||||
args->status = DST_PARSE_ERROR;
|
||||
return src;
|
||||
|
||||
table_oddargs:
|
||||
args->errmsg = "table literal needs an even number of arguments";
|
||||
args->status = DST_PARSE_ERROR;
|
||||
return src;
|
||||
|
||||
struct_oddargs:
|
||||
args->errmsg = "struct literal needs an even number of arguments";
|
||||
args->status = DST_PARSE_ERROR;
|
||||
return src;
|
||||
|
||||
unknown_strescape:
|
||||
args->errmsg = "unknown string escape sequence";
|
||||
args->status = DST_PARSE_ERROR;
|
||||
return src;
|
||||
|
||||
invalid_hex:
|
||||
args->errmsg = "invalid hex escape in string";
|
||||
args->status = DST_PARSE_ERROR;
|
||||
return src;
|
||||
|
||||
invalid_utf8:
|
||||
args->errmsg = "identifier is not valid utf-8";
|
||||
args->status = DST_PARSE_ERROR;
|
||||
return src;
|
||||
|
||||
too_much_recur:
|
||||
args->errmsg = "recursed too deeply in parsing";
|
||||
args->status = DST_PARSE_ERROR;
|
||||
return src;
|
||||
static void pushstate(DstParser *p, Consumer consumer, int flags) {
|
||||
DstParseState s;
|
||||
s.qcount = 0;
|
||||
s.argn = 0;
|
||||
s.flags = flags;
|
||||
s.consumer = consumer;
|
||||
s.start = p->index;
|
||||
dst_v_push(p->states, s);
|
||||
}
|
||||
|
||||
/* Parse an array of bytes. Return value in the fiber return value. */
|
||||
DstParseResult dst_parse(const uint8_t *src, int32_t len, int flags) {
|
||||
DstParseResult res;
|
||||
ParseArgs args;
|
||||
const uint8_t *newsrc;
|
||||
static void popstate(DstParser *p, Dst val) {
|
||||
DstParseState top = dst_v_last(p->states);
|
||||
DstParseState *newtop;
|
||||
dst_v_pop(p->states);
|
||||
newtop = &dst_v_last(p->states);
|
||||
if (newtop->flags & PFLAG_CONTAINER) {
|
||||
int32_t i, len;
|
||||
len = newtop->qcount;
|
||||
/* Quote the returned value qcount times */
|
||||
for (i = 0; i < len; i++) {
|
||||
if (p->flags & DST_PARSEFLAG_SOURCEMAP)
|
||||
val = dst_ast_wrap(val, (int32_t) top.start, (int32_t) p->index);
|
||||
val = quote(val);
|
||||
}
|
||||
newtop->qcount = 0;
|
||||
|
||||
dst_array_init(&args.stack, 10);
|
||||
args.status = DST_PARSE_OK;
|
||||
args.srcstart = src;
|
||||
args.end = src + len;
|
||||
args.errmsg = NULL;
|
||||
args.flags = flags;
|
||||
/* Ast wrap */
|
||||
if (p->flags & DST_PARSEFLAG_SOURCEMAP)
|
||||
val = dst_ast_wrap(val, (int32_t) top.start, (int32_t) p->index);
|
||||
|
||||
newsrc = parse_recur(&args, src, DST_RECURSION_GUARD);
|
||||
res.status = args.status;
|
||||
res.bytes_read = (int32_t) (newsrc - src);
|
||||
newtop->argn++;
|
||||
dst_v_push(p->argstack, val);
|
||||
}
|
||||
}
|
||||
|
||||
if (args.errmsg) {
|
||||
res.error = dst_cstring(args.errmsg);
|
||||
res.value = dst_wrap_nil();
|
||||
static uint8_t checkescape(uint8_t c) {
|
||||
switch (c) {
|
||||
default: return 0;
|
||||
case 'h': return 1;
|
||||
case 'n': return '\n';
|
||||
case 't': return '\t';
|
||||
case 'r': return '\r';
|
||||
case '0': return '\0';
|
||||
case 'z': return '\0';
|
||||
case 'f': return '\f';
|
||||
case 'e': return 27;
|
||||
case '"': return '"';
|
||||
case '\'': return '\'';
|
||||
case '\\': return '\\';
|
||||
}
|
||||
}
|
||||
|
||||
/* Forward declare */
|
||||
static int stringchar(DstParser *p, DstParseState *state, uint8_t c);
|
||||
|
||||
static int escapeh(DstParser *p, DstParseState *state, uint8_t c) {
|
||||
int digit = to_hex(c);
|
||||
if (digit < 0) {
|
||||
p->error = "invalid hex digit in hex escape";
|
||||
return 1;
|
||||
}
|
||||
state->argn = (state->argn << 4) + digit;;
|
||||
state->qcount--;
|
||||
if (!state->qcount) {
|
||||
dst_v_push(p->buf, (state->argn & 0xFF));
|
||||
state->argn = 0;
|
||||
state->consumer = stringchar;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int escape1(DstParser *p, DstParseState *state, uint8_t c) {
|
||||
uint8_t e = checkescape(c);
|
||||
if (!e) {
|
||||
p->error = "invalid string escape sequence";
|
||||
return 1;
|
||||
}
|
||||
if (c == 'h') {
|
||||
state->qcount = 2;
|
||||
state->argn = 0;
|
||||
state->consumer = escapeh;
|
||||
} else {
|
||||
res.value = dst_array_pop(&args.stack);
|
||||
res.error = NULL;
|
||||
dst_v_push(p->buf, e);
|
||||
state->consumer = stringchar;
|
||||
}
|
||||
|
||||
dst_array_deinit(&args.stack);
|
||||
|
||||
return res;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Parse a c string */
|
||||
DstParseResult dst_parsec(const char *src, int flags) {
|
||||
int32_t len = 0;
|
||||
while (src[len]) ++len;
|
||||
return dst_parse((const uint8_t *)src, len, flags);
|
||||
static int stringchar(DstParser *p, DstParseState *state, uint8_t c) {
|
||||
/* Enter escape */
|
||||
if (c == '\\') {
|
||||
state->consumer = escape1;
|
||||
return 1;
|
||||
}
|
||||
/* String end */
|
||||
if (c == '"') {
|
||||
/* String end */
|
||||
Dst ret = dst_wrap_string(dst_string(p->buf, dst_v_count(p->buf)));
|
||||
dst_v_empty(p->buf);
|
||||
popstate(p, ret);
|
||||
return 1;
|
||||
}
|
||||
/* normal char */
|
||||
dst_v_push(p->buf, c);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Check for string equality in the buffer */
|
||||
static int check_str_const(const char *cstr, const uint8_t *str, int32_t len) {
|
||||
int32_t index;
|
||||
for (index = 0; index < len; index++) {
|
||||
uint8_t c = str[index];
|
||||
uint8_t k = ((const uint8_t *)cstr)[index];
|
||||
if (c < k) return -1;
|
||||
if (c > k) return 1;
|
||||
if (k == '\0') break;
|
||||
}
|
||||
return (cstr[index] == '\0') ? 0 : -1;
|
||||
}
|
||||
|
||||
static int tokenchar(DstParser *p, DstParseState *state, uint8_t c) {
|
||||
Dst numcheck, ret;
|
||||
int32_t blen;
|
||||
if (is_symbol_char(c)) {
|
||||
dst_v_push(p->buf, (uint8_t) c);
|
||||
if (c > 127) state->argn = 1; /* Use to indicate non ascii */
|
||||
return 1;
|
||||
}
|
||||
/* Token finished */
|
||||
blen = dst_v_count(p->buf);
|
||||
numcheck = dst_scan_number(p->buf, blen);
|
||||
if (!dst_checktype(numcheck, DST_NIL)) {
|
||||
ret = numcheck;
|
||||
} else if (!check_str_const("nil", p->buf, blen)) {
|
||||
ret = dst_wrap_nil();
|
||||
} else if (!check_str_const("false", p->buf, blen)) {
|
||||
ret = dst_wrap_false();
|
||||
} else if (!check_str_const("true", p->buf, blen)) {
|
||||
ret = dst_wrap_true();
|
||||
} else {
|
||||
if (p->buf[0] >= '0' && p->buf[0] <= '9') {
|
||||
p->error = "symbol literal cannot start with a digit";
|
||||
return 0;
|
||||
} else {
|
||||
/* Don't do full utf8 check unless we have seen non ascii characters. */
|
||||
int valid = (!state->argn) || valid_utf8(p->buf, blen);
|
||||
if (!valid) {
|
||||
p->error = "invalid utf-8 in symbol";
|
||||
return 0;
|
||||
}
|
||||
if (p->buf[0] == ':') {
|
||||
ret = dst_stringv(p->buf + 1, blen - 1);
|
||||
} else {
|
||||
ret = dst_symbolv(p->buf, blen);
|
||||
}
|
||||
}
|
||||
}
|
||||
dst_v_empty(p->buf);
|
||||
popstate(p, ret);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int comment(DstParser *p, DstParseState *state, uint8_t c) {
|
||||
(void) state;
|
||||
if (c == '\n') dst_v_pop(p->states);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Forward declaration */
|
||||
static int root(DstParser *p, DstParseState *state, uint8_t c);
|
||||
|
||||
static int dotuple(DstParser *p, DstParseState *state, uint8_t c) {
|
||||
if (c == ')') {
|
||||
int32_t i;
|
||||
Dst *ret = dst_tuple_begin(state->argn);
|
||||
for (i = state->argn - 1; i >= 0; i--) {
|
||||
ret[i] = dst_v_last(p->argstack); dst_v_pop(p->argstack);
|
||||
}
|
||||
popstate(p, dst_wrap_tuple(dst_tuple_end(ret)));
|
||||
return 1;
|
||||
}
|
||||
return root(p, state, c);
|
||||
}
|
||||
|
||||
static int doarray(DstParser *p, DstParseState *state, uint8_t c) {
|
||||
if (c == ']') {
|
||||
int32_t i;
|
||||
DstArray *array = dst_array(state->argn);
|
||||
for (i = state->argn - 1; i >= 0; i--) {
|
||||
array->data[i] = dst_v_last(p->argstack); dst_v_pop(p->argstack);
|
||||
}
|
||||
array->count = state->argn;
|
||||
popstate(p, dst_wrap_array(array));
|
||||
return 1;
|
||||
}
|
||||
return root(p, state, c);
|
||||
}
|
||||
|
||||
static int dostruct(DstParser *p, DstParseState *state, uint8_t c) {
|
||||
if (c == '}') {
|
||||
int32_t i;
|
||||
DstKV *st;
|
||||
if (state->argn & 1) {
|
||||
p->error = "struct literal expects even number of arguments";
|
||||
return 1;
|
||||
}
|
||||
st = dst_struct_begin(state->argn >> 1);
|
||||
for (i = state->argn; i > 0; i -= 2) {
|
||||
Dst value = dst_v_last(p->argstack); dst_v_pop(p->argstack);
|
||||
Dst key = dst_v_last(p->argstack); dst_v_pop(p->argstack);
|
||||
dst_struct_put(st, key, value);
|
||||
}
|
||||
popstate(p, dst_wrap_struct(dst_struct_end(st)));
|
||||
return 1;
|
||||
}
|
||||
return root(p, state, c);
|
||||
}
|
||||
|
||||
static int dotable(DstParser *p, DstParseState *state, uint8_t c) {
|
||||
if (c == '}') {
|
||||
int32_t i;
|
||||
DstTable *table;
|
||||
if (state->argn & 1) {
|
||||
p->error = "table literal expects even number of arguments";
|
||||
return 1;
|
||||
}
|
||||
table = dst_table(state->argn >> 1);
|
||||
for (i = state->argn; i > 0; i -= 2) {
|
||||
Dst value = dst_v_last(p->argstack); dst_v_pop(p->argstack);
|
||||
Dst key = dst_v_last(p->argstack); dst_v_pop(p->argstack);
|
||||
dst_table_put(table, key, value);
|
||||
}
|
||||
popstate(p, dst_wrap_table(table));
|
||||
return 1;
|
||||
}
|
||||
return root(p, state, c);
|
||||
}
|
||||
|
||||
static int ampersand(DstParser *p, DstParseState *state, uint8_t c) {
|
||||
(void) state;
|
||||
dst_v_pop(p->states);
|
||||
if (c == '{') {
|
||||
pushstate(p, dotable, PFLAG_CONTAINER);
|
||||
return 1;
|
||||
}
|
||||
pushstate(p, tokenchar, 0);
|
||||
dst_v_push(p->buf, '@'); /* Push the leading ampersand that was dropped */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int root(DstParser *p, DstParseState *state, uint8_t c) {
|
||||
switch (c) {
|
||||
default:
|
||||
if (is_whitespace(c)) return 1;
|
||||
pushstate(p, tokenchar, 0);
|
||||
return 0;
|
||||
case '\'':
|
||||
state->qcount++;
|
||||
return 1;
|
||||
case '"':
|
||||
pushstate(p, stringchar, 0);
|
||||
return 1;
|
||||
case '#':
|
||||
pushstate(p, comment, 0);
|
||||
return 1;
|
||||
case '@':
|
||||
pushstate(p, ampersand, 0);
|
||||
return 1;
|
||||
case ')':
|
||||
case ']':
|
||||
case '}':
|
||||
p->error = "mismatched delimiter";
|
||||
return 1;
|
||||
case '(':
|
||||
pushstate(p, dotuple, PFLAG_CONTAINER);
|
||||
return 1;
|
||||
case '[':
|
||||
pushstate(p, doarray, PFLAG_CONTAINER);
|
||||
return 1;
|
||||
case '{':
|
||||
pushstate(p, dostruct, PFLAG_CONTAINER);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
int dst_parser_consume(DstParser *parser, uint8_t c) {
|
||||
int consumed = 0;
|
||||
if (parser->error) return 0;
|
||||
while (!consumed && !parser->error) {
|
||||
DstParseState *state = &dst_v_last(parser->states);
|
||||
consumed = state->consumer(parser, state, c);
|
||||
}
|
||||
parser->lookback = c;
|
||||
return 1;
|
||||
}
|
||||
|
||||
DstParserStatus dst_parser_status(DstParser *parser) {
|
||||
if (parser->error) return DST_PARSE_ERROR;
|
||||
if (dst_v_count(parser->states) > 1) return DST_PARSE_PENDING;
|
||||
if (dst_v_count(parser->argstack)) return DST_PARSE_FULL;
|
||||
return DST_PARSE_ROOT;
|
||||
}
|
||||
|
||||
const char *dst_parser_error(DstParser *parser) {
|
||||
DstParserStatus status = dst_parser_status(parser);
|
||||
if (status == DST_PARSE_ERROR) {
|
||||
const char *e = parser->error;
|
||||
dst_v_empty(parser->argstack);
|
||||
dst_v__cnt(parser->states) = 1;
|
||||
parser->error = NULL;
|
||||
dst_v_empty(parser->buf);
|
||||
return e;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Dst dst_parser_produce(DstParser *parser) {
|
||||
Dst ret;
|
||||
DstParserStatus status = dst_parser_status(parser);
|
||||
if (status != DST_PARSE_FULL) return dst_wrap_nil();
|
||||
ret = dst_v_last(parser->argstack);
|
||||
dst_v_pop(parser->argstack);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void dst_parser_init(DstParser *parser, int flags) {
|
||||
parser->argstack = NULL;
|
||||
parser->states = NULL;
|
||||
parser->buf = NULL;
|
||||
parser->error = NULL;
|
||||
parser->index = 0;
|
||||
parser->lookback = -1;
|
||||
parser->flags = flags;
|
||||
pushstate(parser, root, PFLAG_CONTAINER);
|
||||
}
|
||||
|
||||
void dst_parser_deinit(DstParser *parser) {
|
||||
dst_v_free(parser->argstack);
|
||||
dst_v_free(parser->buf);
|
||||
dst_v_free(parser->states);
|
||||
}
|
||||
|
||||
/* C functions */
|
||||
|
||||
static int parsermark(void *p, size_t size) {
|
||||
int32_t i;
|
||||
DstParser *parser = (DstParser *)p;
|
||||
(void) size;
|
||||
for (i = 0; i < dst_v_count(parser->argstack); i++) {
|
||||
dst_mark(parser->argstack[i]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parsergc(void *p, size_t size) {
|
||||
DstParser *parser = (DstParser *)p;
|
||||
(void) size;
|
||||
dst_parser_deinit(parser);
|
||||
return 0;
|
||||
}
|
||||
|
||||
DstAbstractType dst_parse_parsertype = {
|
||||
"stl.parser",
|
||||
parsergc,
|
||||
parsermark
|
||||
};
|
||||
|
||||
/* C Function parser */
|
||||
int dst_parse_cfun(DstArgs args) {
|
||||
const uint8_t *src;
|
||||
int32_t len;
|
||||
DstParseResult res;
|
||||
const char *status_string = "ok";
|
||||
DstTable *t;
|
||||
if (args.n < 1) return dst_throw(args, "expected at least on argument");
|
||||
if (!dst_chararray_view(args.v[0], &src, &len)) return dst_throw(args, "expected string/buffer");
|
||||
res = dst_parse(src, len, 0);
|
||||
t = dst_table(4);
|
||||
switch (res.status) {
|
||||
case DST_PARSE_OK:
|
||||
status_string = "ok";
|
||||
break;
|
||||
case DST_PARSE_ERROR:
|
||||
status_string = "error";
|
||||
break;
|
||||
case DST_PARSE_NODATA:
|
||||
status_string = "nodata";
|
||||
break;
|
||||
case DST_PARSE_UNEXPECTED_EOS:
|
||||
status_string = "eos";
|
||||
break;
|
||||
static int cfun_parser(DstArgs args) {
|
||||
int flags;
|
||||
if (args.n > 1) return dst_throw(args, "expected 1 argument");
|
||||
if (args.n) {
|
||||
if (!dst_checktype(args.v[0], DST_INTEGER)) return dst_throw(args, "expected integer");
|
||||
flags = dst_unwrap_integer(args.v[0]);
|
||||
} else {
|
||||
flags = 0;
|
||||
}
|
||||
dst_table_put(t, dst_cstringv("status"), dst_cstringv(status_string));
|
||||
if (res.status == DST_PARSE_OK) dst_table_put(t, dst_cstringv("value"), res.value);
|
||||
if (res.status == DST_PARSE_ERROR) dst_table_put(t, dst_cstringv("error"), dst_wrap_string(res.error));
|
||||
dst_table_put(t, dst_cstringv("bytes-read"), dst_wrap_integer(res.bytes_read));
|
||||
return dst_return(args, dst_wrap_table(t));
|
||||
DstParser *p = dst_abstract(&dst_parse_parsertype, sizeof(DstParser));
|
||||
dst_parser_init(p, 0);
|
||||
return dst_return(args, dst_wrap_abstract(p));
|
||||
}
|
||||
|
||||
/* Load the library */
|
||||
int dst_lib_parse(DstArgs args) {
|
||||
DstTable *env = dst_env_arg(args);
|
||||
|
||||
dst_env_def(env, "parser", dst_wrap_cfunction(cfun_parser));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
87
core/stl.c
87
core/stl.c
@ -23,13 +23,6 @@
|
||||
#include <dst/dst.h>
|
||||
#include <dst/dststl.h>
|
||||
|
||||
int dst_stl_push(DstArgs args) {
|
||||
if (args.n != 2) return dst_throw(args, "expected 2 arguments");
|
||||
if (!dst_checktype(args.v[0], DST_ARRAY)) return dst_throw(args, "expected array");
|
||||
dst_array_push(dst_unwrap_array(args.v[0]), args.v[1]);
|
||||
return dst_return(args, args.v[0]);
|
||||
}
|
||||
|
||||
int dst_stl_exit(DstArgs args) {
|
||||
int32_t exitcode = 0;
|
||||
if (args.n > 0) {
|
||||
@ -252,49 +245,51 @@ int dst_stl_hash(DstArgs args) {
|
||||
return dst_return(args, dst_wrap_integer(dst_hash(args.v[0])));
|
||||
}
|
||||
|
||||
Dst dst_stl_env() {
|
||||
Dst ret;
|
||||
DstArgs args;
|
||||
DstTable *module = dst_table(0);
|
||||
ret = dst_wrap_table(module);
|
||||
args.n = 1;
|
||||
args.v = &ret;
|
||||
args.ret = &ret;
|
||||
DstTable *dst_stl_env() {
|
||||
DstTable *env = dst_table(0);
|
||||
Dst ret = dst_wrap_table(env);
|
||||
|
||||
dst_module_def(module, "native", dst_wrap_cfunction(dst_load_native));
|
||||
dst_module_def(module, "push", dst_wrap_cfunction(dst_stl_push));
|
||||
dst_module_def(module, "print", dst_wrap_cfunction(dst_stl_print));
|
||||
dst_module_def(module, "describe", dst_wrap_cfunction(dst_stl_describe));
|
||||
dst_module_def(module, "string", dst_wrap_cfunction(dst_stl_string));
|
||||
dst_module_def(module, "buffer-to-string", dst_wrap_cfunction(dst_stl_buffer_to_string));
|
||||
dst_module_def(module, "table", dst_wrap_cfunction(dst_cfun_table));
|
||||
dst_module_def(module, "array", dst_wrap_cfunction(dst_cfun_array));
|
||||
dst_module_def(module, "tuple", dst_wrap_cfunction(dst_cfun_tuple));
|
||||
dst_module_def(module, "struct", dst_wrap_cfunction(dst_cfun_struct));
|
||||
dst_module_def(module, "fiber", dst_wrap_cfunction(dst_stl_fiber));
|
||||
dst_module_def(module, "status", dst_wrap_cfunction(dst_stl_status));
|
||||
dst_module_def(module, "buffer", dst_wrap_cfunction(dst_stl_buffer));
|
||||
dst_module_def(module, "gensym", dst_wrap_cfunction(dst_stl_gensym));
|
||||
dst_module_def(module, "get", dst_wrap_cfunction(dst_stl_get));
|
||||
dst_module_def(module, "put", dst_wrap_cfunction(dst_stl_put));
|
||||
dst_module_def(module, "length", dst_wrap_cfunction(dst_stl_length));
|
||||
dst_module_def(module, "gccollect", dst_wrap_cfunction(dst_stl_gccollect));
|
||||
dst_module_def(module, "type", dst_wrap_cfunction(dst_stl_type));
|
||||
dst_module_def(module, "next", dst_wrap_cfunction(dst_stl_next));
|
||||
dst_module_def(module, "hash", dst_wrap_cfunction(dst_stl_hash));
|
||||
dst_module_def(module, "exit", dst_wrap_cfunction(dst_stl_exit));
|
||||
dst_env_def(env, "native", dst_wrap_cfunction(dst_load_native));
|
||||
dst_env_def(env, "print", dst_wrap_cfunction(dst_stl_print));
|
||||
dst_env_def(env, "describe", dst_wrap_cfunction(dst_stl_describe));
|
||||
dst_env_def(env, "string", dst_wrap_cfunction(dst_stl_string));
|
||||
dst_env_def(env, "buffer-to-string", dst_wrap_cfunction(dst_stl_buffer_to_string));
|
||||
dst_env_def(env, "table", dst_wrap_cfunction(dst_cfun_table));
|
||||
dst_env_def(env, "array", dst_wrap_cfunction(dst_cfun_array));
|
||||
dst_env_def(env, "tuple", dst_wrap_cfunction(dst_cfun_tuple));
|
||||
dst_env_def(env, "struct", dst_wrap_cfunction(dst_cfun_struct));
|
||||
dst_env_def(env, "fiber", dst_wrap_cfunction(dst_stl_fiber));
|
||||
dst_env_def(env, "status", dst_wrap_cfunction(dst_stl_status));
|
||||
dst_env_def(env, "buffer", dst_wrap_cfunction(dst_stl_buffer));
|
||||
dst_env_def(env, "gensym", dst_wrap_cfunction(dst_stl_gensym));
|
||||
dst_env_def(env, "get", dst_wrap_cfunction(dst_stl_get));
|
||||
dst_env_def(env, "put", dst_wrap_cfunction(dst_stl_put));
|
||||
dst_env_def(env, "length", dst_wrap_cfunction(dst_stl_length));
|
||||
dst_env_def(env, "gccollect", dst_wrap_cfunction(dst_stl_gccollect));
|
||||
dst_env_def(env, "type", dst_wrap_cfunction(dst_stl_type));
|
||||
dst_env_def(env, "next", dst_wrap_cfunction(dst_stl_next));
|
||||
dst_env_def(env, "hash", dst_wrap_cfunction(dst_stl_hash));
|
||||
dst_env_def(env, "exit", dst_wrap_cfunction(dst_stl_exit));
|
||||
|
||||
dst_module_def(module, "parse", dst_wrap_cfunction(dst_parse_cfun));
|
||||
dst_module_def(module, "compile", dst_wrap_cfunction(dst_compile_cfun));
|
||||
dst_module_def(module, "asm", dst_wrap_cfunction(dst_asm_cfun));
|
||||
dst_module_def(module, "disasm", dst_wrap_cfunction(dst_disasm_cfun));
|
||||
dst_env_def(env, "compile", dst_wrap_cfunction(dst_compile_cfun));
|
||||
dst_env_def(env, "asm", dst_wrap_cfunction(dst_asm_cfun));
|
||||
dst_env_def(env, "disasm", dst_wrap_cfunction(dst_disasm_cfun));
|
||||
|
||||
/* Allow references to the environment */
|
||||
dst_module_def(module, "_env", ret);
|
||||
dst_env_def(env, "_env", ret);
|
||||
|
||||
/*Load auxiliary modules */
|
||||
dst_io_init(args);
|
||||
dst_math_init(args);
|
||||
/*Load auxiliary envs */
|
||||
{
|
||||
DstArgs args;
|
||||
args.n = 1;
|
||||
args.v = &ret;
|
||||
args.ret = &ret;
|
||||
dst_lib_io(args);
|
||||
dst_lib_math(args);
|
||||
dst_lib_array(args);
|
||||
dst_lib_buffer(args);
|
||||
dst_lib_parse(args);
|
||||
}
|
||||
|
||||
return ret;
|
||||
return env;
|
||||
}
|
||||
|
@ -217,6 +217,7 @@ static int32_t dst_escape_string_length(const uint8_t *str, int32_t slen) {
|
||||
case '\n':
|
||||
case '\r':
|
||||
case '\0':
|
||||
case '\\':
|
||||
len += 2;
|
||||
break;
|
||||
default:
|
||||
@ -249,6 +250,10 @@ static void dst_escape_string_impl(uint8_t *buf, const uint8_t *str, int32_t len
|
||||
buf[j++] = '\\';
|
||||
buf[j++] = '0';
|
||||
break;
|
||||
case '\\':
|
||||
buf[j++] = '\\';
|
||||
buf[j++] = '\\';
|
||||
break;
|
||||
default:
|
||||
buf[j++] = c;
|
||||
break;
|
||||
|
25
core/util.c
25
core/util.c
@ -108,23 +108,36 @@ int dst_cstrcmp(const uint8_t *str, const char *other) {
|
||||
}
|
||||
|
||||
/* Add a module definition */
|
||||
void dst_module_def(DstTable *module, const char *name, Dst val) {
|
||||
void dst_env_def(DstTable *env, const char *name, Dst val) {
|
||||
DstTable *subt = dst_table(1);
|
||||
dst_table_put(subt, dst_csymbolv("value"), val);
|
||||
dst_table_put(module, dst_csymbolv(name), dst_wrap_table(subt));
|
||||
dst_table_put(env, dst_csymbolv(name), dst_wrap_table(subt));
|
||||
}
|
||||
|
||||
/* Add a module var */
|
||||
void dst_module_var(DstTable *module, const char *name, Dst val) {
|
||||
/* Add a var to the environment */
|
||||
void dst_env_var(DstTable *env, const char *name, Dst val) {
|
||||
DstArray *array = dst_array(1);
|
||||
DstTable *subt = dst_table(1);
|
||||
dst_array_push(array, val);
|
||||
dst_table_put(subt, dst_csymbolv("ref"), dst_wrap_array(array));
|
||||
dst_table_put(module, dst_csymbolv(name), dst_wrap_table(subt));
|
||||
dst_table_put(env, dst_csymbolv(name), dst_wrap_table(subt));
|
||||
}
|
||||
|
||||
/* Resolve a symbol in the environment. Undefined symbols will
|
||||
* resolve to nil */
|
||||
Dst dst_env_resolve(DstTable *env, const char *name) {
|
||||
Dst ref;
|
||||
Dst entry = dst_table_get(env, dst_csymbolv(name));
|
||||
if (dst_checktype(entry, DST_NIL)) return dst_wrap_nil();
|
||||
ref = dst_get(entry, dst_csymbolv("ref"));
|
||||
if (dst_checktype(ref, DST_ARRAY)) {
|
||||
return dst_getindex(ref, 0);
|
||||
}
|
||||
return dst_get(entry, dst_csymbolv("value"));
|
||||
}
|
||||
|
||||
/* Get module from the arguments passed to library */
|
||||
DstTable *dst_get_module(DstArgs args) {
|
||||
DstTable *dst_env_arg(DstArgs args) {
|
||||
DstTable *module;
|
||||
if (args.n >= 1 && dst_checktype(args.v[0], DST_TABLE)) {
|
||||
module = dst_unwrap_table(args.v[0]);
|
||||
|
@ -61,6 +61,7 @@ const void *dst_strbinsearch(
|
||||
#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_empty(v) (((v) != NULL) ? (dst_v__cnt(v) = 0) : 0)
|
||||
#define dst_v_copy(v) (dst_v_copymem((v), sizeof(*(v))))
|
||||
#define dst_v_flatten(v) (dst_v_flattenmem((v), sizeof(*(v))))
|
||||
|
||||
|
@ -195,7 +195,7 @@
|
||||
|
||||
# Merge sort
|
||||
|
||||
# Impertiave merge sort merge
|
||||
# Imperative merge sort merge
|
||||
(def merge (fn [xs ys]
|
||||
(def ret [])
|
||||
(def xlen (length xs))
|
||||
@ -207,17 +207,17 @@
|
||||
(def xi (get xs i))
|
||||
(def yj (get ys j))
|
||||
(if (< xi yj)
|
||||
(do (push ret xi) (varset! i (+ i 1)))
|
||||
(do (push ret yj) (varset! j (+ j 1)))))
|
||||
(do (array-push ret xi) (varset! i (+ i 1)))
|
||||
(do (array-push ret yj) (varset! j (+ j 1)))))
|
||||
# Push rest of xs
|
||||
(while (< i xlen)
|
||||
(def xi (get xs i))
|
||||
(push ret xi)
|
||||
(array-push ret xi)
|
||||
(varset! i (+ i 1)))
|
||||
# Push rest of ys
|
||||
(while (< j ylen)
|
||||
(def yj (get ys j))
|
||||
(push ret yj)
|
||||
(array-push ret yj)
|
||||
(varset! j (+ j 1)))
|
||||
ret))
|
||||
|
||||
|
@ -139,14 +139,6 @@ void dst_fiber_funcframe_tail(DstFiber *fiber, DstFunction *func);
|
||||
void dst_fiber_cframe(DstFiber *fiber);
|
||||
void dst_fiber_popframe(DstFiber *fiber);
|
||||
|
||||
/* Assembly */
|
||||
DstAssembleResult dst_asm(DstAssembleOptions opts);
|
||||
DstFunction *dst_asm_func(DstAssembleResult result);
|
||||
Dst dst_disasm(DstFuncDef *def);
|
||||
Dst dst_asm_decode_instruction(uint32_t instr);
|
||||
int dst_asm_cfun(DstArgs args);
|
||||
int dst_disasm_cfun(DstArgs args);
|
||||
|
||||
/* Treat similar types through uniform interfaces for iteration */
|
||||
int dst_seq_view(Dst seq, const Dst **data, int32_t *len);
|
||||
int dst_chararray_view(Dst str, const uint8_t **data, int32_t *len);
|
||||
@ -163,6 +155,17 @@ int dst_equals(Dst x, Dst y);
|
||||
int32_t dst_hash(Dst x);
|
||||
int dst_compare(Dst x, Dst y);
|
||||
|
||||
/* GC */
|
||||
void dst_mark(Dst x);
|
||||
void dst_sweep();
|
||||
void dst_collect();
|
||||
void dst_clear_memory();
|
||||
void dst_gcroot(Dst root);
|
||||
int dst_gcunroot(Dst root);
|
||||
int dst_gcunrootall(Dst root);
|
||||
#define dst_maybe_collect() do {\
|
||||
if (dst_vm_next_collection >= dst_vm_gc_interval) dst_collect(); } while (0)
|
||||
|
||||
/* Data structure functions */
|
||||
Dst dst_get(Dst ds, Dst key);
|
||||
void dst_put(Dst ds, Dst key, Dst value);
|
||||
@ -178,11 +181,6 @@ DstAst *dst_ast_node(Dst x);
|
||||
Dst dst_ast_unwrap1(Dst x);
|
||||
Dst dst_ast_unwrap(Dst x);
|
||||
|
||||
/* Parsing */
|
||||
DstParseResult dst_parse(const uint8_t *src, int32_t len, int flags);
|
||||
DstParseResult dst_parsec(const char *src, int flags);
|
||||
int dst_parse_cfun(DstArgs args);
|
||||
|
||||
/* Native */
|
||||
DstCFunction dst_native(const char *name, const uint8_t **error);
|
||||
int dst_load_native(DstArgs args);
|
||||
@ -198,40 +196,89 @@ 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);
|
||||
|
||||
/* Module helpers */
|
||||
DstTable *dst_get_module(DstArgs args);
|
||||
void dst_module_def(DstTable *module, const char *name, Dst val);
|
||||
void dst_module_var(DstTable *module, const char *name, Dst val);
|
||||
|
||||
/* Context functions */
|
||||
void dst_context_init(DstContext *c, Dst env);
|
||||
void dst_context_deinit(DstContext *c);
|
||||
void dst_context_repl(DstContext *c, Dst env);
|
||||
int dst_context_run(DstContext *c);
|
||||
void dst_env_def(DstTable *env, const char *name, Dst val);
|
||||
void dst_env_var(DstTable *env, const char *name, Dst val);
|
||||
Dst dst_env_resolve(DstTable *env, const char *name);
|
||||
DstTable *dst_env_arg(DstArgs args);
|
||||
|
||||
/* C Function helpers */
|
||||
#define dst_throw(a, e) (*((a).ret) = dst_cstringv(e), 1)
|
||||
#define dst_throwv(a, v) (*((a).ret) = (v), 1)
|
||||
#define dst_return(a, v) (*((a).ret) = (v), 0)
|
||||
|
||||
/* Parsing */
|
||||
typedef enum DstParserStatus DstParserStatus;
|
||||
typedef struct DstParseState DstParseState;
|
||||
typedef struct DstParser DstParser;
|
||||
enum DstParserStatus {
|
||||
DST_PARSE_ROOT,
|
||||
DST_PARSE_ERROR,
|
||||
DST_PARSE_FULL,
|
||||
DST_PARSE_PENDING
|
||||
};
|
||||
struct DstParser {
|
||||
Dst* argstack;
|
||||
DstParseState *states;
|
||||
uint8_t *buf;
|
||||
const char *error;
|
||||
size_t index;
|
||||
int lookback;
|
||||
int flags;
|
||||
};
|
||||
#define DST_PARSEFLAG_SOURCEMAP 1
|
||||
void dst_parser_init(DstParser *parser, int flags);
|
||||
void dst_parser_deinit(DstParser *parser);
|
||||
int dst_parser_consume(DstParser *parser, uint8_t c);
|
||||
DstParserStatus dst_parser_status(DstParser *parser);
|
||||
Dst dst_parser_produce(DstParser *parser);
|
||||
const char *dst_parser_error(DstParser *parser);
|
||||
int dst_parse_cfun(DstArgs args);
|
||||
|
||||
/* Compile */
|
||||
DstCompileResult dst_compile(DstCompileOptions opts);
|
||||
typedef enum DstCompileStatus DstCompileStatus;
|
||||
typedef struct DstCompileOptions DstCompileOptions;
|
||||
typedef struct DstCompileResult DstCompileResult;
|
||||
enum DstCompileStatus {
|
||||
DST_COMPILE_OK,
|
||||
DST_COMPILE_ERROR
|
||||
};
|
||||
struct DstCompileResult {
|
||||
DstCompileStatus status;
|
||||
DstFuncDef *funcdef;
|
||||
const uint8_t *error;
|
||||
int32_t error_start;
|
||||
int32_t error_end;
|
||||
};
|
||||
DstCompileResult dst_compile(Dst source, DstTable *env, int flags);
|
||||
DstFunction *dst_compile_func(DstCompileResult result);
|
||||
int dst_compile_cfun(DstArgs args);
|
||||
|
||||
/* STL */
|
||||
Dst dst_stl_env();
|
||||
int dst_io_init(DstArgs args);
|
||||
int dst_math_init(DstArgs args);
|
||||
/* Assembly */
|
||||
typedef enum DstAssembleStatus DstAssembleStatus;
|
||||
typedef struct DstAssembleResult DstAssembleResult;
|
||||
typedef struct DstAssembleOptions DstAssembleOptions;
|
||||
enum DstAssembleStatus {
|
||||
DST_ASSEMBLE_OK,
|
||||
DST_ASSEMBLE_ERROR
|
||||
};
|
||||
struct DstAssembleResult {
|
||||
DstFuncDef *funcdef;
|
||||
const uint8_t *error;
|
||||
DstAssembleStatus status;
|
||||
};
|
||||
DstAssembleResult dst_asm(Dst source, int flags);
|
||||
DstFunction *dst_asm_func(DstAssembleResult result);
|
||||
Dst dst_disasm(DstFuncDef *def);
|
||||
Dst dst_asm_decode_instruction(uint32_t instr);
|
||||
int dst_asm_cfun(DstArgs args);
|
||||
int dst_disasm_cfun(DstArgs args);
|
||||
|
||||
/* GC */
|
||||
void dst_mark(Dst x);
|
||||
void dst_sweep();
|
||||
void dst_collect();
|
||||
void dst_clear_memory();
|
||||
void dst_gcroot(Dst root);
|
||||
int dst_gcunroot(Dst root);
|
||||
int dst_gcunrootall(Dst root);
|
||||
#define dst_maybe_collect() do {\
|
||||
if (dst_vm_next_collection >= dst_vm_gc_interval) dst_collect(); } while (0)
|
||||
/* STL */
|
||||
DstTable *dst_stl_env();
|
||||
int dst_lib_io(DstArgs args);
|
||||
int dst_lib_math(DstArgs args);
|
||||
int dst_lib_array(DstArgs args);
|
||||
int dst_lib_buffer(DstArgs args);
|
||||
int dst_lib_parse(DstArgs args);
|
||||
|
||||
#endif /* DST_H_defined */
|
||||
|
@ -24,7 +24,6 @@
|
||||
#define DST_CONFIG_H_defined
|
||||
|
||||
#include <stdint.h>
|
||||
#include "dst.h"
|
||||
|
||||
/*
|
||||
* Detect OS and endianess.
|
||||
|
@ -23,7 +23,6 @@
|
||||
#ifndef DST_TYPES_H_defined
|
||||
#define DST_TYPES_H_defined
|
||||
|
||||
#include <stdint.h>
|
||||
#include "dstconfig.h"
|
||||
|
||||
#ifdef DST_NANBOX
|
||||
@ -48,18 +47,8 @@ typedef struct DstStackFrame DstStackFrame;
|
||||
typedef struct DstAbstractType DstAbstractType;
|
||||
typedef struct DstArgs DstArgs;
|
||||
typedef struct DstAst DstAst;
|
||||
typedef struct DstContext DstContext;
|
||||
typedef int (*DstCFunction)(DstArgs args);
|
||||
|
||||
typedef enum DstAssembleStatus DstAssembleStatus;
|
||||
typedef struct DstAssembleResult DstAssembleResult;
|
||||
typedef struct DstAssembleOptions DstAssembleOptions;
|
||||
typedef enum DstCompileStatus DstCompileStatus;
|
||||
typedef struct DstCompileOptions DstCompileOptions;
|
||||
typedef struct DstCompileResult DstCompileResult;
|
||||
typedef struct DstParseResult DstParseResult;
|
||||
typedef enum DstParseStatus DstParseStatus;
|
||||
|
||||
/* Basic types for all Dst Values */
|
||||
typedef enum DstType {
|
||||
DST_NIL,
|
||||
@ -424,42 +413,7 @@ struct DstAbstractHeader {
|
||||
size_t size;
|
||||
};
|
||||
|
||||
/* Assemble structs */
|
||||
enum DstAssembleStatus {
|
||||
DST_ASSEMBLE_OK,
|
||||
DST_ASSEMBLE_ERROR
|
||||
};
|
||||
|
||||
struct DstAssembleOptions {
|
||||
Dst source;
|
||||
uint32_t flags;
|
||||
};
|
||||
|
||||
struct DstAssembleResult {
|
||||
DstFuncDef *funcdef;
|
||||
const uint8_t *error;
|
||||
DstAssembleStatus status;
|
||||
};
|
||||
|
||||
/* Compile structs */
|
||||
enum DstCompileStatus {
|
||||
DST_COMPILE_OK,
|
||||
DST_COMPILE_ERROR
|
||||
};
|
||||
|
||||
struct DstCompileResult {
|
||||
DstCompileStatus status;
|
||||
DstFuncDef *funcdef;
|
||||
const uint8_t *error;
|
||||
int32_t error_start;
|
||||
int32_t error_end;
|
||||
};
|
||||
|
||||
struct DstCompileOptions {
|
||||
uint32_t flags;
|
||||
Dst source;
|
||||
Dst env;
|
||||
};
|
||||
|
||||
/* ASTs are simple wrappers around values. They contain information about sourcemapping
|
||||
* and other meta data. Possibly types? They are used mainly during compilation and parsing */
|
||||
@ -470,41 +424,4 @@ struct DstAst {
|
||||
int flags;
|
||||
};
|
||||
|
||||
#define DST_PARSEFLAG_SOURCEMAP 1
|
||||
|
||||
/* Parse structs */
|
||||
enum DstParseStatus {
|
||||
DST_PARSE_OK,
|
||||
DST_PARSE_ERROR,
|
||||
DST_PARSE_UNEXPECTED_EOS,
|
||||
DST_PARSE_NODATA
|
||||
};
|
||||
|
||||
struct DstParseResult {
|
||||
Dst value;
|
||||
const uint8_t *error;
|
||||
int32_t bytes_read;
|
||||
DstParseStatus status;
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
DST_CONTEXT_ERROR_PARSE,
|
||||
DST_CONTEXT_ERROR_COMPILE,
|
||||
DST_CONTEXT_ERROR_RUNTIME
|
||||
} DstContextErrorType;
|
||||
|
||||
/* Evaluation context. Encapsulates parsing and compiling for easier integration
|
||||
* with client programs. */
|
||||
struct DstContext {
|
||||
Dst env;
|
||||
DstBuffer buffer;
|
||||
size_t flushed_bytes;
|
||||
void *user;
|
||||
|
||||
void (*read_chunk)(DstContext *self);
|
||||
void (*on_error)(DstContext *self, DstContextErrorType type, Dst err, size_t start, size_t end);
|
||||
void (*on_value)(DstContext *self, Dst value);
|
||||
void (*deinit)(DstContext *self);
|
||||
};
|
||||
|
||||
#endif /* DST_TYPES_H_defined */
|
||||
|
Loading…
Reference in New Issue
Block a user