1
0
mirror of https://github.com/janet-lang/janet synced 2024-06-22 21:23:16 +00:00

Fix scope issue in compiler.

This commit is contained in:
bakpakin 2018-01-15 23:31:39 -05:00
parent 6df88f225f
commit 23196ff6a2
10 changed files with 174 additions and 107 deletions

View File

@ -71,7 +71,7 @@ $(DST_TARGET): $(DST_CORE_SOURCES) $(DST_CLIENT_SOURCES) $(DST_ALL_HEADERS)
##### Testing #####
###################
run: $(DST_TARGET)
repl: $(DST_TARGET)
@ ./$(DST_TARGET)
debug: $(DST_TARGET)
@ -106,4 +106,4 @@ install: $(DST_TARGET)
uninstall:
rm $(BINDIR)/dst
.PHONY: clean install run debug valgrind test valtest install uninstall
.PHONY: clean install repl debug valgrind test valtest install uninstall

View File

@ -913,3 +913,26 @@ Dst dst_disasm(DstFuncDef *def) {
return dst_wrap_struct(dst_table_to_struct(ret));
}
/* C Function for assembly */
int dst_asm_cfun(DstArgs args) {
DstAssembleOptions opts;
DstAssembleResult res;
if (args.n < 1) return dst_throw(args, "expected assembly source");
opts.source = args.v[0];
opts.flags = 0;
res = dst_asm(opts);
if (res.status == DST_ASSEMBLE_OK) {
return dst_return(args, dst_wrap_function(dst_asm_func(res)));
} else {
return dst_throwv(args, dst_wrap_string(res.error));
}
}
int dst_disasm_cfun(DstArgs args) {
DstFunction *f;
if (args.n < 1 || !dst_checktype(args.v[0], DST_FUNCTION))
return dst_throw(args, "expected function");
f = dst_unwrap_function(args.v[0]);
return dst_return(args, dst_disasm(f->def));
}

View File

