1
0
mirror of https://github.com/janet-lang/janet synced 2024-11-28 02:59:54 +00:00

Redo parser as a FSM. Again.

This commit is contained in:
bakpakin 2018-01-18 17:25:45 -05:00
parent 8e6ed707e7
commit 0531866954
20 changed files with 827 additions and 800 deletions

View File

@ -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

View File

@ -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();

View File

@ -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;
}

View File

@ -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 {

View File

@ -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;
}

View File

@ -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));

View File

@ -104,7 +104,7 @@ struct DstCompiler {
int32_t *mapbuffer;
/* Hold the environment */
Dst env;
DstTable *env;
DstCompileResult result;
};

View File

@ -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);

View File

@ -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;
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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]);

View File

@ -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))))

View File

@ -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))

View File

@ -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 */

View File

@ -24,7 +24,6 @@
#define DST_CONFIG_H_defined
#include <stdint.h>
#include "dst.h"
/*
* Detect OS and endianess.

View File

@ -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 */