Add context functions for more uniform interface

This commit is contained in:
bakpakin 2018-01-16 23:18:45 -05:00
parent 23196ff6a2
commit d373d38aee
15 changed files with 684 additions and 519 deletions

View File

@ -31,7 +31,7 @@ CLIBS=-lm -ldl
PREFIX=/usr/local
DST_TARGET=dst
DEBUGGER=lldb
DST_INTERNAL_HEADERS=$(addprefix core/,symcache.h opcodes.h compile.h gc.h sourcemap.h util.h)
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_C_LIBS=$(addprefix libs/,testlib.so)
@ -48,8 +48,8 @@ all: $(DST_TARGET)
###################################
DST_CORE_SOURCES=$(addprefix core/,\
abstract.c array.c asm.c buffer.c compile.c compile_specials.c\
fiber.c gc.c io.c math.c native.c parse.c sourcemap.c string.c\
abstract.c array.c asm.c ast.c buffer.c compile.c compile_specials.c\
context.c fiber.c gc.c io.c math.c native.c parse.c string.c\
stl.c strtod.c struct.c symcache.c table.c tuple.c util.c\
value.c vm.c wrap.c)

View File

@ -117,7 +117,6 @@ static int repl() {
{
opts.source = res.value;
opts.flags = 0;
opts.sourcemap = res.map;
opts.env = env;
cres = dst_compile(opts);
if (cres.status == DST_COMPILE_OK) {
@ -167,7 +166,6 @@ static void runfile(const uint8_t *src, int32_t len) {
{
opts.source = res.value;
opts.flags = 0;
opts.sourcemap = res.map;
opts.env = env;
cres = dst_compile(opts);
if (cres.status == DST_COMPILE_OK) {
@ -290,7 +288,9 @@ int main(int argc, char **argv) {
/* Run a repl if nothing else happened, or the flag is set */
if (!fileRead || (flags & DST_CLIENT_REPL)) {
status = repl();
DstContext ctxt;
dst_context_repl(&ctxt, env);
status = dst_context_run(&ctxt);
}
dst_deinit();

View File

@ -25,7 +25,6 @@
#include <dst/dst.h>
#include "opcodes.h"
#include "gc.h"
#include "sourcemap.h"
#include "util.h"
/* Bytecode op argument types */

186
core/ast.c Normal file
View File

@ -0,0 +1,186 @@
/*
* Copyright (c) 2017 Calvin Rose
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include <dst/dst.h>
/* Mark an ast node */
static int dst_ast_gcmark(void *p, size_t size) {
DstAst *ast = (DstAst *)p;
(void) size;
dst_mark(ast->value);
return 0;
}
/* AST type */
static DstAbstractType dst_ast_type = {
"ast",
NULL,
dst_ast_gcmark
};
/* Create an ast type */
Dst dst_ast_wrap(Dst x, int32_t start, int32_t end) {
DstAst *ast = dst_abstract(&dst_ast_type, sizeof(DstAst));
ast->value = x;
ast->source_start = start;
ast->source_end = end;
ast->flags = 1 << dst_type(x);
return dst_wrap_abstract(ast);
}
/* Get the node associated with a value */
DstAst *dst_ast_node(Dst x) {
if (dst_checktype(x, DST_ABSTRACT) &&
dst_abstract_type(dst_unwrap_abstract(x)) == &dst_ast_type) {
DstAst *ast = (DstAst *)dst_unwrap_abstract(x);
return ast;
}
return NULL;
}
/* Unwrap an ast value one level deep */
Dst dst_ast_unwrap1(Dst x) {
if (dst_checktype(x, DST_ABSTRACT) &&
dst_abstract_type(dst_unwrap_abstract(x)) == &dst_ast_type) {
DstAst *ast = (DstAst *)dst_unwrap_abstract(x);
return ast->value;
}
return x;
}
Dst dst_ast_unwrap(Dst x);
static Dst astunwrap_array(DstArray *other) {
DstArray *array;
Dst diffval;
int32_t i, prescan;
for (prescan = 0; prescan < other->count; prescan++) {
diffval = dst_ast_unwrap(other->data[prescan]);
if (!dst_equals(diffval, other->data[prescan])) break;
}
if (prescan == other->count) return dst_wrap_array(other);
array = dst_array(other->count);
for (i = 0; i < prescan; i++) {
array->data[i] = other->data[i];
}
array->data[prescan] = diffval;
for (i = prescan + 1; i < other->count; i++) {
array->data[i] = dst_ast_unwrap(other->data[i]);
}
array->count = other->count;
return dst_wrap_array(array);
}
static Dst astunwrap_tuple(const Dst *other) {
Dst *tuple;
int32_t i, prescan;
Dst diffval;
for (prescan = 0; prescan < dst_tuple_length(other); prescan++) {
diffval = dst_ast_unwrap(other[prescan]);
if (!dst_equals(diffval, other[prescan])) break;
}
if (prescan == dst_tuple_length(other)) return dst_wrap_tuple(other);
tuple = dst_tuple_begin(dst_tuple_length(other));
for (i = 0; i < prescan; i++) {
tuple[i] = other[i];
}
tuple[prescan] = diffval;
for (i = prescan + 1; i < dst_tuple_length(other); i++) {
tuple[i] = dst_ast_unwrap(other[i]);
}
return dst_wrap_tuple(dst_tuple_end(tuple));
}
static Dst astunwrap_struct(const DstKV *other) {
DstKV *st;
const DstKV *prescan, *iter;
Dst diffval, diffkey;
prescan = NULL;
while ((prescan = dst_struct_next(other, prescan))) {
diffkey = dst_ast_unwrap(prescan->key);
diffval = dst_ast_unwrap(prescan->value);
if (!dst_equals(diffkey, prescan->key) ||
!dst_equals(diffval, prescan->value))
break;
}
if (!prescan) return dst_wrap_struct(other);
st = dst_struct_begin(dst_struct_length(other));
iter = NULL;
while ((iter = dst_struct_next(other, iter))) {
if (iter == prescan) break;
dst_struct_put(st, iter->key, iter->value);
}
dst_struct_put(st, diffkey, diffval);
while ((iter = dst_struct_next(other, iter))) {
dst_struct_put(st,
dst_ast_unwrap(iter->key),
dst_ast_unwrap(iter->value));
}
return dst_wrap_struct(dst_struct_end(st));
}
static Dst astunwrap_table(DstTable *other) {
DstTable *table;
const DstKV *prescan, *iter;
Dst diffval, diffkey;
prescan = NULL;
while ((prescan = dst_table_next(other, prescan))) {
diffkey = dst_ast_unwrap(prescan->key);
diffval = dst_ast_unwrap(prescan->value);
if (!dst_equals(diffkey, prescan->key) ||
!dst_equals(diffval, prescan->value))
break;
}
if (!prescan) return dst_wrap_table(other);
table = dst_table(other->capacity);
iter = NULL;
while ((iter = dst_table_next(other, iter))) {
if (iter == prescan) break;
dst_table_put(table, iter->key, iter->value);
}
dst_table_put(table, diffkey, diffval);
while ((iter = dst_table_next(other, iter))) {
dst_table_put(table,
dst_ast_unwrap(iter->key),
dst_ast_unwrap(iter->value));
}
return dst_wrap_table(table);
}
/* Unwrap an ast value recursively. Preserve as much structure as possible
* to avoid unecessary allocation. */
Dst dst_ast_unwrap(Dst x) {
x = dst_ast_unwrap1(x);
switch (dst_type(x)) {
default:
return x;
case DST_ARRAY:
return astunwrap_array(dst_unwrap_array(x));
case DST_TUPLE:
return astunwrap_tuple(dst_unwrap_tuple(x));
case DST_STRUCT:
return astunwrap_struct(dst_unwrap_struct(x));
case DST_TABLE:
return astunwrap_table(dst_unwrap_table(x));
}
}

View File

@ -24,18 +24,25 @@
#include <dst/dststl.h>
#include "compile.h"
#include "gc.h"
#include "sourcemap.h"
#include "util.h"
DstFopts dstc_fopts_default(DstCompiler *c) {
DstFopts ret;
ret.compiler = c;
ret.flags = 0;
ret.hint = dstc_cslot(dst_wrap_nil());
return ret;
}
/* Throw an error with a dst string. */
void dstc_error(DstCompiler *c, const Dst *sourcemap, const uint8_t *m) {
void dstc_error(DstCompiler *c, DstAst *ast, const uint8_t *m) {
/* Don't override first error */
if (c->result.status == DST_COMPILE_ERROR) {
return;
}
if (NULL != sourcemap) {
c->result.error_start = dst_unwrap_integer(sourcemap[0]);
c->result.error_end = dst_unwrap_integer(sourcemap[1]);
if (NULL != ast) {
c->result.error_start = ast->source_start;
c->result.error_end = ast->source_end;
} else {
c->result.error_start = -1;
c->result.error_end = -1;
@ -45,38 +52,8 @@ void dstc_error(DstCompiler *c, const Dst *sourcemap, const uint8_t *m) {
}
/* Throw an error with a message in a cstring */
void dstc_cerror(DstCompiler *c, const Dst *sourcemap, const char *m) {
dstc_error(c, sourcemap, dst_cstring(m));
}
/* Use these to get sub options. They will traverse the source map so
* compiler errors make sense. Then modify the returned options. */
DstFopts dstc_getindex(DstFopts opts, int32_t index) {
const Dst *sourcemap = dst_sourcemap_index(opts.sourcemap, index);
Dst nextval = dst_getindex(opts.x, index);
opts.x = nextval;
opts.flags = 0;
opts.sourcemap = sourcemap;
return opts;
}
/* Index into the key of a table or struct */
DstFopts dstc_getkey(DstFopts opts, Dst key) {
const Dst *sourcemap = dst_sourcemap_key(opts.sourcemap, key);
opts.x = key;
opts.sourcemap = sourcemap;
opts.flags = 0;
return opts;
}
/* Index into the value of a table or struct */
DstFopts dstc_getvalue(DstFopts opts, Dst key) {
const Dst *sourcemap = dst_sourcemap_value(opts.sourcemap, key);
Dst nextval = dst_get(opts.x, key);
opts.x = nextval;
opts.sourcemap = sourcemap;
opts.flags = 0;
return opts;
void dstc_cerror(DstCompiler *c, DstAst *ast, const char *m) {
dstc_error(c, ast, dst_cstring(m));
}
/* Check error */
@ -229,7 +206,7 @@ DstSlot dstc_cslot(Dst x) {
/* Allow searching for symbols. Return information about the symbol */
DstSlot dstc_resolve(
DstCompiler *c,
const Dst *sourcemap,
DstAst *ast,
const uint8_t *sym) {
DstSlot ret = dstc_cslot(dst_wrap_nil());
@ -261,7 +238,7 @@ DstSlot dstc_resolve(
Dst check = dst_get(c->env, dst_wrap_symbol(sym));
Dst ref;
if (!(dst_checktype(check, DST_STRUCT) || dst_checktype(check, DST_TABLE))) {
dstc_error(c, sourcemap, dst_formatc("unknown symbol %q", sym));
dstc_error(c, ast, dst_formatc("unknown symbol %q", sym));
return dstc_cslot(dst_wrap_nil());
}
ref = dst_get(check, dst_csymbolv("ref"));
@ -331,11 +308,11 @@ DstSlot dstc_resolve(
}
/* Emit a raw instruction with source mapping. */
void dstc_emit(DstCompiler *c, const Dst *sourcemap, uint32_t instr) {
void dstc_emit(DstCompiler *c, DstAst *ast, uint32_t instr) {
dst_v_push(c->buffer, instr);
if (NULL != sourcemap) {
dst_v_push(c->mapbuffer, dst_unwrap_integer(sourcemap[0]));
dst_v_push(c->mapbuffer, dst_unwrap_integer(sourcemap[1]));
if (NULL != ast) {
dst_v_push(c->mapbuffer, ast->source_start);
dst_v_push(c->mapbuffer, ast->source_end);
} else {
dst_v_push(c->mapbuffer, -1);
dst_v_push(c->mapbuffer, -1);
@ -343,7 +320,7 @@ void dstc_emit(DstCompiler *c, const Dst *sourcemap, uint32_t instr) {
}
/* Add a constant to the current scope. Return the index of the constant. */
static int32_t dstc_const(DstCompiler *c, const Dst *sourcemap, Dst x) {
static int32_t dstc_const(DstCompiler *c, DstAst *ast, Dst x) {
DstScope *scope = &dst_v_last(c->scopes);
int32_t i, len;
/* Get the topmost function scope */
@ -360,7 +337,7 @@ static int32_t dstc_const(DstCompiler *c, const Dst *sourcemap, Dst x) {
}
/* Ensure not too many constsants. */
if (len >= 0xFFFF) {
dstc_cerror(c, sourcemap, "too many constants");
dstc_cerror(c, ast, "too many constants");
return 0;
}
dst_v_push(scope->consts, x);
@ -368,22 +345,22 @@ static int32_t dstc_const(DstCompiler *c, const Dst *sourcemap, Dst x) {
}
/* Load a constant into a local slot */
static void dstc_loadconst(DstCompiler *c, const Dst *sourcemap, Dst k, int32_t dest) {
static void dstc_loadconst(DstCompiler *c, DstAst *ast, Dst k, int32_t dest) {
switch (dst_type(k)) {
case DST_NIL:
dstc_emit(c, sourcemap, (dest << 8) | DOP_LOAD_NIL);
dstc_emit(c, ast, (dest << 8) | DOP_LOAD_NIL);
break;
case DST_TRUE:
dstc_emit(c, sourcemap, (dest << 8) | DOP_LOAD_TRUE);
dstc_emit(c, ast, (dest << 8) | DOP_LOAD_TRUE);
break;
case DST_FALSE:
dstc_emit(c, sourcemap, (dest << 8) | DOP_LOAD_FALSE);
dstc_emit(c, ast, (dest << 8) | DOP_LOAD_FALSE);
break;
case DST_INTEGER:
{
int32_t i = dst_unwrap_integer(k);
if (i <= INT16_MAX && i >= INT16_MIN) {
dstc_emit(c, sourcemap,
dstc_emit(c, ast,
(i << 16) |
(dest << 8) |
DOP_LOAD_INTEGER);
@ -393,8 +370,8 @@ static void dstc_loadconst(DstCompiler *c, const Dst *sourcemap, Dst k, int32_t
}
default:
{
int32_t cindex = dstc_const(c, sourcemap, k);
dstc_emit(c, sourcemap,
int32_t cindex = dstc_const(c, ast, k);
dstc_emit(c, ast,
(cindex << 16) |
(dest << 8) |
DOP_LOAD_CONSTANT);
@ -407,7 +384,7 @@ static void dstc_loadconst(DstCompiler *c, const Dst *sourcemap, Dst k, int32_t
* that can be used in an instruction. */
int32_t dstc_preread(
DstCompiler *c,
const Dst *sourcemap,
DstAst *ast,
int32_t max,
int nth,
DstSlot s) {
@ -419,24 +396,24 @@ int32_t dstc_preread(
if (s.flags & (DST_SLOT_CONSTANT | DST_SLOT_REF)) {
ret = dstc_lslotn(c, 0xFF, nth);
dstc_loadconst(c, sourcemap, s.constant, ret);
dstc_loadconst(c, ast, s.constant, ret);
/* If we also are a reference, deref the one element array */
if (s.flags & DST_SLOT_REF) {
dstc_emit(c, sourcemap,
dstc_emit(c, ast,
(ret << 16) |
(ret << 8) |
DOP_GET_INDEX);
}
} else if (s.envindex > 0 || s.index > max) {
ret = dstc_lslotn(c, max, nth);
dstc_emit(c, sourcemap,
dstc_emit(c, ast,
((uint32_t)(s.index) << 24) |
((uint32_t)(s.envindex) << 16) |
((uint32_t)(ret) << 8) |
DOP_LOAD_UPVALUE);
} else if (s.index > max) {
ret = dstc_lslotn(c, max, nth);
dstc_emit(c, sourcemap,
dstc_emit(c, ast,
((uint32_t)(s.index) << 16) |
((uint32_t)(ret) << 8) |
DOP_MOVE_NEAR);
@ -473,7 +450,7 @@ int dstc_sequal(DstSlot lhs, DstSlot rhs) {
* be writeable (not a literal). */
void dstc_copy(
DstCompiler *c,
const Dst *sourcemap,
DstAst *ast,
DstSlot dest,
DstSlot src) {
int writeback = 0;
@ -483,7 +460,7 @@ void dstc_copy(
/* Can't write to constants */
if (dest.flags & DST_SLOT_CONSTANT) {
dstc_cerror(c, sourcemap, "cannot write to constant");
dstc_cerror(c, ast, "cannot write to constant");
return;
}
@ -506,21 +483,21 @@ void dstc_copy(
/* If dest is a near index, do some optimization */
if (dest.envindex == 0 && dest.index >= 0 && dest.index <= 0xFF) {
if (src.flags & DST_SLOT_CONSTANT) {
dstc_loadconst(c, sourcemap, src.constant, dest.index);
dstc_loadconst(c, ast, src.constant, dest.index);
} else if (src.flags & DST_SLOT_REF) {
dstc_loadconst(c, sourcemap, src.constant, dest.index);
dstc_emit(c, sourcemap,
dstc_loadconst(c, ast, src.constant, dest.index);
dstc_emit(c, ast,
(dest.index << 16) |
(dest.index << 8) |
DOP_GET_INDEX);
} else if (src.envindex > 0) {
dstc_emit(c, sourcemap,
dstc_emit(c, ast,
(src.index << 24) |
(src.envindex << 16) |
(dest.index << 8) |
DOP_LOAD_UPVALUE);
} else {
dstc_emit(c, sourcemap,
dstc_emit(c, ast,
(src.index << 16) |
(dest.index << 8) |
DOP_MOVE_NEAR);
@ -531,15 +508,15 @@ void dstc_copy(
/* Process: src -> srclocal -> destlocal -> dest */
/* src -> srclocal */
srclocal = dstc_preread(c, sourcemap, 0xFF, 1, src);
srclocal = dstc_preread(c, ast, 0xFF, 1, src);
/* Pull down dest (find destlocal) */
if (dest.flags & DST_SLOT_REF) {
writeback = 1;
destlocal = srclocal;
reflocal = dstc_lslotn(c, 0xFF, 2);
dstc_emit(c, sourcemap,
(dstc_const(c, sourcemap, dest.constant) << 16) |
dstc_emit(c, ast,
(dstc_const(c, ast, dest.constant) << 16) |
(reflocal << 8) |
DOP_LOAD_CONSTANT);
} else if (dest.envindex > 0) {
@ -554,7 +531,7 @@ void dstc_copy(
/* srclocal -> destlocal */
if (srclocal != destlocal) {
dstc_emit(c, sourcemap,
dstc_emit(c, ast,
((uint32_t)(srclocal) << 16) |
((uint32_t)(destlocal) << 8) |
DOP_MOVE_NEAR);
@ -562,18 +539,18 @@ void dstc_copy(
/* destlocal -> dest */
if (writeback == 1) {
dstc_emit(c, sourcemap,
dstc_emit(c, ast,
(destlocal << 16) |
(reflocal << 8) |
DOP_PUT_INDEX);
} else if (writeback == 2) {
dstc_emit(c, sourcemap,
dstc_emit(c, ast,
((uint32_t)(dest.index) << 24) |
((uint32_t)(dest.envindex) << 16) |
((uint32_t)(destlocal) << 8) |
DOP_SET_UPVALUE);
} else if (writeback == 3) {
dstc_emit(c, sourcemap,
dstc_emit(c, ast,
((uint32_t)(dest.index) << 16) |
((uint32_t)(destlocal) << 8) |
DOP_MOVE_FAR);
@ -587,13 +564,13 @@ void dstc_copy(
}
/* Generate the return instruction for a slot. */
DstSlot dstc_return(DstCompiler *c, const Dst *sourcemap, DstSlot s) {
DstSlot dstc_return(DstCompiler *c, DstAst *ast, DstSlot s) {
if (!(s.flags & DST_SLOT_RETURNED)) {
if (s.flags & DST_SLOT_CONSTANT && dst_checktype(s.constant, DST_NIL)) {
dstc_emit(c, sourcemap, DOP_RETURN_NIL);
dstc_emit(c, ast, DOP_RETURN_NIL);
} else {
int32_t ls = dstc_preread(c, sourcemap, 0xFFFF, 1, s);
dstc_emit(c, sourcemap, DOP_RETURN | (ls << 8));
int32_t ls = dstc_preread(c, ast, 0xFFFF, 1, s);
dstc_emit(c, ast, DOP_RETURN | (ls << 8));
dstc_postread(c, s, ls);
}
s.flags |= DST_SLOT_RETURNED;
@ -619,32 +596,30 @@ DstSlot dstc_gettarget(DstFopts opts) {
}
/* Get a bunch of slots for function arguments */
DstSM *dstc_toslots(DstFopts opts, int32_t start) {
int32_t i, len;
DstSM *dstc_toslots(DstCompiler *c, const Dst *vals, int32_t len) {
int32_t i;
DstSM *ret = NULL;
len = dst_length(opts.x);
for (i = start; i < len; i++) {
DstFopts subopts = dstc_fopts_default(c);
for (i = 0; i < len; i++) {
DstSM sm;
DstFopts subopts = dstc_getindex(opts, i);
sm.slot = dstc_value(subopts);
sm.map = subopts.sourcemap;
sm.slot = dstc_value(subopts, vals[i]);
sm.map = dst_ast_node(vals[i]);
dst_v_push(ret, sm);
}
return ret;
}
/* Get a bunch of slots for function arguments */
DstSM *dstc_toslotskv(DstFopts opts) {
DstSM *dstc_toslotskv(DstCompiler *c, Dst ds) {
DstSM *ret = NULL;
const DstKV *kv = NULL;
while (NULL != (kv = dst_next(opts.x, kv))) {
DstFopts subopts = dstc_fopts_default(c);
while ((kv = dst_next(ds, kv))) {
DstSM km, vm;
DstFopts kopts = dstc_getkey(opts, kv->key);
DstFopts vopts = dstc_getvalue(opts, kv->key);
km.slot = dstc_value(kopts);
km.map = kopts.sourcemap;
vm.slot = dstc_value(vopts);
vm.map = vopts.sourcemap;
km.slot = dstc_value(subopts, kv->key);
km.map = dst_ast_node(kv->key);
vm.slot = dstc_value(subopts, kv->value);
vm.map = dst_ast_node(kv->value);
dst_v_push(ret, km);
dst_v_push(ret, vm);
}
@ -652,15 +627,13 @@ DstSM *dstc_toslotskv(DstFopts opts) {
}
/* Push slots load via dstc_toslots. */
void dstc_pushslots(DstFopts opts, DstSM *sms) {
DstCompiler *c = opts.compiler;
const Dst *sm = opts.sourcemap;
void dstc_pushslots(DstCompiler *c, DstAst *ast, DstSM *sms) {
int32_t i;
for (i = 0; i < dst_v_count(sms) - 2; i += 3) {
int32_t ls1 = dstc_preread(c, sms[i].map, 0xFF, 1, sms[i].slot);
int32_t ls2 = dstc_preread(c, sms[i + 1].map, 0xFF, 2, sms[i + 1].slot);
int32_t ls3 = dstc_preread(c, sms[i + 2].map, 0xFF, 3, sms[i + 2].slot);
dstc_emit(c, sm,
dstc_emit(c, ast,
(ls3 << 24) |
(ls2 << 16) |
(ls1 << 8) |
@ -672,7 +645,7 @@ void dstc_pushslots(DstFopts opts, DstSM *sms) {
if (i == dst_v_count(sms) - 2) {
int32_t ls1 = dstc_preread(c, sms[i].map, 0xFF, 1, sms[i].slot);
int32_t ls2 = dstc_preread(c, sms[i + 1].map, 0xFFFF, 2, sms[i + 1].slot);
dstc_emit(c, sm,
dstc_emit(c, ast,
(ls2 << 16) |
(ls1 << 8) |
DOP_PUSH_2);
@ -680,7 +653,7 @@ void dstc_pushslots(DstFopts opts, DstSM *sms) {
dstc_postread(c, sms[i + 1].slot, ls2);
} else if (i == dst_v_count(sms) - 1) {
int32_t ls1 = dstc_preread(c, sms[i].map, 0xFFFFFF, 1, sms[i].slot);
dstc_emit(c, sm,
dstc_emit(c, ast,
(ls1 << 8) |
DOP_PUSH);
dstc_postread(c, sms[i].slot, ls1);
@ -688,10 +661,10 @@ void dstc_pushslots(DstFopts opts, DstSM *sms) {
}
/* Free slots loaded via dstc_toslots */
void dstc_freeslots(DstFopts opts, DstSM *sms) {
void dstc_freeslots(DstCompiler *c, DstSM *sms) {
int32_t i;
for (i = 0; i < dst_v_count(sms); i++) {
dstc_freeslot(opts.compiler, sms[i].slot);
dstc_freeslot(c, sms[i].slot);
}
dst_v_free(sms);
}
@ -699,108 +672,117 @@ void dstc_freeslots(DstFopts opts, DstSM *sms) {
/* Compile some code that will be thrown away. Used to ensure
* that dead code is well formed without including it in the final
* bytecode. */
void dstc_throwaway(DstFopts opts) {
void dstc_throwaway(DstFopts opts, Dst x) {
DstCompiler *c = opts.compiler;
int32_t bufstart = dst_v_count(c->buffer);
int32_t mapbufstart = dst_v_count(c->mapbuffer);
dstc_scope(c, DST_SCOPE_UNUSED);
dstc_value(opts);
dstc_value(opts, x);
dstc_popscope(c);
if (NULL != c->buffer) {
dst_v__cnt(c->buffer) = bufstart;
if (NULL != c->mapbuffer)
dst_v__cnt(c->mapbuffer) = bufstart;
dst_v__cnt(c->mapbuffer) = mapbufstart;
}
}
/* Compile a call or tailcall instruction */
static DstSlot dstc_call(DstFopts opts, DstSM *sms, DstSlot fun) {
static DstSlot dstc_call(DstFopts opts, DstAst *ast, DstSM *sms, DstSlot fun) {
DstSlot retslot;
int32_t localindex;
DstCompiler *c = opts.compiler;
const Dst *sm = opts.sourcemap;
dstc_pushslots(opts, sms);
dstc_freeslots(opts, sms);
localindex = dstc_preread(c, sm, 0xFF, 1, fun);
dstc_pushslots(c, ast, sms);
dstc_freeslots(c, sms);
localindex = dstc_preread(c, ast, 0xFF, 1, fun);
if (opts.flags & DST_FOPTS_TAIL) {
dstc_emit(c, sm, (localindex << 8) | DOP_TAILCALL);
dstc_emit(c, ast, (localindex << 8) | DOP_TAILCALL);
retslot = dstc_cslot(dst_wrap_nil());
retslot.flags = DST_SLOT_RETURNED;
} else {
retslot = dstc_gettarget(opts);
dstc_emit(c, sm, (localindex << 16) | (retslot.index << 8) | DOP_CALL);
dstc_emit(c, ast, (localindex << 16) | (retslot.index << 8) | DOP_CALL);
}
dstc_postread(c, fun, localindex);
return retslot;
}
/* Compile a tuple */
DstSlot dstc_tuple(DstFopts opts) {
DstSlot dstc_tuple(DstFopts opts, DstAst *ast, Dst x) {
Dst headval;
DstSlot head;
DstFopts subopts;
const Dst *tup = dst_unwrap_tuple(opts.x);
DstCompiler *c = opts.compiler;
DstFopts subopts = dstc_fopts_default(c);
const Dst *tup = dst_unwrap_tuple(x);
/* Empty tuple is tuple literal */
if (dst_tuple_length(tup) == 0) return dstc_cslot(opts.x);
if (dst_tuple_length(tup) == 0) return dstc_cslot(x);
/* Symbols could be specials */
if (dst_checktype(tup[0], DST_SYMBOL)) {
const DstSpecial *s = dstc_special(dst_unwrap_symbol(tup[0]));
headval = dst_ast_unwrap1(tup[0]);
if (dst_checktype(headval, DST_SYMBOL)) {
const DstSpecial *s = dstc_special(dst_unwrap_symbol(headval));
if (NULL != s) {
return s->compile(opts, dst_tuple_length(tup) - 1, tup + 1);
return s->compile(opts, ast, dst_tuple_length(tup) - 1, tup + 1);
}
}
/* Compile the head of the tuple */
subopts = dstc_getindex(opts, 0);
subopts.flags = DST_FUNCTION | DST_CFUNCTION;
head = dstc_value(subopts);
return dstc_call(opts, dstc_toslots(opts, 1), head);
head = dstc_value(subopts, tup[0]);
return dstc_call(opts, ast, dstc_toslots(c, tup + 1, dst_tuple_length(tup) - 1), head);
}
static DstSlot dstc_array(DstFopts opts) {
return dstc_call(opts, dstc_toslots(opts, 0), dstc_cslot(dst_wrap_cfunction(dst_cfun_array)));
static DstSlot dstc_array(DstFopts opts, DstAst *ast, Dst x) {
DstCompiler *c = opts.compiler;
DstArray *a = dst_unwrap_array(x);
return dstc_call(opts, ast,
dstc_toslots(c, a->data, a->count),
dstc_cslot(dst_wrap_cfunction(dst_cfun_array)));
}
static DstSlot dstc_tablector(DstFopts opts, DstCFunction cfun) {
return dstc_call(opts, dstc_toslotskv(opts), dstc_cslot(dst_wrap_cfunction(cfun)));
static DstSlot dstc_tablector(DstFopts opts, DstAst *ast, Dst x, DstCFunction cfun) {
DstCompiler *c = opts.compiler;
return dstc_call(opts, ast, dstc_toslotskv(c, x), dstc_cslot(dst_wrap_cfunction(cfun)));
}
/* Compile a single value */
DstSlot dstc_value(DstFopts opts) {
DstSlot dstc_value(DstFopts opts, Dst x) {
DstSlot ret;
DstAst *ast = dst_ast_node(x);
x = dst_ast_unwrap1(x);
if (dstc_iserr(&opts)) {
return dstc_cslot(dst_wrap_nil());
}
if (opts.compiler->recursion_guard <= 0) {
dstc_cerror(opts.compiler, opts.sourcemap, "recursed too deeply");
dstc_cerror(opts.compiler, ast, "recursed too deeply");
return dstc_cslot(dst_wrap_nil());
}
opts.compiler->recursion_guard--;
switch (dst_type(opts.x)) {
switch (dst_type(x)) {
default:
ret = dstc_cslot(opts.x);
ret = dstc_cslot(x);
break;
case DST_SYMBOL:
{
const uint8_t *sym = dst_unwrap_symbol(opts.x);
ret = dstc_resolve(opts.compiler, opts.sourcemap, sym);
const uint8_t *sym = dst_unwrap_symbol(x);
ret = dstc_resolve(opts.compiler, ast, sym);
break;
}
case DST_TUPLE:
ret = dstc_tuple(opts);
ret = dstc_tuple(opts, ast, x);
break;
case DST_ARRAY:
ret = dstc_array(opts);
ret = dstc_array(opts, ast, x);
break;
case DST_STRUCT:
ret = dstc_tablector(opts, dst_cfun_struct);
ret = dstc_tablector(opts, ast, x, dst_cfun_struct);
break;
case DST_TABLE:
ret = dstc_tablector(opts, dst_cfun_table);
ret = dstc_tablector(opts, ast, x, dst_cfun_table);
break;
}
if (opts.flags & DST_FOPTS_TAIL) {
ret = dstc_return(opts.compiler, opts.sourcemap, ret);
ret = dstc_return(opts.compiler, ast, ret);
}
if (opts.flags & DST_FOPTS_HINT && !dstc_sequal(opts.hint, ret)) {
dstc_copy(opts.compiler, opts.sourcemap, opts.hint, ret);
dstc_copy(opts.compiler, ast, opts.hint, ret);
ret = opts.hint;
}
opts.compiler->recursion_guard++;
@ -899,13 +881,11 @@ DstCompileResult dst_compile(DstCompileOptions opts) {
/* Set initial form options */
fopts.compiler = &c;
fopts.sourcemap = opts.sourcemap;
fopts.flags = DST_FOPTS_TAIL | DST_SLOTTYPE_ANY;
fopts.hint = dstc_cslot(dst_wrap_nil());
fopts.x = opts.source;
/* Compile the value */
dstc_value(fopts);
dstc_value(fopts, opts.source);
if (c.result.status == DST_COMPILE_OK) {
c.result.funcdef = dstc_pop_funcdef(&c);
@ -941,11 +921,8 @@ int dst_compile_cfun(DstArgs args) {
DstTable *t;
if (args.n < 1)
return dst_throw(args, "expected at least one argument");
if (args.n >= 3 && !dst_checktype(args.v[2], DST_TUPLE))
return dst_throw(args, "expected source map to be tuple");
opts.source = args.v[0];
opts.env = args.n >= 2 ? args.v[1] : dst_stl_env();
opts.sourcemap = args.n >= 3 ? dst_unwrap_tuple(args.v[2]) : NULL;
opts.flags = 0;
res = dst_compile(opts);
if (res.status == DST_COMPILE_OK) {

View File

@ -56,21 +56,9 @@ struct DstSlot {
/* Slot and map pairing */
typedef struct DstSM {
DstSlot slot;
const Dst *map;
DstAst *map;
} DstSM;
/* Special forms that need support */
/* cond
* while (continue, break)
* quote
* fn
* def
* var
* varset
* do
* apply (overloaded with normal function)
*/
#define DST_SCOPE_FUNCTION 1
#define DST_SCOPE_ENV 2
#define DST_SCOPE_TOP 4
@ -128,24 +116,25 @@ struct DstCompiler {
/* Options for compiling a single form */
struct DstFopts {
DstCompiler *compiler;
Dst x;
const Dst *sourcemap;
uint32_t flags; /* bit set of accepted primitive types */
DstSlot hint;
};
/* Get the default form options */
DstFopts dstc_fopts_default(DstCompiler *c);
/* A grouping of optimizations on a cfunction given certain conditions
* on the arguments (such as all constants, or some known types). The appropriate
* optimizations should be tried before compiling a normal function call. */
typedef struct DstCFunOptimizer {
DstCFunction cfun;
DstSlot (*optimize)(DstFopts opts, int32_t argn, const Dst *argv);
DstSlot (*optimize)(DstFopts opts, DstAst *ast, int32_t argn, const Dst *argv);
} DstCFunOptimizer;
/* A grouping of a named special and the corresponding compiler fragment */
typedef struct DstSpecial {
const char *name;
DstSlot (*compile)(DstFopts opts, int32_t argn, const Dst *argv);
DstSlot (*compile)(DstFopts opts, DstAst *ast, int32_t argn, const Dst *argv);
} DstSpecial;
/****************************************************/
@ -180,7 +169,7 @@ void dstc_nameslot(DstCompiler *c, const uint8_t *sym, DstSlot s);
* that can be used in an instruction. */
int32_t dstc_preread(
DstCompiler *c,
const Dst *sourcemap,
DstAst *ast,
int32_t max,
int nth,
DstSlot s);
@ -191,48 +180,42 @@ void dstc_postread(DstCompiler *c, DstSlot s, int32_t index);
/* Move value from one slot to another. Cannot copy to constant slots. */
void dstc_copy(
DstCompiler *c,
const Dst *sourcemap,
DstAst *ast,
DstSlot dest,
DstSlot src);
/* Throw away some code after checking that it is well formed. */
void dstc_throwaway(DstFopts opts);
void dstc_throwaway(DstFopts opts, Dst x);
/* Generate the return instruction for a slot. */
DstSlot dstc_return(DstCompiler *c, const Dst *sourcemap, DstSlot s);
DstSlot dstc_return(DstCompiler *c, DstAst *ast, DstSlot s);
/* Get a target slot for emitting an instruction. Will always return
* a local slot. */
DstSlot dstc_gettarget(DstFopts opts);
/* Get a bunch of slots for function arguments */
DstSM *dstc_toslots(DstFopts opts, int32_t start);
DstSM *dstc_toslots(DstCompiler *c, const Dst *vals, int32_t len);
/* Get a bunch of slots for function arguments */
DstSM *dstc_toslotskv(DstFopts opts);
DstSM *dstc_toslotskv(DstCompiler *c, Dst ds);
/* Push slots load via dstc_toslots. */
void dstc_pushslots(DstFopts opts, DstSM *sms);
void dstc_pushslots(DstCompiler *c, DstAst *ast, DstSM *sms);
/* Free slots loaded via dstc_toslots */
void dstc_freeslots(DstFopts opts, DstSM *sms);
void dstc_freeslots(DstCompiler *c, DstSM *sms);
/* Store an error */
void dstc_error(DstCompiler *c, const Dst *sourcemap, const uint8_t *m);
void dstc_cerror(DstCompiler *c, const Dst *sourcemap, const char *m);
void dstc_error(DstCompiler *c, DstAst *ast, const uint8_t *m);
void dstc_cerror(DstCompiler *c, DstAst *ast, const char *m);
/* Dispatch to correct form compiler */
DstSlot dstc_value(DstFopts opts);
DstSlot dstc_value(DstFopts opts, Dst x);
/* Check if two slots are equal */
int dstc_sequal(DstSlot lhs, DstSlot rhs);
/* Use these to get sub options. They will traverse the source map so
* compiler errors make sense. Then modify the returned options. */
DstFopts dstc_getindex(DstFopts opts, int32_t index);
DstFopts dstc_getkey(DstFopts opts, Dst key);
DstFopts dstc_getvalue(DstFopts opts, Dst key);
/* Push and pop from the scope stack */
void dstc_scope(DstCompiler *c, int newfn);
void dstc_popscope(DstCompiler *c);
@ -246,9 +229,9 @@ DstSlot dstc_cslot(Dst x);
void dstc_freeslot(DstCompiler *c, DstSlot slot);
/* Search for a symbol */
DstSlot dstc_resolve(DstCompiler *c, const Dst *sourcemap, const uint8_t *sym);
DstSlot dstc_resolve(DstCompiler *c, DstAst *ast, const uint8_t *sym);
/* Emit instructions. */
void dstc_emit(DstCompiler *c, const Dst *sourcemap, uint32_t instr);
void dstc_emit(DstCompiler *c, DstAst *ast, uint32_t instr);
#endif

View File

@ -24,50 +24,49 @@
#include <dst/dststl.h>
#include "compile.h"
#include "gc.h"
#include "sourcemap.h"
#include "util.h"
DstSlot dstc_quote(DstFopts opts, int32_t argn, const Dst *argv) {
DstSlot dstc_quote(DstFopts opts, DstAst *ast, int32_t argn, const Dst *argv) {
if (argn != 1) {
dstc_cerror(opts.compiler, opts.sourcemap, "expected 1 argument");
dstc_cerror(opts.compiler, ast, "expected 1 argument");
return dstc_cslot(dst_wrap_nil());
}
return dstc_cslot(argv[0]);
return dstc_cslot(dst_ast_unwrap(argv[0]));
}
DstSlot dstc_varset(DstFopts opts, int32_t argn, const Dst *argv) {
DstFopts subopts;
DstSlot dstc_varset(DstFopts opts, DstAst *ast, int32_t argn, const Dst *argv) {
DstFopts subopts = dstc_fopts_default(opts.compiler);
DstSlot ret, dest;
Dst head;
if (argn != 2) {
dstc_cerror(opts.compiler, opts.sourcemap, "expected 2 arguments");
dstc_cerror(opts.compiler, ast, "expected 2 arguments");
return dstc_cslot(dst_wrap_nil());
}
if (!dst_checktype(argv[0], DST_SYMBOL)) {
dstc_cerror(opts.compiler, opts.sourcemap, "expected symbol");
head = dst_ast_unwrap(argv[0]);
if (!dst_checktype(head, DST_SYMBOL)) {
dstc_cerror(opts.compiler, ast, "expected symbol");
return dstc_cslot(dst_wrap_nil());
}
dest = dstc_resolve(opts.compiler, opts.sourcemap, dst_unwrap_symbol(argv[0]));
dest = dstc_resolve(opts.compiler, ast, dst_unwrap_symbol(head));
if (!(dest.flags & DST_SLOT_MUTABLE)) {
dstc_cerror(opts.compiler, opts.sourcemap, "cannot set constant");
dstc_cerror(opts.compiler, ast, "cannot set constant");
return dstc_cslot(dst_wrap_nil());
}
subopts = dstc_getindex(opts, 2);
subopts.flags = DST_FOPTS_HINT;
subopts.hint = dest;
ret = dstc_value(subopts);
dstc_copy(opts.compiler, subopts.sourcemap, dest, ret);
ret = dstc_value(subopts, argv[1]);
dstc_copy(opts.compiler, ast, dest, ret);
return ret;
}
/* Add attributes to a global def or var table */
static void handleattr(DstFopts opts, int32_t argn, const Dst *argv, DstTable *tab) {
static void handleattr(DstCompiler *c, int32_t argn, const Dst *argv, DstTable *tab) {
int32_t i;
for (i = 1; i < argn - 1; i++) {
Dst attr = argv[i];
DstFopts subopts = dstc_getindex(opts, i + 1);
Dst attr = dst_ast_unwrap1(argv[i]);
switch (dst_type(attr)) {
default:
dstc_cerror(opts.compiler, subopts.sourcemap, "could not add meta data to def");
dstc_cerror(c, dst_ast_node(argv[i]), "could not add metadata to binding");
return;
case DST_SYMBOL:
dst_table_put(tab, attr, dst_wrap_true());
@ -79,45 +78,44 @@ static void handleattr(DstFopts opts, int32_t argn, const Dst *argv, DstTable *t
}
}
DstSlot dstc_var(DstFopts opts, int32_t argn, const Dst *argv) {
DstSlot dstc_var(DstFopts opts, DstAst *ast, int32_t argn, const Dst *argv) {
DstCompiler *c = opts.compiler;
DstFopts subopts;
DstFopts subopts = dstc_fopts_default(c);
Dst head;
DstSlot ret;
if (argn < 2) {
dstc_cerror(opts.compiler, opts.sourcemap, "expected at least 2 arguments");
dstc_cerror(c, ast, "expected at least 2 arguments");
return dstc_cslot(dst_wrap_nil());
}
if (!dst_checktype(argv[0], DST_SYMBOL)) {
dstc_cerror(opts.compiler, opts.sourcemap, "expected symbol");
head = dst_ast_unwrap1(argv[0]);
if (!dst_checktype(head, DST_SYMBOL)) {
dstc_cerror(c, dst_ast_node(argv[0]), "expected symbol");
return dstc_cslot(dst_wrap_nil());
}
subopts = dstc_getindex(opts, argn);
subopts.flags = opts.flags & ~DST_FOPTS_TAIL;
ret = dstc_value(subopts);
subopts.hint = opts.hint;
ret = dstc_value(subopts, argv[argn - 1]);
if (dst_v_last(c->scopes).flags & DST_SCOPE_TOP) {
DstCompiler *c = opts.compiler;
const Dst *sm = opts.sourcemap;
DstSlot refslot, refarrayslot;
/* Global var, generate var */
DstTable *reftab = dst_table(1);
DstArray *ref = dst_array(1);
dst_array_push(ref, dst_wrap_nil());
dst_table_put(reftab, dst_csymbolv("ref"), dst_wrap_array(ref));
handleattr(opts, argn, argv, reftab);
dst_put(opts.compiler->env, argv[0], dst_wrap_table(reftab));
handleattr(c, argn, argv, reftab);
dst_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;
/* Generate code to set ref */
int32_t refarrayindex = dstc_preread(c, sm, 0xFF, 1, refarrayslot);
int32_t retindex = dstc_preread(c, sm, 0xFF, 2, ret);
dstc_emit(c, sm,
int32_t refarrayindex = dstc_preread(c, ast, 0xFF, 1, refarrayslot);
int32_t retindex = dstc_preread(c, ast, 0xFF, 2, ret);
dstc_emit(c, ast,
(retindex << 16) |
(refarrayindex << 8) |
DOP_PUT_INDEX);
dstc_postread(c, refarrayslot, refarrayindex);
dstc_postread(c, ret, retindex);
/*dstc_freeslot(c, refarrayslot);*/
ret = refslot;
} else {
/* Non root scope, bring to local slot */
@ -132,30 +130,30 @@ DstSlot dstc_var(DstFopts opts, int32_t argn, const Dst *argv) {
localslot.flags = DST_SLOT_NAMED | DST_SLOT_MUTABLE;
localslot.envindex = 0;
localslot.constant = dst_wrap_nil();
dstc_copy(opts.compiler, opts.sourcemap, localslot, ret);
dstc_copy(c, ast, localslot, ret);
ret = localslot;
}
dstc_nameslot(c, dst_unwrap_symbol(argv[0]), ret);
dstc_nameslot(c, dst_unwrap_symbol(head), ret);
}
return ret;
}
DstSlot dstc_def(DstFopts opts, int32_t argn, const Dst *argv) {
DstSlot dstc_def(DstFopts opts, DstAst *ast, int32_t argn, const Dst *argv) {
DstCompiler *c = opts.compiler;
const Dst *sm = opts.sourcemap;
DstFopts subopts;
DstFopts subopts = dstc_fopts_default(c);
DstSlot ret;
Dst head;
if (argn < 2) {
dstc_cerror(opts.compiler, opts.sourcemap, "expected at least 2 arguments");
dstc_cerror(c, ast, "expected at least 2 arguments");
return dstc_cslot(dst_wrap_nil());
}
if (!dst_checktype(argv[0], DST_SYMBOL)) {
dstc_cerror(opts.compiler, opts.sourcemap, "expected symbol");
head = dst_ast_unwrap1(argv[0]);
if (!dst_checktype(head, DST_SYMBOL)) {
dstc_cerror(c, dst_ast_node(argv[0]), "expected symbol");
return dstc_cslot(dst_wrap_nil());
}
subopts = dstc_getindex(opts, argn);
subopts.flags &= ~DST_FOPTS_TAIL;
ret = dstc_value(subopts);
subopts.flags = opts.flags & ~DST_FOPTS_TAIL;
ret = dstc_value(subopts, argv[argn - 1]);
ret.flags |= DST_SLOT_NAMED;
if (dst_v_last(c->scopes).flags & DST_SCOPE_TOP) {
DstTable *tab = dst_table(2);
@ -164,14 +162,14 @@ DstSlot dstc_def(DstFopts opts, int32_t argn, const Dst *argv) {
DstSlot tabslot = dstc_cslot(dst_wrap_table(tab));
/* Add env entry to env */
handleattr(opts, argn, argv, tab);
dst_put(c->env, argv[0], dst_wrap_table(tab));
handleattr(c, argn, argv, tab);
dst_put(c->env, head, dst_wrap_table(tab));
/* Put value in table when evaulated */
tableindex = dstc_preread(c, sm, 0xFF, 1, tabslot);
valsymindex = dstc_preread(c, sm, 0xFF, 2, valsym);
valueindex = dstc_preread(c, sm, 0xFF, 3, ret);
dstc_emit(c, sm,
tableindex = dstc_preread(c, ast, 0xFF, 1, tabslot);
valsymindex = dstc_preread(c, ast, 0xFF, 2, valsym);
valueindex = dstc_preread(c, ast, 0xFF, 3, ret);
dstc_emit(c, ast,
(valueindex << 24) |
(valsymindex << 16) |
(tableindex << 8) |
@ -181,7 +179,7 @@ DstSlot dstc_def(DstFopts opts, int32_t argn, const Dst *argv) {
dstc_postread(c, ret, valueindex);
} else {
/* Non root scope, simple slot alias */
dstc_nameslot(c, dst_unwrap_symbol(argv[0]), ret);
dstc_nameslot(c, dst_unwrap_symbol(head), ret);
}
return ret;
}
@ -197,57 +195,45 @@ DstSlot dstc_def(DstFopts opts, int32_t argn, const Dst *argv) {
* ...
* :done
*/
DstSlot dstc_if(DstFopts opts, int32_t argn, const Dst *argv) {
DstSlot dstc_if(DstFopts opts, DstAst *ast, int32_t argn, const Dst *argv) {
DstCompiler *c = opts.compiler;
const Dst *sm = opts.sourcemap;
int32_t labelr, labeljr, labeld, labeljd, condlocal;
DstFopts leftopts, rightopts, condopts;
DstFopts condopts, bodyopts;
DstSlot cond, left, right, target;
Dst truebody, falsebody;
const int tail = opts.flags & DST_FOPTS_TAIL;
const int drop = opts.flags & DST_FOPTS_DROP;
(void) argv;
if (argn < 2 || argn > 3) {
dstc_cerror(c, sm, "expected 2 or 3 arguments to if");
dstc_cerror(c, ast, "expected 2 or 3 arguments to if");
return dstc_cslot(dst_wrap_nil());
}
/* Get the bodies of the if expression */
truebody = argv[1];
falsebody = argn > 2 ? argv[2] : dst_wrap_nil();
/* Get options */
condopts = dstc_getindex(opts, 1);
leftopts = dstc_getindex(opts, 2);
rightopts = dstc_getindex(opts, 3);
if (argn == 2) rightopts.sourcemap = opts.sourcemap;
if (opts.flags & DST_FOPTS_HINT) {
leftopts.flags |= DST_FOPTS_HINT;
rightopts.flags |= DST_FOPTS_HINT;
}
if (tail) {
leftopts.flags |= DST_FOPTS_TAIL;
rightopts.flags |= DST_FOPTS_TAIL;
}
if (drop) {
leftopts.flags |= DST_FOPTS_DROP;
rightopts.flags |= DST_FOPTS_DROP;
}
condopts = dstc_fopts_default(c);
bodyopts = opts;
/* Compile condition */
cond = dstc_value(condopts);
cond = dstc_value(condopts, argv[0]);
/* Check constant condition. */
/* TODO: Use type info for more short circuits */
if ((cond.flags & DST_SLOT_CONSTANT) && !(cond.flags & DST_SLOT_REF)) {
DstFopts goodopts, badopts;
if (dst_truthy(cond.constant)) {
goodopts = leftopts;
badopts = rightopts;
} else {
goodopts = rightopts;
badopts = leftopts;
if (!dst_truthy(cond.constant)) {
/* Swap the true and false bodies */
Dst temp = falsebody;
falsebody = truebody;
truebody = temp;
}
dstc_scope(c, 0);
target = dstc_value(goodopts);
target = dstc_value(bodyopts, truebody);
dstc_popscope(c);
dstc_throwaway(badopts);
dstc_throwaway(bodyopts, falsebody);
return target;
}
@ -257,27 +243,27 @@ DstSlot dstc_if(DstFopts opts, int32_t argn, const Dst *argv) {
: dstc_cslot(dst_wrap_nil());
/* Compile jump to right */
condlocal = dstc_preread(c, sm, 0xFF, 1, cond);
condlocal = dstc_preread(c, ast, 0xFF, 1, cond);
labeljr = dst_v_count(c->buffer);
dstc_emit(c, sm, DOP_JUMP_IF_NOT | (condlocal << 8));
dstc_emit(c, ast, DOP_JUMP_IF_NOT | (condlocal << 8));
dstc_postread(c, cond, condlocal);
dstc_freeslot(c, cond);
/* Condition left body */
dstc_scope(c, 0);
left = dstc_value(leftopts);
if (!drop && !tail) dstc_copy(c, sm, target, left);
left = dstc_value(bodyopts, truebody);
if (!drop && !tail) dstc_copy(c, ast, target, left);
dstc_popscope(c);
/* Compile jump to done */
labeljd = dst_v_count(c->buffer);
if (!tail) dstc_emit(c, sm, DOP_JUMP);
if (!tail) dstc_emit(c, ast, DOP_JUMP);
/* Compile right body */
labelr = dst_v_count(c->buffer);
dstc_scope(c, 0);
right = dstc_value(rightopts);
if (!drop && !tail) dstc_copy(c, sm, target, right);
right = dstc_value(bodyopts, falsebody);
if (!drop && !tail) dstc_copy(c, ast, target, right);
dstc_popscope(c);
/* Write jumps - only add jump lengths if jump actually emitted */
@ -291,44 +277,44 @@ DstSlot dstc_if(DstFopts opts, int32_t argn, const Dst *argv) {
/* Compile a do form. Do forms execute their body sequentially and
* evaluate to the last expression in the body. */
DstSlot dstc_do(DstFopts opts, int32_t argn, const Dst *argv) {
DstSlot dstc_do(DstFopts opts, DstAst *ast, int32_t argn, const Dst *argv) {
int32_t i;
DstSlot ret;
dstc_scope(opts.compiler, 0);
(void) argv;
DstCompiler *c = opts.compiler;
DstFopts subopts = dstc_fopts_default(c);
(void) ast;
dstc_scope(c, 0);
for (i = 0; i < argn; i++) {
DstFopts subopts = dstc_getindex(opts, i + 1);
if (i != argn - 1) {
subopts.flags = DST_FOPTS_DROP;
} else if (opts.flags & DST_FOPTS_TAIL) {
subopts.flags = DST_FOPTS_TAIL;
}
ret = dstc_value(subopts);
ret = dstc_value(subopts, argv[i]);
if (i != argn - 1) {
dstc_freeslot(opts.compiler, ret);
dstc_freeslot(c, ret);
}
}
dstc_popscope_keepslot(opts.compiler, ret);
dstc_popscope_keepslot(c, ret);
return ret;
}
DstSlot dstc_transfer(DstFopts opts, int32_t argn, const Dst *argv) {
DstSlot dstc_transfer(DstFopts opts, DstAst *ast, int32_t argn, const Dst *argv) {
DstCompiler *c = opts.compiler;
const Dst *sm = opts.sourcemap;
DstFopts subopts = dstc_fopts_default(c);;
DstSlot dest, fib, val;
int32_t destindex, fibindex, valindex;
(void) argv;
if (argn > 2) {
dstc_cerror(c, sm, "expected no more than 2 arguments");
dstc_cerror(c, ast, "expected no more than 2 arguments");
return dstc_cslot(dst_wrap_nil());
}
dest = dstc_gettarget(opts);
fib = (argn > 0) ? dstc_value(dstc_getindex(opts, 1)) : dstc_cslot(dst_wrap_nil());
val = (argn > 1) ? dstc_value(dstc_getindex(opts, 2)) : dstc_cslot(dst_wrap_nil());
destindex = dstc_preread(c, sm, 0xFF, 1, dest);
fibindex = dstc_preread(c, sm, 0xFF, 2, fib);
valindex = dstc_preread(c, sm, 0xFF, 3, val);
dstc_emit(c, sm,
fib = (argn > 0) ? dstc_value(subopts, argv[0]) : dstc_cslot(dst_wrap_nil());
val = (argn > 1) ? dstc_value(subopts, argv[1]) : dstc_cslot(dst_wrap_nil());
destindex = dstc_preread(c, ast, 0xFF, 1, dest);
fibindex = dstc_preread(c, ast, 0xFF, 2, fib);
valindex = dstc_preread(c, ast, 0xFF, 3, val);
dstc_emit(c, ast,
(valindex << 24) |
(fibindex << 16) |
(destindex << 8) |
@ -350,23 +336,22 @@ DstSlot dstc_transfer(DstFopts opts, int32_t argn, const Dst *argv) {
* jump :whiletop
* :done
*/
DstSlot dstc_while(DstFopts opts, int32_t argn, const Dst *argv) {
DstSlot dstc_while(DstFopts opts, DstAst *ast, int32_t argn, const Dst *argv) {
DstCompiler *c = opts.compiler;
const Dst *sm = opts.sourcemap;
DstSlot cond;
DstFopts subopts = dstc_fopts_default(c);
int32_t condlocal, labelwt, labeld, labeljt, labelc, i;
int infinite = 0;
(void) argv;
if (argn < 2) {
dstc_cerror(c, sm, "expected at least 2 arguments");
dstc_cerror(c, ast, "expected at least 2 arguments");
return dstc_cslot(dst_wrap_nil());
}
labelwt = dst_v_count(c->buffer);
/* Compile condition */
cond = dstc_value(dstc_getindex(opts, 1));
cond = dstc_value(subopts, argv[0]);
/* Check for constant condition */
if (cond.flags & DST_SLOT_CONSTANT) {
@ -382,22 +367,21 @@ DstSlot dstc_while(DstFopts opts, int32_t argn, const Dst *argv) {
/* Infinite loop does not need to check condition */
if (!infinite) {
condlocal = dstc_preread(c, sm, 0xFF, 1, cond);
condlocal = dstc_preread(c, ast, 0xFF, 1, cond);
labelc = dst_v_count(c->buffer);
dstc_emit(c, sm, DOP_JUMP_IF_NOT | (condlocal << 8));
dstc_emit(c, ast, DOP_JUMP_IF_NOT | (condlocal << 8));
dstc_postread(c, cond, condlocal);
}
/* Compile body */
for (i = 1; i < argn; i++) {
DstFopts subopts = dstc_getindex(opts, i + 1);
subopts.flags = DST_FOPTS_DROP;
dstc_freeslot(c, dstc_value(subopts));
dstc_freeslot(c, dstc_value(subopts, argv[i]));
}
/* Compile jump to whiletop */
labeljt = dst_v_count(c->buffer);
dstc_emit(c, sm, DOP_JUMP);
dstc_emit(c, ast, DOP_JUMP);
/* Calculate jumps */
labeld = dst_v_count(c->buffer);
@ -405,7 +389,7 @@ DstSlot dstc_while(DstFopts opts, int32_t argn, const Dst *argv) {
c->buffer[labeljt] |= (labelwt - labeljt) << 8;
/* Pop scope and return nil slot */
dstc_popscope(opts.compiler);
dstc_popscope(c);
return dstc_cslot(dst_wrap_nil());
}
@ -423,18 +407,18 @@ static int32_t dstc_addfuncdef(DstCompiler *c, DstFuncDef *def) {
return dst_v_count(scope->defs) - 1;
}
DstSlot dstc_fn(DstFopts opts, int32_t argn, const Dst *argv) {
DstSlot dstc_fn(DstFopts opts, DstAst *ast, int32_t argn, const Dst *argv) {
DstCompiler *c = opts.compiler;
const Dst *sm = opts.sourcemap;
DstFuncDef *def;
DstSlot ret;
Dst head, paramv;
int32_t paramcount, argi, parami, arity, localslot, defindex;
DstFopts subopts = dstc_fopts_default(c);
const Dst *params;
const Dst *psm;
int varargs = 0;
if (argn < 2) {
dstc_cerror(c, sm, "expected at least 2 arguments to function literal");
dstc_cerror(c, ast, "expected at least 2 arguments to function literal");
return dstc_cslot(dst_wrap_nil());
}
@ -444,22 +428,23 @@ DstSlot dstc_fn(DstFopts opts, int32_t argn, const Dst *argv) {
/* Read function parameters */
parami = 0;
arity = 0;
if (dst_checktype(argv[0], DST_SYMBOL)) parami = 1;
head = dst_ast_unwrap(argv[0]);
if (dst_checktype(head, DST_SYMBOL)) parami = 1;
if (parami >= argn) {
dstc_cerror(c, sm, "expected function parameters");
dstc_cerror(c, dst_ast_node(argv[0]), "expected function parameters");
return dstc_cslot(dst_wrap_nil());
}
if (dst_seq_view(argv[parami], &params, &paramcount)) {
psm = dst_sourcemap_index(sm, parami + 1);
paramv = dst_ast_unwrap(argv[parami]);
if (dst_seq_view(paramv, &params, &paramcount)) {
int32_t i;
for (i = 0; i < paramcount; i++) {
const Dst *psmi = dst_sourcemap_index(psm, i);
if (dst_checktype(params[i], DST_SYMBOL)) {
Dst param = dst_ast_unwrap(params[i]);
if (dst_checktype(param, DST_SYMBOL)) {
DstSlot slot;
/* Check for varargs */
if (0 == dst_cstrcmp(dst_unwrap_symbol(params[i]), "&")) {
if (0 == dst_cstrcmp(dst_unwrap_symbol(param), "&")) {
if (i != paramcount - 2) {
dstc_cerror(c, psmi, "variable argument symbol in unexpected location");
dstc_cerror(c, dst_ast_node(params[i]), "variable argument symbol in unexpected location");
return dstc_cslot(dst_wrap_nil());
}
varargs = 1;
@ -470,24 +455,23 @@ DstSlot dstc_fn(DstFopts opts, int32_t argn, const Dst *argv) {
slot.envindex = 0;
slot.constant = dst_wrap_nil();
slot.index = dstc_lsloti(c);
dstc_nameslot(c, dst_unwrap_symbol(params[i]), slot);
dstc_nameslot(c, dst_unwrap_symbol(param), slot);
arity++;
} else {
dstc_cerror(c, psmi, "expected symbol as function parameter");
dstc_cerror(c, dst_ast_node(params[i]), "expected symbol as function parameter");
return dstc_cslot(dst_wrap_nil());
}
}
} else {
dstc_cerror(c, sm, "expected function parameters");
dstc_cerror(c, ast, "expected function parameters");
return dstc_cslot(dst_wrap_nil());
}
/* Compile function body */
for (argi = parami + 1; argi < argn; argi++) {
DstSlot s;
DstFopts subopts = dstc_getindex(opts, argi + 1);
subopts.flags = argi == (argn - 1) ? DST_FOPTS_TAIL : DST_FOPTS_DROP;
s = dstc_value(subopts);
s = dstc_value(subopts, argv[argi]);
dstc_freeslot(c, s);
}
@ -504,13 +488,13 @@ DstSlot dstc_fn(DstFopts opts, int32_t argn, const Dst *argv) {
ret = dstc_gettarget(opts);
localslot = ret.index > 0xF0 ? 0xF1 : ret.index;
dstc_emit(c, sm,
dstc_emit(c, ast,
(defindex << 16) |
(localslot << 8) |
DOP_CLOSURE);
if (ret.index != localslot) {
dstc_emit(c, sm,
dstc_emit(c, ast,
(ret.index << 16) |
(localslot << 8) |
DOP_MOVE_FAR);

183
core/context.c Normal file
View File

@ -0,0 +1,183 @@
/*
* Copyright (c) 2017 Calvin Rose
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include <dst/dst.h>
/*static void deinit_file(DstContext *c) {*/
/*FILE *f = (FILE *) (c->user);*/
/*fclose(f);*/
/*}*/
/* Read input for a repl */
static void replread(DstContext *c) {
if (c->buffer.count == 0)
printf("> ");
else
printf(">> ");
for (;;) {
int x = fgetc(stdin);
if (x == EOF) {
dst_buffer_push_u8(&c->buffer, '\n');
printf("\n");
break;
}
dst_buffer_push_u8(&c->buffer, x);
if (x == '\n') break;
}
}
/* 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), "_", dst_wrap_nil());
}
/* Handle errors on repl */
static void replerror(DstContext *c, DstContextErrorType type, Dst err, size_t start, size_t end) {
const char *errtype;
(void) c;
(void) start;
(void) end;
switch (type) {
case DST_CONTEXT_ERROR_PARSE:
errtype = "parse";
break;
case DST_CONTEXT_ERROR_RUNTIME:
errtype = "runtime";
break;
case DST_CONTEXT_ERROR_COMPILE:
errtype = "compile";
break;
}
dst_puts(dst_formatc("%s error: %v\n", errtype, err));
}
void dst_context_repl(DstContext *c, Dst env) {
dst_buffer_init(&c->buffer, 1024);
c->env = env;
dst_gcroot(env);
c->flushed_bytes = 0;
c->user = NULL;
if (dst_checktype(c->env, DST_TABLE))
dst_module_def(dst_unwrap_table(c->env), "_", dst_wrap_nil());
c->read_chunk = replread;
c->on_error = replerror;
c->on_value = replonvalue;
}
/* 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);
}
}
/* Start a context */
int dst_context_run(DstContext *c) {
int done = 0;
int flags = 0;
while (!done) {
DstCompileResult cres;
DstCompileOptions opts;
DstParseResult res = dst_parse(c->buffer.data, c->buffer.count);
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 |= 1 << DST_CONTEXT_ERROR_PARSE;
if (c->on_error) {
c->on_error(c, DST_CONTEXT_ERROR_PARSE,
dst_wrap_string(res.error),
c->flushed_bytes + res.bytes_read,
c->flushed_bytes + res.bytes_read);
}
}
break;
}
case DST_PARSE_ERROR:
if (c->on_error) {
flags |= 1 << DST_CONTEXT_ERROR_PARSE;
c->on_error(c, DST_CONTEXT_ERROR_PARSE,
dst_wrap_string(res.error),
c->flushed_bytes + res.bytes_read,
c->flushed_bytes + 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 */
if (c->on_error) {
flags |= 1 << DST_CONTEXT_ERROR_RUNTIME;
c->on_error(c, DST_CONTEXT_ERROR_RUNTIME, ret, -1, -1);
}
} else {
if (c->on_value) {
c->on_value(c, ret);
}
}
} else {
if (c->on_error) {
flags |= 1 << DST_CONTEXT_ERROR_COMPILE;
c->on_error(c, DST_CONTEXT_ERROR_COMPILE,
dst_wrap_string(cres.error),
c->flushed_bytes + cres.error_start,
c->flushed_bytes + cres.error_end);
}
}
bshift(c, res.bytes_read);
}
break;
}
}
dst_buffer_deinit(&c->buffer);
if (c->deinit) c->deinit(c);
dst_gcunroot(c->env);
return flags;
}

View File

@ -73,7 +73,12 @@ static void dst_mark_buffer(DstBuffer *buffer) {
}
static void dst_mark_abstract(void *adata) {
if (dst_gc_reachable(dst_abstract_header(adata)))
return;
dst_gc_mark(dst_abstract_header(adata));
if (dst_abstract_header(adata)->type->gcmark) {
dst_abstract_header(adata)->type->gcmark(adata, dst_abstract_size(adata));
}
}
/* Mark a bunch of items in memory */

View File

@ -41,7 +41,8 @@ static int dst_io_gc(void *p, size_t len);
DstAbstractType dst_io_filetype = {
"io.file",
dst_io_gc
dst_io_gc,
NULL
};
/* Check argupments to fopen */

View File

@ -155,40 +155,15 @@ static int to_hex(uint8_t c) {
}
}
/* Make source mapping for atom (non recursive structure) */
static Dst atom_map(int32_t start, int32_t end) {
Dst *t = dst_tuple_begin(2);
t[0] = dst_wrap_integer(start);
t[1] = dst_wrap_integer(end);
return dst_wrap_tuple(dst_tuple_end(t));
}
/* Create mappingd for recursive data structure */
static Dst ds_map(int32_t start, int32_t end, Dst submap) {
Dst *t = dst_tuple_begin(3);
t[0] = dst_wrap_integer(start);
t[1] = dst_wrap_integer(end);
t[2] = submap;
return dst_wrap_tuple(dst_tuple_end(t));
}
/* Create a sourcemapping for a key value pair */
static Dst kv_map(Dst k, Dst v) {
Dst *t = dst_tuple_begin(2);
t[0] = k;
t[1] = v;
return dst_wrap_tuple(dst_tuple_end(t));
}
typedef struct {
DstArray stack;
DstArray mapstack;
const uint8_t *srcstart;
const uint8_t *end;
const char *errmsg;
DstParseStatus status;
} ParseArgs;
/* Entry point of the recursive descent parser */
static const uint8_t *parse_recur(
ParseArgs *args,
@ -199,7 +174,6 @@ static const uint8_t *parse_recur(
const uint8_t *mapstart;
int32_t qcount = 0;
Dst ret;
Dst submapping;
/* Prevent stack overflow */
if (recur == 0) goto too_much_recur;
@ -226,7 +200,6 @@ static const uint8_t *parse_recur(
/* Open mapping */
mapstart = src;
submapping = dst_wrap_nil();
/* Detect token type based on first character */
switch (*src) {
@ -372,27 +345,20 @@ static const uint8_t *parse_recur(
case ')':
{
Dst *tup = dst_tuple_begin(n);
Dst *subtup = dst_tuple_begin(n);
for (i = n; i > 0; i--) {
tup[i - 1] = dst_array_pop(&args->stack);
subtup[i - 1] = dst_array_pop(&args->mapstack);
}
ret = dst_wrap_tuple(dst_tuple_end(tup));
submapping = dst_wrap_tuple(dst_tuple_end(subtup));
break;
}
case ']':
{
DstArray *arr = dst_array(n);
DstArray *subarr = dst_array(n);
for (i = n; i > 0; i--) {
arr->data[i - 1] = dst_array_pop(&args->stack);
subarr->data[i - 1] = dst_array_pop(&args->mapstack);
}
arr->count = n;
subarr->count = n;
ret = dst_wrap_array(arr);
submapping = dst_wrap_array(subarr);
break;
}
case '}':
@ -404,32 +370,20 @@ static const uint8_t *parse_recur(
}
if (istable) {
DstTable *t = dst_table(n);
DstTable *subt = 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 subval = dst_array_pop(&args->mapstack);
Dst subkey = dst_array_pop(&args->mapstack);
dst_table_put(t, key, val);
dst_table_put(subt, key, kv_map(subkey, subval));
}
ret = dst_wrap_table(t);
submapping = dst_wrap_table(subt);
} else {
DstKV *st = dst_struct_begin(n >> 1);
DstKV *subst = 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 subval = dst_array_pop(&args->mapstack);
Dst subkey = dst_array_pop(&args->mapstack);
dst_struct_put(st, key, val);
dst_struct_put(subst, key, kv_map(subkey, subval));
}
ret = dst_wrap_struct(dst_struct_end(st));
submapping = dst_wrap_struct(dst_struct_end(subst));
}
break;
}
@ -438,35 +392,15 @@ static const uint8_t *parse_recur(
}
}
/* Push source mapping */
if (dst_checktype(submapping, DST_NIL)) {
/* We just parsed an atom */
dst_array_push(&args->mapstack, atom_map(
mapstart - args->srcstart,
src - args->srcstart));
} else {
/* We just parsed a recursive data structure */
dst_array_push(&args->mapstack, ds_map(
mapstart - args->srcstart,
src - args->srcstart,
submapping));
}
/* Quote the returned value qcount times */
while (qcount--) {
int32_t start = mapstart - args->srcstart;
int32_t end = src - args->srcstart;
Dst sourcemap = dst_array_pop(&args->mapstack);
Dst* tup = dst_tuple_begin(2);
tup[0] = atom_map(start, end);
tup[1] = sourcemap;
ret = dst_ast_wrap(ret, mapstart - args->srcstart, src - args->srcstart);
ret = quote(ret);
dst_array_push(&args->mapstack, ds_map(
start,
end,
dst_wrap_tuple(dst_tuple_end(tup))));
}
/* Ast wrap */
ret = dst_ast_wrap(ret, mapstart - args->srcstart, src - args->srcstart);
/* Push the result to the stack */
dst_array_push(&args->stack, ret);
@ -537,8 +471,6 @@ DstParseResult dst_parse(const uint8_t *src, int32_t len) {
args.end = src + len;
args.errmsg = NULL;
dst_array_init(&args.mapstack, 10);
newsrc = parse_recur(&args, src, DST_RECURSION_GUARD);
res.status = args.status;
res.bytes_read = (int32_t) (newsrc - src);
@ -546,15 +478,12 @@ DstParseResult dst_parse(const uint8_t *src, int32_t len) {
if (args.errmsg) {
res.error = dst_cstring(args.errmsg);
res.value = dst_wrap_nil();
res.map = NULL;
} else {
res.value = dst_array_pop(&args.stack);
res.error = NULL;
res.map = dst_unwrap_tuple(dst_array_pop(&args.mapstack));
}
dst_array_deinit(&args.stack);
dst_array_deinit(&args.mapstack);
return res;
}
@ -592,7 +521,6 @@ int dst_parse_cfun(DstArgs args) {
break;
}
dst_table_put(t, dst_cstringv("status"), dst_cstringv(status_string));
if (res.status == DST_PARSE_OK) dst_table_put(t, dst_cstringv("map"), dst_wrap_tuple(res.map));
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));

View File

@ -1,77 +0,0 @@
/*
* Copyright (c) 2017 Calvin Rose
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include <dst/dst.h>
#include "sourcemap.h"
/* Get the sub source map by indexing a value. Used to traverse
* into arrays and tuples */
const Dst *dst_sourcemap_index(const Dst *map, int32_t index) {
if (NULL != map && dst_tuple_length(map) >= 3) {
const Dst *seq;
int32_t len;
if (dst_seq_view(map[2], &seq, &len)) {
if (index >= 0 && index < len) {
if (dst_checktype(seq[index], DST_TUPLE)) {
const Dst *ret = dst_unwrap_tuple(seq[index]);
if (dst_tuple_length(ret) >= 2 &&
dst_checktype(ret[0], DST_INTEGER) &&
dst_checktype(ret[1], DST_INTEGER)) {
return ret;
}
}
}
}
}
return NULL;
}
/* Traverse into tables and structs */
static const Dst *dst_sourcemap_kv(const Dst *map, Dst key, int kv) {
if (NULL != map && dst_tuple_length(map) >= 3) {
Dst kvpair = dst_get(map[2], key);
if (dst_checktype(kvpair, DST_TUPLE)) {
const Dst *kvtup = dst_unwrap_tuple(kvpair);
if (dst_tuple_length(kvtup) >= 2) {
if (dst_checktype(kvtup[kv], DST_TUPLE)) {
const Dst *ret = dst_unwrap_tuple(kvtup[kv]);
if (dst_tuple_length(ret) >= 2 &&
dst_checktype(ret[0], DST_INTEGER) &&
dst_checktype(ret[1], DST_INTEGER)) {
return ret;
}
}
}
}
}
return NULL;
}
/* Traverse into a key of a table or struct */
const Dst *dst_sourcemap_key(const Dst *map, Dst key) {
return dst_sourcemap_kv(map, key, 0);
}
/* Traverse into a value of a table or struct */
const Dst *dst_sourcemap_value(const Dst *map, Dst key) {
return dst_sourcemap_kv(map, key, 1);
}

View File

@ -1,44 +0,0 @@
/*
* Copyright (c) 2017 Calvin Rose
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef DST_SOURCEMAP_H_defined
#define DST_SOURCEMAP_H_defined
#include <dst/dst.h>
/* Get the sub source map by indexing a value. Used to traverse
* into arrays and tuples */
const Dst *dst_sourcemap_index(const Dst *map, int32_t index);
/* Traverse into a key of a table or struct */
const Dst *dst_sourcemap_key(const Dst *map, Dst key);
/* Traverse into a value of a table or struct */
const Dst *dst_sourcemap_value(const Dst *map, Dst key);
/* Try to rebuild a source map from given another map */
const Dst *dst_sourcemap_remap(
const Dst *oldmap,
Dst oldsource,
Dst newsource);
#endif

View File

@ -170,6 +170,12 @@ int32_t dst_capacity(Dst x);
Dst dst_getindex(Dst ds, int32_t index);
void dst_setindex(Dst ds, Dst value, int32_t index);
/* AST */
Dst dst_ast_wrap(Dst x, int32_t start, int32_t end);
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);
DstParseResult dst_parsec(const char *src);
@ -194,6 +200,10 @@ 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_repl(DstContext *c, Dst env);
int dst_context_run(DstContext *c);
/* C Function helpers */
#define dst_throw(a, e) (*((a).ret) = dst_cstringv(e), 1)
#define dst_throwv(a, v) (*((a).ret) = (v), 1)

View File

@ -47,6 +47,8 @@ typedef struct DstKV DstKV;
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;
@ -413,6 +415,7 @@ struct DstFunction {
struct DstAbstractType {
const char *name;
int (*gc)(void *data, size_t len);
int (*gcmark)(void *data, size_t len);
};
/* Contains information about userdata */
@ -454,11 +457,19 @@ struct DstCompileResult {
struct DstCompileOptions {
uint32_t flags;
const Dst *sourcemap;
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 */
struct DstAst {
Dst value;
int32_t source_start;
int32_t source_end;
int flags;
};
/* Parse structs */
enum DstParseStatus {
DST_PARSE_OK,
@ -470,9 +481,28 @@ enum DstParseStatus {
struct DstParseResult {
Dst value;
const uint8_t *error;
const Dst *map;
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 */