@ -102,6 +102,7 @@ int32_t dstc_lsloti(DstCompiler *c) {
break;
}
if (biti == -1) {
/* Extend bit vector for slots */
dst_v_push(scope->slots, len == 7 ? 0xFFFF0000 : 0);
biti = len << 5;
}
@ -112,6 +113,19 @@ int32_t dstc_lsloti(DstCompiler *c) {
return biti;
}
/* Allocate a given slot index */
static void slotalloci(DstCompiler *c, int32_t index) {
int32_t count;
int32_t block = index >> 5;
DstScope *scope = &dst_v_last(c->scopes);
if (index < 0) return;
while ((count = dst_v_count(scope->slots)) <= block) {
/* Extend bit vector for slots */
dst_v_push(scope->slots, count == 7 ? 0xFFFF0000 : 0);
}
scope->slots[block] |= 1 << (index & 0x1F);
}
/* Free a slot index */
void dstc_sfreei(DstCompiler *c, int32_t index) {
DstScope *scope = &dst_v_last(c->scopes);
@ -135,7 +149,7 @@ int32_t dstc_lslotn(DstCompiler *c, int32_t max, int32_t nth) {
/* Free a slot */
void dstc_freeslot(DstCompiler *c, DstSlot s) {
if (s.flags & (DST_SLOT_CONSTANT | DST_SLOT_NAMED)) return;
if (s.flags & (DST_SLOT_CONSTANT | DST_SLOT_REF | DST_SLOT_NAMED)) return;
if (s.envindex > 0) return;
dstc_sfreei(c, s.index);
}
@ -194,6 +208,14 @@ void dstc_popscope(DstCompiler *c) {
}
}
/* Leave a scope but keep a slot allocated. */
void dstc_popscope_keepslot(DstCompiler *c, DstSlot retslot) {
dstc_popscope(c);
if (retslot.envindex == 0 && retslot.index >= 0) {
slotalloci(c, retslot.index);
}
}
/* Create a slot with a constant */
DstSlot dstc_cslot(Dst x) {
DstSlot ret;
@ -433,6 +455,20 @@ void dstc_postread(DstCompiler *c, DstSlot s, int32_t index) {
}
}
/* Check if two slots are equal */
int dstc_sequal(DstSlot lhs, DstSlot rhs) {
if (lhs.flags == rhs.flags &&
lhs.index == rhs.index &&
lhs.envindex == rhs.envindex) {
if (lhs.flags & (DST_SLOT_REF | DST_SLOT_CONSTANT)) {
return dst_equals(lhs.constant, rhs.constant);
} else {
return 1;
}
}
return 0;
}
/* Move values from one slot to another. The destination must
* be writeable (not a literal). */
void dstc_copy(
@ -452,16 +488,7 @@ void dstc_copy(
}
/* Short circuit if dest and source are equal */
if (dest.flags == src.flags &&
dest.index == src.index &&
dest.envindex == src.envindex) {
if (dest.flags & (DST_SLOT_REF)) {
if (dst_equals(dest.constant, src.constant))
return;
} else {
return;
}
}
if (dstc_sequal(dest, src)) return;
/* Types of slots - src */
/* constants */
@ -772,6 +799,10 @@ DstSlot dstc_value(DstFopts opts) {
if (opts.flags & DST_FOPTS_TAIL) {
ret = dstc_return(opts.compiler, opts.sourcemap, ret);
}
if (opts.flags & DST_FOPTS_HINT && !dstc_sequal(opts.hint, ret)) {
dstc_copy(opts.compiler, opts.sourcemap, opts.hint, ret);
ret = opts.hint;
}
opts.compiler->recursion_guard++;
return ret;
}
@ -820,6 +851,9 @@ DstFuncDef *dstc_pop_funcdef(DstCompiler *c) {
def->flags = 0;
if (scope.flags & DST_SCOPE_ENV) {
def->flags |= DST_FUNCDEF_FLAG_NEEDSENV;
if (def->environments_length == 0) {
def->environments_length = 1;
}
}
/* Pop the scope */
@ -888,6 +922,40 @@ DstFunction *dst_compile_func(DstCompileResult res) {
}
DstFunction *func = dst_gcalloc(DST_MEMORY_FUNCTION, sizeof(DstFunction));
func->def = res.funcdef;
func->envs = NULL;
if (res.funcdef->flags & DST_FUNCDEF_FLAG_NEEDSENV) {
func->envs = malloc(sizeof(DstFuncEnv *));
if (NULL == func->envs) {
DST_OUT_OF_MEMORY;
}
func->envs[0] = NULL;
} else {
func->envs = NULL;
}
return func;
}
/* C Function for compiling */
int dst_compile_cfun(DstArgs args) {
DstCompileOptions opts;
DstCompileResult res;
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) {
DstFunction *fun = dst_compile_func(res);
return dst_return(args, dst_wrap_function(fun));
} else {
t = dst_table(2);
dst_table_put(t, dst_cstringv("error"), dst_wrap_string(res.error));
dst_table_put(t, dst_cstringv("error-start"), dst_wrap_integer(res.error_start));
dst_table_put(t, dst_cstringv("error-end"), dst_wrap_integer(res.error_end));
return dst_return(args, dst_wrap_table(t));
}
}

View File

@ -224,6 +224,9 @@ void dstc_cerror(DstCompiler *c, const Dst *sourcemap, const char *m);
/* Dispatch to correct form compiler */
DstSlot dstc_value(DstFopts opts);
/* 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);
@ -233,6 +236,7 @@ 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);
void dstc_popscope_keepslot(DstCompiler *c, DstSlot retslot);
DstFuncDef *dstc_pop_funcdef(DstCompiler *c);
/* Create a destory slots */

View File

@ -308,7 +308,7 @@ DstSlot dstc_do(DstFopts opts, int32_t argn, const Dst *argv) {
dstc_freeslot(opts.compiler, ret);
}
}
dstc_popscope(opts.compiler);
dstc_popscope_keepslot(opts.compiler, ret);
return ret;
}
@ -501,10 +501,7 @@ DstSlot dstc_fn(DstFopts opts, int32_t argn, const Dst *argv) {
if (arity + varargs > def->slotcount) def->slotcount = arity + varargs;
/* Instantiate closure */
ret.flags = 0;
ret.envindex = 0;
ret.constant = dst_wrap_nil();
ret.index = dstc_lsloti(c);
ret = dstc_gettarget(opts);
localslot = ret.index > 0xF0 ? 0xF1 : ret.index;
dstc_emit(c, sm,

View File

@ -565,3 +565,36 @@ DstParseResult dst_parsec(const char *src) {
while (src[len]) ++len;
return dst_parse((const uint8_t *)src, len);
}
/* C Function parser */
int dst_parse_cfun(DstArgs args) {
const uint8_t *src;
int32_t len;
DstParseResult res;
const char *status_string = "ok";
DstTable *t;
if (args.n < 1) return dst_throw(args, "expected at least on argument");
if (!dst_chararray_view(args.v[0], &src, &len)) return dst_throw(args, "expected string/buffer");
res = dst_parse(src, len);
t = dst_table(4);
switch (res.status) {
case DST_PARSE_OK:
status_string = "ok";
break;
case DST_PARSE_ERROR:
status_string = "error";
break;
case DST_PARSE_NODATA:
status_string = "nodata";
break;
case DST_PARSE_UNEXPECTED_EOS:
status_string = "eos";
break;
}
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));
return dst_return(args, dst_wrap_table(t));
}

