Add quoting and a global gc root. The gc root

provides global variables.
This commit is contained in:
Calvin Rose 2017-03-14 19:13:17 -04:00
parent 84b7e96921
commit 9f09a19feb
11 changed files with 89 additions and 91 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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. */

9
gc.c
View File

@ -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;

1
gst.h
View File

@ -9,5 +9,6 @@
#include "value.h"
#include "stl.h"
#include "thread.h"
#include "ds.h"
#endif // gst_h_INCLUDED

24
main.c
View File

@ -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);
}
}

40
parse.c
View File

@ -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;

View File

@ -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,

10
stl.c
View File

@ -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);

65
value.c
View File

@ -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:

4
vm.c
View File

@ -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;
}