diff --git a/compile.c b/compile.c index 824c73ca..4386fd78 100644 --- a/compile.c +++ b/compile.c @@ -1296,6 +1296,25 @@ void gst_compiler(GstCompiler *c, Gst *vm) { compiler_push_scope(c, 0); } +/* Add environment */ +void gst_compiler_env(GstCompiler *c, GstValue env) { + uint32_t i; + GstBucket *bucket; + /* Register everything in environment */ + if (env.type == GST_OBJECT) { + for (i = 0; i < env.data.object->capacity; ++i) { + bucket = env.data.object->buckets[i]; + while (bucket) { + if (bucket->key.type == GST_STRING) { + compiler_declare_symbol(c, c->tail, bucket->key); + gst_array_push(c->vm, c->env, bucket->value); + } + bucket = bucket->next; + } + } + } +} + /* Register a global for the compilation environment. */ void gst_compiler_add_global(GstCompiler *c, const char *name, GstValue x) { GstValue sym = gst_load_cstring(c->vm, name); diff --git a/compile.h b/compile.h index 0736b490..d347b929 100644 --- a/compile.h +++ b/compile.h @@ -20,6 +20,9 @@ struct GstCompiler { /* Initialize the Compiler */ void gst_compiler(GstCompiler *c, Gst *vm); +/* Register an environment for compilation */ +void gst_compiler_env(GstCompiler *c, GstValue env); + /* Register a global for the compilation environment. */ void gst_compiler_add_global(GstCompiler *c, const char *name, GstValue x); diff --git a/datatypes.h b/datatypes.h index 99a901cb..9df4b796 100644 --- a/datatypes.h +++ b/datatypes.h @@ -51,7 +51,6 @@ typedef struct GstBucket GstBucket; struct GstValue { GstType type; union { - /* The various types */ GstBoolean boolean; GstNumber number; GstArray *array; @@ -62,6 +61,7 @@ struct GstValue { GstCFunction cfunction; GstFunction *function; uint8_t *string; + char *cstring; /* Allias for ease of use from c */ /* Indirectly used union members */ uint16_t *u16p; GstFuncEnv *env; @@ -162,6 +162,8 @@ struct Gst { uint32_t black : 1; /* Thread */ GstThread *thread; + /* A GC root */ + GstValue rootenv; /* Return state */ const char *crash; GstValue ret; /* Returned value from gst_start. Also holds errors. */ diff --git a/gc.c b/gc.c index 832e9dd4..769ec831 100644 --- a/gc.c +++ b/gc.c @@ -222,13 +222,14 @@ void *gst_zalloc(Gst *vm, uint32_t size) { /* Run garbage collection */ void gst_collect(Gst *vm) { + GstValue temp; /* Thread can be null */ if (vm->thread) { - GstValue thread; - thread.type = GST_THREAD; - thread.data.thread = vm->thread; - gst_mark(vm, &thread); + temp.type = GST_THREAD; + temp.data.thread = vm->thread; + gst_mark(vm, &temp); } + gst_mark(vm, &vm->rootenv); gst_mark(vm, &vm->ret); gst_sweep(vm); vm->nextCollection = 0; diff --git a/gst.h b/gst.h index 0e3a876b..7616705a 100644 --- a/gst.h +++ b/gst.h @@ -9,5 +9,6 @@ #include "value.h" #include "stl.h" #include "thread.h" +#include "ds.h" #endif // gst_h_INCLUDED diff --git a/main.c b/main.c index 3976f113..2bcf91ad 100644 --- a/main.c +++ b/main.c @@ -3,14 +3,6 @@ #include "gst.h" #include "disasm.h" -/* Simple printer for gst strings */ -static void string_put(FILE *out, uint8_t * string) { - uint32_t i; - uint32_t len = gst_string_length(string); - for (i = 0; i < len; ++i) - fputc(string[i], out); -} - /* A simple repl for debugging */ void debug_repl(FILE *in, FILE *out) { char buffer[1024] = {0}; @@ -22,6 +14,10 @@ void debug_repl(FILE *in, FILE *out) { gst_init(&vm); + vm.rootenv.type = GST_OBJECT; + vm.rootenv.data.object = gst_object(&vm, 10); + gst_object_put(&vm, vm.rootenv.data.object, gst_load_cstring(&vm, "_ENV"), vm.rootenv); + for (;;) { /* Reset state */ @@ -61,9 +57,10 @@ void debug_repl(FILE *in, FILE *out) { /* Try to compile generated AST */ gst_compiler(&c, &vm); + func.type = GST_NIL; + gst_compiler_add_global(&c, "ans", func); gst_stl_load(&c); - /* Save last expression */ - gst_compiler_add_global(&c, "_", vm.ret); + gst_compiler_env(&c, vm.rootenv); func.type = GST_FUNCTION; func.data.function = gst_compiler_compile(&c, p.value); @@ -90,16 +87,15 @@ void debug_repl(FILE *in, FILE *out) { fprintf(out, "VM crash: %s\n", vm.crash); } else { fprintf(out, "VM error: "); - string_put(out, gst_to_string(&vm, vm.ret)); - printf("\n"); + fprintf(out, "%s\n", (char *)gst_to_string(&vm, vm.ret)); } } reader = buffer; buffer[0] = 0; continue; } else if (out) { - string_put(out, gst_to_string(&vm, vm.ret)); - fprintf(out, "\n"); + fprintf(out, "%s\n", (char *)gst_to_string(&vm, vm.ret)); + gst_object_put(&vm, vm.rootenv.data.object, gst_load_cstring(&vm, "ans"), vm.ret); } } diff --git a/parse.c b/parse.c index f21e4a8b..9e105dcc 100644 --- a/parse.c +++ b/parse.c @@ -18,6 +18,7 @@ typedef enum ParseType { /* Contain a parse state that goes on the parse stack */ struct GstParseState { ParseType type; + uint32_t quoteCount; union { struct { uint8_t endDelimiter; @@ -63,6 +64,19 @@ static GstParseState *parser_pop(GstParser * p) { return p->data + --p->count; } +/* Quote a value */ +static GstValue quote(GstParser *p, GstValue x) { + /* Load a quote form to get the string literal */ + GstValue tuplev; + GstValue *tuple; + tuple = gst_tuple(p->vm, 2); + tuplev.type = GST_TUPLE; + tuplev.data.tuple = tuple; + tuple[0] = gst_load_cstring(p->vm, "quote"); + tuple[1] = x; + return tuplev; +} + /* Add a new, empty ParseState to the ParseStack. */ static void parser_push(GstParser *p, ParseType type, uint8_t character) { GstParseState *top; @@ -72,6 +86,11 @@ static void parser_push(GstParser *p, ParseType type, uint8_t character) { p->data = data; p->cap = newCap; } + if (p->count) { + top = parser_peek(p); + top->quoteCount = p->quoteCount; + p->quoteCount = 0; + } ++p->count; top = parser_peek(p); if (!top) return; @@ -96,6 +115,8 @@ static void parser_push(GstParser *p, ParseType type, uint8_t character) { static void parser_append(GstParser *p, GstValue x) { GstParseState *top = parser_peek(p); if (!top) return; + while (top->quoteCount--) + x = quote(p, x); switch (top->type) { case PTYPE_ROOT: p->value = x; @@ -267,18 +288,12 @@ static int string_state(GstParser *p, uint8_t c) { if (c == '\\') { top->buf.string.state = STRING_STATE_ESCAPE; } else if (c == '"') { - /* Load a quote form to get the string literal */ - GstValue x, tuplev; - GstValue *tuple; + /* Return quoted form */ + GstValue x; x.type = GST_STRING; x.data.string = gst_buffer_to_string(p->vm, top->buf.string.buffer); - tuple = gst_tuple(p->vm, 2); - tuplev.type = GST_TUPLE; - tuplev.data.tuple = tuple; - tuple[0] = gst_load_cstring(p->vm, "quote"); - tuple[1] = x; parser_pop(p); - parser_append(p, tuplev); + parser_append(p, quote(p, x)); } else { gst_buffer_push(p->vm, top->buf.string.buffer, c); } @@ -343,6 +358,10 @@ static int root_state(GstParser *p, uint8_t c) { parser_push(p, PTYPE_STRING, c); return 1; } + if (c == '\'') { + p->quoteCount++; + return 1; + } if (is_whitespace(c)) return 1; if (is_symbol_char(c)) { parser_push(p, PTYPE_TOKEN, c); @@ -453,10 +472,11 @@ int gst_parse_string(GstParser *p, uint8_t *string) { void gst_parser(GstParser *p, Gst *vm) { p->vm = vm; GstParseState *data = gst_alloc(vm, sizeof(GstParseState) * 10); + p->cap = 10; p->data = data; p->count = 0; - p->cap = 10; p->index = 0; + p->quoteCount = 0; p->error = NULL; p->status = GST_PARSER_PENDING; p->value.type = GST_NIL; diff --git a/parse.h b/parse.h index 272b0750..b9e2f07d 100644 --- a/parse.h +++ b/parse.h @@ -16,6 +16,7 @@ struct GstParser { uint32_t cap; uint32_t index; uint32_t flags; + uint32_t quoteCount; enum { GST_PARSER_PENDING = 0, GST_PARSER_FULL, diff --git a/stl.c b/stl.c index 00387537..33276a5b 100644 --- a/stl.c +++ b/stl.c @@ -109,13 +109,11 @@ int gst_stl_compile(Gst *vm) { GstValue ret; GstCompiler c; /* init state */ - gst_compiler(&c, vm); - /* Check for environment variables */ - if (env.type == GST_OBJECT) { - /* Iterate through environment, adding globals */ - } else if (env.type != GST_NIL) { - gst_c_throwc(vm, "invalid type for environment"); + if (env.type == GST_NIL) { + env = vm->rootenv; } + gst_compiler(&c, vm); + gst_compiler_env(&c, env); /* Prepare return value */ ret.type = GST_FUNCTION; ret.data.function = gst_compiler_compile(&c, ast); diff --git a/value.c b/value.c index d0956257..3d5f4073 100644 --- a/value.c +++ b/value.c @@ -9,12 +9,13 @@ int gst_truthy(GstValue v) { return v.type != GST_NIL && !(v.type == GST_BOOLEAN && !v.data.boolean); } -static uint8_t * load_cstring(Gst *vm, const char *string, uint32_t len) { - uint8_t *data = gst_alloc(vm, len + 2 * sizeof(uint32_t)); +static uint8_t *load_cstring(Gst *vm, const char *string, uint32_t len) { + uint8_t *data = gst_alloc(vm, len + 1 + 2 * sizeof(uint32_t)); data += 2 * sizeof(uint32_t); gst_string_hash(data) = 0; gst_string_length(data) = len; gst_memcpy(data, string, len); + data[len] = 0; return data; } @@ -27,7 +28,7 @@ GstValue gst_load_cstring(Gst *vm, const char *string) { static uint8_t * number_to_string(Gst *vm, GstNumber x) { static const uint32_t SIZE = 20; - uint8_t *data = gst_alloc(vm, SIZE + 2 * sizeof(uint32_t)); + uint8_t *data = gst_alloc(vm, SIZE + 1 + 2 * sizeof(uint32_t)); data += 2 * sizeof(uint32_t); /* TODO - not depend on stdio */ snprintf((char *) data, SIZE, "%.21g", x); @@ -43,7 +44,7 @@ static const char *HEX_CHARACTERS = "0123456789abcdef"; static uint8_t *string_description(Gst *vm, const char *title, uint32_t titlelen, void *pointer) { uint32_t len = 5 + titlelen + sizeof(void *) * 2; uint32_t i; - uint8_t *data = gst_alloc(vm, len + 2 * sizeof(uint32_t)); + uint8_t *data = gst_alloc(vm, len + 1 + 2 * sizeof(uint32_t)); uint8_t *c; union { uint8_t bytes[sizeof(void *)]; @@ -68,6 +69,7 @@ static uint8_t *string_description(Gst *vm, const char *title, uint32_t titlelen *c++ = '>'; gst_string_hash(data) = 0; gst_string_length(data) = c - data; + *c = 0; return data; } @@ -85,60 +87,11 @@ uint8_t *gst_to_string(Gst *vm, GstValue x) { case GST_NUMBER: return number_to_string(vm, x.data.number); case GST_ARRAY: - { - uint32_t i; - GstBuffer *b = gst_buffer(vm, 40); - gst_buffer_push(vm, b, '['); - for (i = 0; i < x.data.array->count; ++i) { - uint8_t *substr = gst_to_string(vm, x.data.array->data[i]); - gst_buffer_append(vm, b, substr, gst_string_length(substr)); - if (i < x.data.array->count - 1) - gst_buffer_push(vm, b, ' '); - } - gst_buffer_push(vm, b, ']'); - return gst_buffer_to_string(vm, b); - } + return string_description(vm, "array", 5, x.data.pointer); case GST_TUPLE: - { - uint32_t i, count; - GstBuffer *b = gst_buffer(vm, 40); - GstValue *tuple = x.data.tuple; - gst_buffer_push(vm, b, '('); - count = gst_tuple_length(tuple); - for (i = 0; i < count; ++i) { - uint8_t *substr = gst_to_string(vm, tuple[i]); - gst_buffer_append(vm, b, substr, gst_string_length(substr)); - if (i < count - 1) - gst_buffer_push(vm, b, ' '); - } - gst_buffer_push(vm, b, ')'); - return gst_buffer_to_string(vm, b); - } + return string_description(vm, "tuple", 5, x.data.pointer); case GST_OBJECT: - { - uint32_t i, count; - GstBucket *bucket; - GstBuffer *b = gst_buffer(vm, 40); - GstObject *object = x.data.object; - gst_buffer_push(vm, b, '{'); - count = 0; - for (i = 0; i < object->capacity; ++i) { - bucket = object->buckets[i]; - while (bucket != NULL) { - uint8_t *substr = gst_to_string(vm, bucket->key); - gst_buffer_append(vm, b, substr, gst_string_length(substr)); - gst_buffer_push(vm, b, ' '); - substr = gst_to_string(vm, bucket->value); - gst_buffer_append(vm, b, substr, gst_string_length(substr)); - count++; - if (count < object->count) - gst_buffer_push(vm, b, ' '); - bucket = bucket->next; - } - } - gst_buffer_push(vm, b, '}'); - return gst_buffer_to_string(vm, b); - } + return string_description(vm, "object", 6, x.data.pointer); case GST_STRING: return x.data.string; case GST_BYTEBUFFER: diff --git a/vm.c b/vm.c index a1f1c3e2..25775844 100644 --- a/vm.c +++ b/vm.c @@ -541,9 +541,13 @@ void gst_init(Gst *vm) { vm->black = 0; /* Add thread */ vm->thread = NULL; + vm->rootenv.type = GST_NIL; } /* Clear all memory associated with the VM */ void gst_deinit(Gst *vm) { gst_clear_memory(vm); + vm->thread = NULL; + vm->rootenv.type = GST_NIL; + vm->ret.type = GST_NIL; }