mirror of
https://github.com/janet-lang/janet
synced 2024-11-17 14:14:49 +00:00
Add quoting and a global gc root. The gc root
provides global variables.
This commit is contained in:
parent
84b7e96921
commit
9f09a19feb
19
compile.c
19
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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
9
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;
|
||||
|
1
gst.h
1
gst.h
@ -9,5 +9,6 @@
|
||||
#include "value.h"
|
||||
#include "stl.h"
|
||||
#include "thread.h"
|
||||
#include "ds.h"
|
||||
|
||||
#endif // gst_h_INCLUDED
|
||||
|
24
main.c
24
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
40
parse.c
40
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;
|
||||
|
1
parse.h
1
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,
|
||||
|
10
stl.c
10
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);
|
||||
|
65
value.c
65
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:
|
||||
|
4
vm.c
4
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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user