mirror of
https://github.com/janet-lang/janet
synced 2024-12-26 00:10:27 +00:00
More work on compiler. Still has memory leak?
This commit is contained in:
parent
6ca5a76286
commit
f817610d4a
@ -32,7 +32,7 @@
|
|||||||
#include <readline/history.h>
|
#include <readline/history.h>
|
||||||
|
|
||||||
/* Compile and run an ast */
|
/* Compile and run an ast */
|
||||||
int debug_compile_and_run(Gst *vm, GstValue ast, GstValue env) {
|
int debug_compile_and_run(Gst *vm, GstValue ast, GstValue last) {
|
||||||
GstCompiler c;
|
GstCompiler c;
|
||||||
GstValue func;
|
GstValue func;
|
||||||
/* Try to compile generated AST */
|
/* Try to compile generated AST */
|
||||||
@ -40,7 +40,8 @@ int debug_compile_and_run(Gst *vm, GstValue ast, GstValue env) {
|
|||||||
gst_compiler_usemodule(&c, "std");
|
gst_compiler_usemodule(&c, "std");
|
||||||
gst_compiler_usemodule(&c, "std.io");
|
gst_compiler_usemodule(&c, "std.io");
|
||||||
gst_compiler_usemodule(&c, "std.parse");
|
gst_compiler_usemodule(&c, "std.parse");
|
||||||
gst_compiler_globals(&c, env);
|
gst_compiler_usemodule(&c, "std.compile");
|
||||||
|
gst_compiler_global(&c, "_", last);
|
||||||
func = gst_wrap_function(gst_compiler_compile(&c, ast));
|
func = gst_wrap_function(gst_compiler_compile(&c, ast));
|
||||||
/* Check for compilation errors */
|
/* Check for compilation errors */
|
||||||
if (c.error) {
|
if (c.error) {
|
||||||
@ -105,7 +106,6 @@ int debug_run(Gst *vm, FILE *in) {
|
|||||||
int debug_repl(Gst *vm) {
|
int debug_repl(Gst *vm) {
|
||||||
const char *buffer, *reader;
|
const char *buffer, *reader;
|
||||||
GstParser p;
|
GstParser p;
|
||||||
GstValue *st;
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
/* Init parser */
|
/* Init parser */
|
||||||
gst_parser(&p, vm);
|
gst_parser(&p, vm);
|
||||||
@ -131,10 +131,7 @@ int debug_repl(Gst *vm) {
|
|||||||
printf("Unexpected end of source\n");
|
printf("Unexpected end of source\n");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
/* Add _ to environemt */
|
if (!debug_compile_and_run(vm, gst_parse_consume(&p), vm->ret)) {
|
||||||
st = gst_struct_begin(vm, 1);
|
|
||||||
gst_struct_put(st, gst_string_cv(vm, "_"), vm->ret);
|
|
||||||
if (!debug_compile_and_run(vm, gst_parse_consume(&p), gst_wrap_struct(gst_struct_end(vm, st)))) {
|
|
||||||
printf("%s\n", gst_to_string(vm, vm->ret));
|
printf("%s\n", gst_to_string(vm, vm->ret));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -147,6 +144,7 @@ int main(int argc, const char **argv) {
|
|||||||
gst_init(&vm);
|
gst_init(&vm);
|
||||||
gst_stl_load(&vm);
|
gst_stl_load(&vm);
|
||||||
gst_parse_load(&vm);
|
gst_parse_load(&vm);
|
||||||
|
gst_compile_load(&vm);
|
||||||
if (argc > 1) {
|
if (argc > 1) {
|
||||||
const char *filename;
|
const char *filename;
|
||||||
FILE *f;
|
FILE *f;
|
||||||
|
235
core/compile.c
235
core/compile.c
@ -72,6 +72,7 @@ struct SlotTracker {
|
|||||||
Slot *slots;
|
Slot *slots;
|
||||||
uint32_t count;
|
uint32_t count;
|
||||||
uint32_t capacity;
|
uint32_t capacity;
|
||||||
|
SlotTracker *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* A GstScope is a lexical scope in the program. It is
|
/* A GstScope is a lexical scope in the program. It is
|
||||||
@ -88,6 +89,8 @@ struct GstScope {
|
|||||||
uint16_t *freeHeap;
|
uint16_t *freeHeap;
|
||||||
GstTable *literals;
|
GstTable *literals;
|
||||||
GstArray *literalsArray;
|
GstArray *literalsArray;
|
||||||
|
GstTable *namedLiterals;
|
||||||
|
GstTable *nilNamedLiterals; /* Work around tables not containg nil */
|
||||||
GstTable *locals;
|
GstTable *locals;
|
||||||
GstScope *parent;
|
GstScope *parent;
|
||||||
};
|
};
|
||||||
@ -142,10 +145,14 @@ static GstScope *compiler_push_scope(GstCompiler *c, int sameFunction) {
|
|||||||
scope->nextLocal = c->tail->nextLocal;
|
scope->nextLocal = c->tail->nextLocal;
|
||||||
scope->literals = c->tail->literals;
|
scope->literals = c->tail->literals;
|
||||||
scope->literalsArray = c->tail->literalsArray;
|
scope->literalsArray = c->tail->literalsArray;
|
||||||
|
scope->namedLiterals = c->tail->namedLiterals;
|
||||||
|
scope->nilNamedLiterals = c->tail->nilNamedLiterals;
|
||||||
} else {
|
} else {
|
||||||
scope->nextLocal = 0;
|
scope->nextLocal = 0;
|
||||||
scope->literals = gst_table(c->vm, 10);
|
scope->literals = gst_table(c->vm, 10);
|
||||||
scope->literalsArray = gst_array(c->vm, 10);
|
scope->literalsArray = gst_array(c->vm, 10);
|
||||||
|
scope->namedLiterals = gst_table(c->vm, 10);
|
||||||
|
scope->nilNamedLiterals = gst_table(c->vm, 10);
|
||||||
}
|
}
|
||||||
c->tail = scope;
|
c->tail = scope;
|
||||||
return scope;
|
return scope;
|
||||||
@ -204,6 +211,9 @@ static void tracker_init(GstCompiler *c, SlotTracker *tracker) {
|
|||||||
tracker->slots = gst_alloc(c->vm, 10 * sizeof(Slot));
|
tracker->slots = gst_alloc(c->vm, 10 * sizeof(Slot));
|
||||||
tracker->count = 0;
|
tracker->count = 0;
|
||||||
tracker->capacity = 10;
|
tracker->capacity = 10;
|
||||||
|
/* Push to tracker stack */
|
||||||
|
tracker->next = (SlotTracker *) c->trackers;
|
||||||
|
c->trackers = tracker;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Free up a slot if it is a temporary slot (does not
|
/* Free up a slot if it is a temporary slot (does not
|
||||||
@ -300,6 +310,8 @@ static void compiler_tracker_free(GstCompiler *c, GstScope *scope, SlotTracker *
|
|||||||
for (i = tracker->count - 1; i < tracker->count; --i) {
|
for (i = tracker->count - 1; i < tracker->count; --i) {
|
||||||
compiler_drop_slot(c, scope, tracker->slots[i]);
|
compiler_drop_slot(c, scope, tracker->slots[i]);
|
||||||
}
|
}
|
||||||
|
/* Pop from tracker stack */
|
||||||
|
c->trackers = tracker->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add a new Slot to a slot tracker. */
|
/* Add a new Slot to a slot tracker. */
|
||||||
@ -350,7 +362,7 @@ static uint16_t compiler_declare_symbol(GstCompiler *c, GstScope *scope, GstValu
|
|||||||
|
|
||||||
/* Try to resolve a symbol. If the symbol can be resovled, return true and
|
/* Try to resolve a symbol. If the symbol can be resovled, return true and
|
||||||
* pass back the level and index by reference. */
|
* pass back the level and index by reference. */
|
||||||
static int symbol_resolve(GstCompiler *c, GstValue x, uint16_t *level, uint16_t *index) {
|
static int symbol_resolve(GstCompiler *c, GstValue x, uint16_t *level, uint16_t *index, GstValue *out) {
|
||||||
GstScope *scope = c->tail;
|
GstScope *scope = c->tail;
|
||||||
uint32_t currentLevel = scope->level;
|
uint32_t currentLevel = scope->level;
|
||||||
while (scope) {
|
while (scope) {
|
||||||
@ -360,7 +372,18 @@ static int symbol_resolve(GstCompiler *c, GstValue x, uint16_t *level, uint16_t
|
|||||||
*index = (uint16_t) check.data.integer;
|
*index = (uint16_t) check.data.integer;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
/* Check for named literals */
|
||||||
|
check = gst_table_get(scope->namedLiterals, x);
|
||||||
|
if (check.type != GST_NIL) {
|
||||||
|
*out = check;
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
/* Check for nil named literal */
|
||||||
|
check = gst_table_get(scope->nilNamedLiterals, x);
|
||||||
|
if (check.type != GST_NIL) {
|
||||||
|
*out = gst_wrap_nil();
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
scope = scope->parent;
|
scope = scope->parent;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@ -377,23 +400,6 @@ static int symbol_resolve(GstCompiler *c, GstValue x, uint16_t *level, uint16_t
|
|||||||
* as the location on the stack. */
|
* as the location on the stack. */
|
||||||
static Slot compile_value(GstCompiler *c, FormOptions opts, GstValue x);
|
static Slot compile_value(GstCompiler *c, FormOptions opts, GstValue x);
|
||||||
|
|
||||||
/* Compile a structure that evaluates to a literal value. Useful
|
|
||||||
* for objects like strings, or anything else that cannot be instatiated
|
|
||||||
* from bytecode and doesn't do anything in the AST. */
|
|
||||||
static Slot compile_literal(GstCompiler *c, FormOptions opts, GstValue x) {
|
|
||||||
GstScope *scope = c->tail;
|
|
||||||
GstBuffer *buffer = c->buffer;
|
|
||||||
Slot ret;
|
|
||||||
uint16_t literalIndex;
|
|
||||||
if (opts.resultUnused) return nil_slot();
|
|
||||||
ret = compiler_get_target(c, opts);
|
|
||||||
literalIndex = compiler_add_literal(c, scope, x);
|
|
||||||
gst_buffer_push_u16(c->vm, buffer, GST_OP_CST);
|
|
||||||
gst_buffer_push_u16(c->vm, buffer, ret.index);
|
|
||||||
gst_buffer_push_u16(c->vm, buffer, literalIndex);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Compile boolean, nil, and number values. */
|
/* Compile boolean, nil, and number values. */
|
||||||
static Slot compile_nonref_type(GstCompiler *c, FormOptions opts, GstValue x) {
|
static Slot compile_nonref_type(GstCompiler *c, FormOptions opts, GstValue x) {
|
||||||
GstBuffer *buffer = c->buffer;
|
GstBuffer *buffer = c->buffer;
|
||||||
@ -430,17 +436,48 @@ static Slot compile_nonref_type(GstCompiler *c, FormOptions opts, GstValue x) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Compile a structure that evaluates to a literal value. Useful
|
||||||
|
* for objects like strings, or anything else that cannot be instantiated
|
||||||
|
* from bytecode and doesn't do anything in the AST. */
|
||||||
|
static Slot compile_literal(GstCompiler *c, FormOptions opts, GstValue x) {
|
||||||
|
GstScope *scope = c->tail;
|
||||||
|
GstBuffer *buffer = c->buffer;
|
||||||
|
Slot ret;
|
||||||
|
uint16_t literalIndex;
|
||||||
|
if (opts.resultUnused) return nil_slot();
|
||||||
|
switch (x.type) {
|
||||||
|
case GST_INTEGER:
|
||||||
|
case GST_REAL:
|
||||||
|
case GST_BOOLEAN:
|
||||||
|
case GST_NIL:
|
||||||
|
return compile_nonref_type(c, opts, x);
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ret = compiler_get_target(c, opts);
|
||||||
|
literalIndex = compiler_add_literal(c, scope, x);
|
||||||
|
gst_buffer_push_u16(c->vm, buffer, GST_OP_CST);
|
||||||
|
gst_buffer_push_u16(c->vm, buffer, ret.index);
|
||||||
|
gst_buffer_push_u16(c->vm, buffer, literalIndex);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/* Compile a symbol. Resolves any kind of symbol. */
|
/* Compile a symbol. Resolves any kind of symbol. */
|
||||||
static Slot compile_symbol(GstCompiler *c, FormOptions opts, GstValue sym) {
|
static Slot compile_symbol(GstCompiler *c, FormOptions opts, GstValue sym) {
|
||||||
|
GstValue lit = gst_wrap_nil();
|
||||||
GstBuffer * buffer = c->buffer;
|
GstBuffer * buffer = c->buffer;
|
||||||
uint16_t index = 0;
|
uint16_t index = 0;
|
||||||
uint16_t level = 0;
|
uint16_t level = 0;
|
||||||
Slot ret;
|
Slot ret;
|
||||||
if (opts.resultUnused) return nil_slot();
|
int status = symbol_resolve(c, sym, &level, &index, &lit);
|
||||||
if (!symbol_resolve(c, sym, &level, &index)) {
|
if (!status) {
|
||||||
c_error(c, "undefined symbol");
|
c_error(c, "undefined symbol");
|
||||||
}
|
}
|
||||||
if (level > 0) {
|
if (opts.resultUnused) return nil_slot();
|
||||||
|
if (status == 2) {
|
||||||
|
/* We have a named literal */
|
||||||
|
return compile_literal(c, opts, lit);
|
||||||
|
} else if (level > 0) {
|
||||||
/* We have an upvalue */
|
/* We have an upvalue */
|
||||||
ret = compiler_get_target(c, opts);
|
ret = compiler_get_target(c, opts);
|
||||||
gst_buffer_push_u16(c->vm, buffer, GST_OP_UPV);
|
gst_buffer_push_u16(c->vm, buffer, GST_OP_UPV);
|
||||||
@ -468,15 +505,20 @@ static Slot compile_symbol(GstCompiler *c, FormOptions opts, GstValue sym) {
|
|||||||
|
|
||||||
/* Compile an assignment operation */
|
/* Compile an assignment operation */
|
||||||
static Slot compile_assign(GstCompiler *c, FormOptions opts, GstValue left, GstValue right) {
|
static Slot compile_assign(GstCompiler *c, FormOptions opts, GstValue left, GstValue right) {
|
||||||
|
GstValue lit = gst_wrap_nil();
|
||||||
GstScope *scope = c->tail;
|
GstScope *scope = c->tail;
|
||||||
GstBuffer *buffer = c->buffer;
|
GstBuffer *buffer = c->buffer;
|
||||||
FormOptions subOpts;
|
FormOptions subOpts;
|
||||||
uint16_t target = 0;
|
uint16_t target = 0;
|
||||||
uint16_t level = 0;
|
uint16_t level = 0;
|
||||||
Slot slot;
|
Slot slot;
|
||||||
|
int status;
|
||||||
subOpts.isTail = 0;
|
subOpts.isTail = 0;
|
||||||
subOpts.resultUnused = 0;
|
subOpts.resultUnused = 0;
|
||||||
if (symbol_resolve(c, left, &level, &target)) {
|
status = symbol_resolve(c, left, &level, &target, &lit);
|
||||||
|
if (status == 2) {
|
||||||
|
c_error(c, "cannot set binding");
|
||||||
|
} else if (status == 1) {
|
||||||
/* Check if we have an up value. Otherwise, it's just a normal
|
/* Check if we have an up value. Otherwise, it's just a normal
|
||||||
* local variable */
|
* local variable */
|
||||||
if (level != 0) {
|
if (level != 0) {
|
||||||
@ -1028,39 +1070,32 @@ static Slot compile_value(GstCompiler *c, FormOptions opts, GstValue x) {
|
|||||||
void gst_compiler(GstCompiler *c, Gst *vm) {
|
void gst_compiler(GstCompiler *c, Gst *vm) {
|
||||||
c->vm = vm;
|
c->vm = vm;
|
||||||
c->buffer = gst_buffer(vm, 128);
|
c->buffer = gst_buffer(vm, 128);
|
||||||
c->env = gst_array(vm, 10);
|
|
||||||
c->tail = NULL;
|
c->tail = NULL;
|
||||||
c->error = NULL;
|
c->error = NULL;
|
||||||
|
c->trackers = NULL;
|
||||||
compiler_push_scope(c, 0);
|
compiler_push_scope(c, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add a global variable */
|
/* Add a global variable */
|
||||||
void gst_compiler_global(GstCompiler *c, const char *name, GstValue x) {
|
void gst_compiler_global(GstCompiler *c, const char *name, GstValue x) {
|
||||||
|
GstScope *scope = c->tail;
|
||||||
GstValue sym = gst_string_cv(c->vm, name);
|
GstValue sym = gst_string_cv(c->vm, name);
|
||||||
compiler_declare_symbol(c, c->tail, sym);
|
if (x.type == GST_NIL)
|
||||||
gst_array_push(c->vm, c->env, x);
|
gst_table_put(c->vm, scope->nilNamedLiterals, sym, gst_wrap_boolean(1));
|
||||||
|
else
|
||||||
|
gst_table_put(c->vm, scope->namedLiterals, sym, x);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add many global variables */
|
/* Add many global variables */
|
||||||
void gst_compiler_globals(GstCompiler *c, GstValue env) {
|
void gst_compiler_globals(GstCompiler *c, GstValue env) {
|
||||||
|
GstScope *scope = c->tail;
|
||||||
|
const GstValue *data;
|
||||||
|
uint32_t len;
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
if (env.type == GST_TABLE) {
|
if (gst_hashtable_view(env, &data, &len))
|
||||||
GstTable *t = env.data.table;
|
for (i = 0; i < len; i += 2)
|
||||||
for (i = 0; i < t->capacity; i += 2) {
|
if (data[i].type == GST_STRING)
|
||||||
if (t->data[i].type == GST_STRING) {
|
gst_table_put(c->vm, scope->namedLiterals, data[i], data[i + 1]);
|
||||||
compiler_declare_symbol(c, c->tail, t->data[i]);
|
|
||||||
gst_array_push(c->vm, c->env, t->data[i + 1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (env.type == GST_STRUCT) {
|
|
||||||
const GstValue *st = env.data.st;
|
|
||||||
for (i = 0; i < gst_struct_capacity(st); i += 2) {
|
|
||||||
if (st[i].type == GST_STRING) {
|
|
||||||
compiler_declare_symbol(c, c->tail, st[i]);
|
|
||||||
gst_array_push(c->vm, c->env, st[i + 1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Use a module that was loaded into the vm */
|
/* Use a module that was loaded into the vm */
|
||||||
@ -1076,6 +1111,7 @@ GstFunction *gst_compiler_compile(GstCompiler *c, GstValue form) {
|
|||||||
GstFuncDef *def;
|
GstFuncDef *def;
|
||||||
if (setjmp(c->onError)) {
|
if (setjmp(c->onError)) {
|
||||||
/* Clear all but root scope */
|
/* Clear all but root scope */
|
||||||
|
c->trackers = NULL;
|
||||||
if (c->tail)
|
if (c->tail)
|
||||||
c->tail->parent = NULL;
|
c->tail->parent = NULL;
|
||||||
if (c->error == NULL)
|
if (c->error == NULL)
|
||||||
@ -1088,16 +1124,10 @@ GstFunction *gst_compiler_compile(GstCompiler *c, GstValue form) {
|
|||||||
compiler_return(c, compile_value(c, opts, form));
|
compiler_return(c, compile_value(c, opts, form));
|
||||||
def = compiler_gen_funcdef(c, c->buffer->count, 0);
|
def = compiler_gen_funcdef(c, c->buffer->count, 0);
|
||||||
{
|
{
|
||||||
uint32_t envSize = c->env->count;
|
|
||||||
GstFuncEnv *env = gst_alloc(c->vm, sizeof(GstFuncEnv));
|
GstFuncEnv *env = gst_alloc(c->vm, sizeof(GstFuncEnv));
|
||||||
GstFunction *func = gst_alloc(c->vm, sizeof(GstFunction));
|
GstFunction *func = gst_alloc(c->vm, sizeof(GstFunction));
|
||||||
if (envSize) {
|
|
||||||
env->values = gst_alloc(c->vm, sizeof(GstValue) * envSize);
|
|
||||||
gst_memcpy(env->values, c->env->data, envSize * sizeof(GstValue));
|
|
||||||
} else {
|
|
||||||
env->values = NULL;
|
env->values = NULL;
|
||||||
}
|
env->stackOffset = 0;
|
||||||
env->stackOffset = envSize;
|
|
||||||
env->thread = NULL;
|
env->thread = NULL;
|
||||||
func->parent = NULL;
|
func->parent = NULL;
|
||||||
func->def = def;
|
func->def = def;
|
||||||
@ -1105,3 +1135,108 @@ GstFunction *gst_compiler_compile(GstCompiler *c, GstValue form) {
|
|||||||
return func;
|
return func;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/***/
|
||||||
|
/* Stl */
|
||||||
|
/***/
|
||||||
|
|
||||||
|
/* GC mark mark all memory used by the compiler */
|
||||||
|
static void gst_compiler_mark(Gst *vm, void *data, uint32_t len) {
|
||||||
|
SlotTracker *st;
|
||||||
|
GstScope *scope;
|
||||||
|
GstCompiler *c = (GstCompiler *) data;
|
||||||
|
if (len != sizeof(GstCompiler))
|
||||||
|
return;
|
||||||
|
/* Mark compiler */
|
||||||
|
gst_mark_value(vm, gst_wrap_buffer(c->buffer));
|
||||||
|
/* Mark trackers */
|
||||||
|
st = (SlotTracker *) c->trackers;
|
||||||
|
while (st) {
|
||||||
|
gst_mark_mem(vm, st->slots);
|
||||||
|
st = st->next;
|
||||||
|
}
|
||||||
|
/* Mark scopes */
|
||||||
|
scope = c->tail;
|
||||||
|
while (scope) {
|
||||||
|
gst_mark_mem(vm, scope->freeHeap);
|
||||||
|
gst_mark_value(vm, gst_wrap_array(scope->literalsArray));
|
||||||
|
gst_mark_value(vm, gst_wrap_table(scope->locals));
|
||||||
|
gst_mark_value(vm, gst_wrap_table(scope->literals));
|
||||||
|
gst_mark_value(vm, gst_wrap_table(scope->namedLiterals));
|
||||||
|
gst_mark_value(vm, gst_wrap_table(scope->nilNamedLiterals));
|
||||||
|
scope = scope->parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Compiler userdata type */
|
||||||
|
static const GstUserType gst_stl_compilertype = {
|
||||||
|
"std.compiler",
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
&gst_compiler_mark
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Create a compiler userdata */
|
||||||
|
static int gst_stl_compiler(Gst *vm) {
|
||||||
|
GstCompiler *c = gst_userdata(vm, sizeof(GstCompiler), &gst_stl_compilertype);
|
||||||
|
gst_compiler(c, vm);
|
||||||
|
gst_c_return(vm, gst_wrap_userdata(c));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add a binding to the compiler's current scope. */
|
||||||
|
static int gst_stl_compiler_binding(Gst *vm) {
|
||||||
|
GstCompiler *c = gst_check_userdata(vm, 0, &gst_stl_compilertype);
|
||||||
|
GstScope *scope;
|
||||||
|
GstValue sym;
|
||||||
|
const uint8_t *data;
|
||||||
|
uint32_t len;
|
||||||
|
if (!c)
|
||||||
|
gst_c_throwc(vm, "expected compiler");
|
||||||
|
if (!gst_chararray_view(gst_arg(vm, 1), &data, &len))
|
||||||
|
gst_c_throwc(vm, "expected string/buffer");
|
||||||
|
scope = c->tail;
|
||||||
|
sym = gst_wrap_string(gst_string_b(c->vm, data, len));
|
||||||
|
gst_table_put(c->vm, scope->namedLiterals, sym, gst_arg(vm, 2));
|
||||||
|
gst_c_return(vm, gst_wrap_userdata(c));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Compile a value */
|
||||||
|
static int gst_stl_compiler_compile(Gst *vm) {
|
||||||
|
GstFunction *ret;
|
||||||
|
GstCompiler *c = gst_check_userdata(vm, 0, &gst_stl_compilertype);
|
||||||
|
if (!c)
|
||||||
|
gst_c_throwc(vm, "expected compiler");
|
||||||
|
ret = gst_compiler_compile(c, gst_arg(vm, 1));
|
||||||
|
if (ret == NULL)
|
||||||
|
gst_c_throwc(vm, c->error);
|
||||||
|
gst_c_return(vm, gst_wrap_function(ret));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Use an environment during compilation. Names that are declared more than
|
||||||
|
* once should use their final declared value. */
|
||||||
|
static int gst_stl_compiler_bindings(Gst *vm) {
|
||||||
|
GstValue env;
|
||||||
|
GstCompiler *c = gst_check_userdata(vm, 0, &gst_stl_compilertype);
|
||||||
|
if (!c)
|
||||||
|
gst_c_throwc(vm, "expected compiler");
|
||||||
|
env = gst_arg(vm, 1);
|
||||||
|
if (env.type != GST_TABLE && env.type != GST_STRUCT)
|
||||||
|
gst_c_throwc(vm, "expected table/struct");
|
||||||
|
gst_compiler_globals(c, env);
|
||||||
|
gst_c_return(vm, gst_wrap_userdata(c));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The module stuff */
|
||||||
|
static const GstModuleItem gst_compile_module[] = {
|
||||||
|
{"compiler", gst_stl_compiler},
|
||||||
|
{"compile", gst_stl_compiler_compile},
|
||||||
|
{"binding!", gst_stl_compiler_binding},
|
||||||
|
{"bindings!", gst_stl_compiler_bindings},
|
||||||
|
{NULL, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Load compiler library */
|
||||||
|
void gst_compile_load(Gst *vm) {
|
||||||
|
gst_module_put(vm, "std.compile", gst_cmodule_struct(vm, gst_compile_module));
|
||||||
|
}
|
||||||
|
33
core/value.c
33
core/value.c
@ -96,6 +96,37 @@ static const uint8_t *string_description(Gst *vm, const char *title, void *point
|
|||||||
return gst_string_b(vm, buf, c - buf);
|
return gst_string_b(vm, buf, c - buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Gets the string value of userdata. Allocates memory, so is slower than
|
||||||
|
* string_description. */
|
||||||
|
static const uint8_t *string_udata(Gst *vm, const char *title, void *pointer) {
|
||||||
|
uint32_t strlen = 0;
|
||||||
|
uint8_t *c, *buf;
|
||||||
|
uint32_t i;
|
||||||
|
union {
|
||||||
|
uint8_t bytes[sizeof(void *)];
|
||||||
|
void *p;
|
||||||
|
} pbuf;
|
||||||
|
|
||||||
|
while (title[strlen]) ++strlen;
|
||||||
|
c = buf = gst_alloc(vm, strlen + 5 + 2 * sizeof(void *));
|
||||||
|
pbuf.p = pointer;
|
||||||
|
*c++ = '<';
|
||||||
|
for (i = 0; title[i]; ++i)
|
||||||
|
*c++ = ((uint8_t *)title) [i];
|
||||||
|
*c++ = ' ';
|
||||||
|
*c++ = '0';
|
||||||
|
*c++ = 'x';
|
||||||
|
for (i = sizeof(void *); i > 0; --i) {
|
||||||
|
uint8_t byte = pbuf.bytes[i - 1];
|
||||||
|
if (!byte) continue;
|
||||||
|
*c++ = HEX(byte >> 4);
|
||||||
|
*c++ = HEX(byte & 0xF);
|
||||||
|
}
|
||||||
|
*c++ = '>';
|
||||||
|
return gst_string_b(vm, buf, c - buf);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
#undef GST_BUFSIZE
|
#undef GST_BUFSIZE
|
||||||
|
|
||||||
/* Returns a string pointer or NULL if could not allocate memory. */
|
/* Returns a string pointer or NULL if could not allocate memory. */
|
||||||
@ -131,7 +162,7 @@ const uint8_t *gst_to_string(Gst *vm, GstValue x) {
|
|||||||
case GST_THREAD:
|
case GST_THREAD:
|
||||||
return string_description(vm, "thread", x.data.pointer);
|
return string_description(vm, "thread", x.data.pointer);
|
||||||
case GST_USERDATA:
|
case GST_USERDATA:
|
||||||
return string_description(vm, "userdata", x.data.pointer);
|
return string_udata(vm, gst_udata_type(x.data.pointer)->name, x.data.pointer);
|
||||||
case GST_FUNCENV:
|
case GST_FUNCENV:
|
||||||
return string_description(vm, "funcenv", x.data.pointer);
|
return string_description(vm, "funcenv", x.data.pointer);
|
||||||
case GST_FUNCDEF:
|
case GST_FUNCDEF:
|
||||||
|
@ -35,8 +35,8 @@ struct GstCompiler {
|
|||||||
const char *error;
|
const char *error;
|
||||||
jmp_buf onError;
|
jmp_buf onError;
|
||||||
GstScope *tail;
|
GstScope *tail;
|
||||||
GstArray *env;
|
|
||||||
GstBuffer *buffer;
|
GstBuffer *buffer;
|
||||||
|
void *trackers;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Initialize the Compiler */
|
/* Initialize the Compiler */
|
||||||
@ -54,4 +54,7 @@ void gst_compiler_usemodule(GstCompiler *c, const char *modulename);
|
|||||||
/* Compile a function that evaluates the given form. */
|
/* Compile a function that evaluates the given form. */
|
||||||
GstFunction *gst_compiler_compile(GstCompiler *c, GstValue form);
|
GstFunction *gst_compiler_compile(GstCompiler *c, GstValue form);
|
||||||
|
|
||||||
|
/* Load the library */
|
||||||
|
void gst_compile_load(Gst *vm);
|
||||||
|
|
||||||
#endif /* end of include guard: COMPILE_H_9VXF71HY */
|
#endif /* end of include guard: COMPILE_H_9VXF71HY */
|
||||||
|
@ -41,6 +41,11 @@
|
|||||||
#define gst_struct_capacity(t) (gst_struct_length(t) * 4)
|
#define gst_struct_capacity(t) (gst_struct_length(t) * 4)
|
||||||
#define gst_struct_hash(t) (gst_struct_raw(t)[1])
|
#define gst_struct_hash(t) (gst_struct_raw(t)[1])
|
||||||
|
|
||||||
|
/* Userdata utils */
|
||||||
|
#define gst_udata_header(u) ((GstUserdataHeader *)(u) - 1)
|
||||||
|
#define gst_udata_type(u) (gst_udata_header(u)->type)
|
||||||
|
#define gst_udata_size(u) (gst_udata_header(u)->size)
|
||||||
|
|
||||||
/* Memcpy for moving memory */
|
/* Memcpy for moving memory */
|
||||||
#ifndef gst_memcpy
|
#ifndef gst_memcpy
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -260,7 +265,7 @@ struct GstFunction {
|
|||||||
|
|
||||||
/* Defines a type for userdata */
|
/* Defines a type for userdata */
|
||||||
struct GstUserType {
|
struct GstUserType {
|
||||||
const char *id;
|
const char *name;
|
||||||
GstValue (*serialize)(Gst *vm, void *data, uint32_t len);
|
GstValue (*serialize)(Gst *vm, void *data, uint32_t len);
|
||||||
GstValue (*deserialize)(Gst *vm, GstValue in);
|
GstValue (*deserialize)(Gst *vm, GstValue in);
|
||||||
void (*finalize)(Gst *vm, void *data, uint32_t len);
|
void (*finalize)(Gst *vm, void *data, uint32_t len);
|
||||||
|
Loading…
Reference in New Issue
Block a user