View File

@ -30,63 +30,6 @@ int dst_stl_push(DstArgs args) {
return dst_return(args, args.v[0]);
}
int dst_stl_parse(DstArgs args) {
const uint8_t *src;
int32_t len;
DstParseResult res;
const char *status_string = "ok";
DstTable *t;
if (args.n < 1) return dst_throw(args, "expected at least on argument");
if (!dst_chararray_view(args.v[0], &src, &len)) return dst_throw(args, "expected string/buffer");
res = dst_parse(src, len);
t = dst_table(4);
switch (res.status) {
case DST_PARSE_OK:
status_string = "ok";
break;
case DST_PARSE_ERROR:
status_string = "error";
break;
case DST_PARSE_NODATA:
status_string = "nodata";
break;
case DST_PARSE_UNEXPECTED_EOS:
status_string = "eos";
break;
}
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));
return dst_return(args, dst_wrap_table(t));
}
int dst_stl_compile(DstArgs args) {
DstCompileOptions opts;
DstCompileResult res;
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) {
DstFunction *fun = dst_compile_func(res);
return dst_return(args, dst_wrap_function(fun));
} else {
t = dst_table(2);
dst_table_put(t, dst_cstringv("error"), dst_wrap_string(res.error));
dst_table_put(t, dst_cstringv("error-start"), dst_wrap_integer(res.error_start));
dst_table_put(t, dst_cstringv("error-end"), dst_wrap_integer(res.error_end));
return dst_return(args, dst_wrap_table(t));
}
}
int dst_stl_exit(DstArgs args) {
int32_t exitcode = 0;
if (args.n > 0) {
@ -147,28 +90,6 @@ int dst_stl_buffer_to_string(DstArgs args) {
return dst_return(args, dst_wrap_string(dst_string(b->data, b->count)));
}
int dst_stl_asm(DstArgs args) {
DstAssembleOptions opts;
DstAssembleResult res;
if (args.n < 1) return dst_throw(args, "expected assembly source");
opts.source = args.v[0];
opts.flags = 0;
res = dst_asm(opts);
if (res.status == DST_ASSEMBLE_OK) {
return dst_return(args, dst_wrap_function(dst_asm_func(res)));
} else {
return dst_throwv(args, dst_wrap_string(res.error));
}
}
int dst_stl_disasm(DstArgs args) {
DstFunction *f;
if (args.n < 1 || !dst_checktype(args.v[0], DST_FUNCTION))
return dst_throw(args, "expected function");
f = dst_unwrap_function(args.v[0]);
return dst_return(args, dst_disasm(f->def));
}
int dst_cfun_tuple(DstArgs args) {
return dst_return(args, dst_wrap_tuple(dst_tuple_n(args.v, args.n)));
}
@ -312,8 +233,6 @@ Dst dst_stl_env() {
dst_module_def(module, "native", dst_wrap_cfunction(dst_load_native));
dst_module_def(module, "push", dst_wrap_cfunction(dst_stl_push));
dst_module_def(module, "parse", dst_wrap_cfunction(dst_stl_parse));
dst_module_def(module, "compile", dst_wrap_cfunction(dst_stl_compile));
dst_module_def(module, "print", dst_wrap_cfunction(dst_stl_print));
dst_module_def(module, "describe", dst_wrap_cfunction(dst_stl_describe));
dst_module_def(module, "string", dst_wrap_cfunction(dst_stl_string));
@ -326,14 +245,17 @@ Dst dst_stl_env() {
dst_module_def(module, "status", dst_wrap_cfunction(dst_stl_status));
dst_module_def(module, "buffer", dst_wrap_cfunction(dst_stl_buffer));
dst_module_def(module, "gensym", dst_wrap_cfunction(dst_stl_gensym));
dst_module_def(module, "asm", dst_wrap_cfunction(dst_stl_asm));
dst_module_def(module, "disasm", dst_wrap_cfunction(dst_stl_disasm));
dst_module_def(module, "get", dst_wrap_cfunction(dst_stl_get));
dst_module_def(module, "put", dst_wrap_cfunction(dst_stl_put));
dst_module_def(module, "length", dst_wrap_cfunction(dst_stl_length));
dst_module_def(module, "gccollect", dst_wrap_cfunction(dst_stl_gccollect));
dst_module_def(module, "type", dst_wrap_cfunction(dst_stl_type));
dst_module_def(module, "exit!", dst_wrap_cfunction(dst_stl_exit));
dst_module_def(module, "exit", dst_wrap_cfunction(dst_stl_exit));
dst_module_def(module, "parse", dst_wrap_cfunction(dst_parse_cfun));
dst_module_def(module, "compile", dst_wrap_cfunction(dst_compile_cfun));
dst_module_def(module, "asm", dst_wrap_cfunction(dst_asm_cfun));
dst_module_def(module, "disasm", dst_wrap_cfunction(dst_disasm_cfun));
/* Allow references to the environment */
dst_module_def(module, "_env", ret);

View File

@ -422,15 +422,16 @@ static int dst_continue(Dst *returnreg) {
case DOP_CLOSURE:
{
int32_t i;
int32_t i, elen;
DstFunction *fn;
DstFuncDef *fd;
vm_assert((int32_t)oparg(2, 0xFFFF) < func->def->defs_length, "invalid funcdef");
fd = func->def->defs[(int32_t)oparg(2, 0xFFFF)];
fn = dst_gcalloc(DST_MEMORY_FUNCTION, sizeof(DstFunction));
fn->def = fd;
if (fd->environments_length) {
fn->envs = malloc(sizeof(DstFuncEnv *) * fd->environments_length);
elen = fd->environments_length;
if (elen) {
fn->envs = malloc(sizeof(DstFuncEnv *) * elen);
if (NULL == fn->envs) {
DST_OUT_OF_MEMORY;
}

View File

@ -93,6 +93,21 @@
(assert (= 93 (f91 103)), "f91(103) = 93")
(assert (= 94 (f91 104)), "f91(104) = 94")
# Fibonacci
(def fib (do (var fib nil) (varset! fib (fn [n] (if (< n 2) n (+ (fib (- n 1)) (fib (- n 2))))))))
(assert (= (fib 0) 0) "fib(0)")
(assert (= (fib 1) 1) "fib(1)")
(assert (= (fib 2) 1) "fib(2)")
(assert (= (fib 3) 2) "fib(3)")
(assert (= (fib 4) 3) "fib(4)")
(assert (= (fib 5) 5) "fib(5)")
(assert (= (fib 6) 8) "fib(6)")
(assert (= (fib 7) 13) "fib(7)")
(assert (= (fib 8) 21) "fib(8)")
(assert (= (fib 9) 34) "fib(9)")
(assert (= (fib 10) 55) "fib(10)")
(assert (= "hello" :hello) "keyword syntax for strings")
(assert (= '(1 2 3) (quote (1 2 3)) (tuple 1 2 3)) "quote shorthand")
@ -226,4 +241,4 @@
# report
(print "\n" num-tests-passed " of " num-tests-run " tests passed\n")
(if (not= num-tests-passed num-tests-run) (exit! 1))
(if (not= num-tests-passed num-tests-run) (exit 1))

View File

@ -142,6 +142,8 @@ DstAssembleResult dst_asm(DstAssembleOptions opts);
DstFunction *dst_asm_func(DstAssembleResult result);
Dst dst_disasm(DstFuncDef *def);
Dst dst_asm_decode_instruction(uint32_t instr);
int dst_asm_cfun(DstArgs args);
int dst_disasm_cfun(DstArgs args);
/* Treat similar types through uniform interfaces for iteration */
int dst_seq_view(Dst seq, const Dst **data, int32_t *len);
@ -171,6 +173,7 @@ void dst_setindex(Dst ds, Dst value, int32_t index);
/* Parsing */
DstParseResult dst_parse(const uint8_t *src, int32_t len);
DstParseResult dst_parsec(const char *src);
int dst_parse_cfun(DstArgs args);
/* Native */
DstCFunction dst_native(const char *name, const uint8_t **error);
@ -199,6 +202,7 @@ void dst_module_var(DstTable *module, const char *name, Dst val);
/* Compile */
DstCompileResult dst_compile(DstCompileOptions opts);
DstFunction *dst_compile_func(DstCompileResult result);
int dst_compile_cfun(DstArgs args);
/* STL */
Dst dst_stl_env();