mirror of
https://github.com/janet-lang/janet
synced 2025-01-12 16:40:27 +00:00
Add context functions for more uniform interface
This commit is contained in:
parent
23196ff6a2
commit
d373d38aee
6
Makefile
6
Makefile
@ -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)
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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
186
core/ast.c
Normal 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));
|
||||
}
|
||||
}
|
||||
|
257
core/compile.c
257
core/compile.c
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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], ¶ms, ¶mcount)) {
|
||||
psm = dst_sourcemap_index(sm, parami + 1);
|
||||
paramv = dst_ast_unwrap(argv[parami]);
|
||||
if (dst_seq_view(paramv, ¶ms, ¶mcount)) {
|
||||
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
183
core/context.c
Normal 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;
|
||||
}
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
82
core/parse.c
82
core/parse.c
@ -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));
|
||||
|
@ -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);
|
||||
}
|
@ -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
|
@ -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)
|
||||
|
@ -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 */
|
||||
|
Loading…
Reference in New Issue
Block a user