mirror of
https://github.com/janet-lang/janet
synced 2024-12-25 07:50:27 +00:00
Work on basic stl. Add _ binding to repl for last value
This commit is contained in:
parent
ca0f8939ef
commit
169e3de5a7
4
Makefile
4
Makefile
@ -6,8 +6,8 @@ TARGET=interp
|
|||||||
PREFIX=/usr/local
|
PREFIX=/usr/local
|
||||||
|
|
||||||
# C sources
|
# C sources
|
||||||
HEADERS=vm.h ds.h compile.h parse.h value.h datatypes.h gc.h util.h gst.h
|
HEADERS=vm.h ds.h compile.h parse.h value.h datatypes.h gc.h util.h gst.h stl.h
|
||||||
SOURCES=main.c parse.c value.c vm.c ds.c compile.c gc.c
|
SOURCES=main.c parse.c value.c vm.c ds.c compile.c gc.c stl.c
|
||||||
OBJECTS=$(patsubst %.c,%.o,$(SOURCES))
|
OBJECTS=$(patsubst %.c,%.o,$(SOURCES))
|
||||||
|
|
||||||
all: $(TARGET)
|
all: $(TARGET)
|
||||||
|
@ -1320,6 +1320,8 @@ GstFunction *gst_compiler_compile(GstCompiler *c, GstValue form) {
|
|||||||
/* Clear all but root scope */
|
/* Clear all but root scope */
|
||||||
if (c->tail)
|
if (c->tail)
|
||||||
c->tail->parent = NULL;
|
c->tail->parent = NULL;
|
||||||
|
if (c->error == NULL)
|
||||||
|
c->error = "unknown error";
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
/* Create a scope */
|
/* Create a scope */
|
||||||
|
14
datatypes.h
14
datatypes.h
@ -18,7 +18,8 @@ typedef enum GstType {
|
|||||||
GST_BYTEBUFFER,
|
GST_BYTEBUFFER,
|
||||||
GST_FUNCTION,
|
GST_FUNCTION,
|
||||||
GST_CFUNCTION,
|
GST_CFUNCTION,
|
||||||
GST_OBJECT
|
GST_OBJECT,
|
||||||
|
GST_USERDATA
|
||||||
} GstType;
|
} GstType;
|
||||||
|
|
||||||
/* The state of the virtual machine */
|
/* The state of the virtual machine */
|
||||||
@ -38,6 +39,7 @@ typedef struct GstThread GstThread;
|
|||||||
typedef int (*GstCFunction)(Gst * vm);
|
typedef int (*GstCFunction)(Gst * vm);
|
||||||
|
|
||||||
/* Implementation details */
|
/* Implementation details */
|
||||||
|
typedef struct GstUserdataHeader GstUserdataHeader;
|
||||||
typedef struct GstFuncDef GstFuncDef;
|
typedef struct GstFuncDef GstFuncDef;
|
||||||
typedef struct GstFuncEnv GstFuncEnv;
|
typedef struct GstFuncEnv GstFuncEnv;
|
||||||
|
|
||||||
@ -104,13 +106,13 @@ struct GstObject {
|
|||||||
uint32_t capacity;
|
uint32_t capacity;
|
||||||
GstBucket **buckets;
|
GstBucket **buckets;
|
||||||
uint32_t flags;
|
uint32_t flags;
|
||||||
GstValue meta;
|
GstObject *meta;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Some function defintion flags */
|
/* Some function defintion flags */
|
||||||
#define GST_FUNCDEF_FLAG_VARARG 1
|
#define GST_FUNCDEF_FLAG_VARARG 1
|
||||||
|
|
||||||
/* A function defintion. Contains information need to instatiate closures. */
|
/* A function definition. Contains information need to instatiate closures. */
|
||||||
struct GstFuncDef {
|
struct GstFuncDef {
|
||||||
uint32_t locals;
|
uint32_t locals;
|
||||||
uint32_t arity; /* Not including varargs */
|
uint32_t arity; /* Not including varargs */
|
||||||
@ -142,6 +144,12 @@ struct GstBucket {
|
|||||||
GstBucket *next;
|
GstBucket *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Contains information about userdata */
|
||||||
|
struct GstUserdataHeader {
|
||||||
|
uint32_t size;
|
||||||
|
GstObject *meta;
|
||||||
|
};
|
||||||
|
|
||||||
/* A stack frame in the VM */
|
/* A stack frame in the VM */
|
||||||
struct GstStackFrame {
|
struct GstStackFrame {
|
||||||
GstValue callee;
|
GstValue callee;
|
||||||
|
14
ds.c
14
ds.c
@ -156,6 +156,20 @@ GstValue *gst_tuple(Gst *vm, uint32_t length) {
|
|||||||
return tuple;
|
return tuple;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/****/
|
||||||
|
/* Userdata functions */
|
||||||
|
/****/
|
||||||
|
|
||||||
|
/* Create new userdata */
|
||||||
|
void *gst_userdata(Gst *vm, uint32_t size, GstObject *meta) {
|
||||||
|
char *data = gst_alloc(vm, sizeof(GstUserdataHeader) + size);
|
||||||
|
GstUserdataHeader *header = (GstUserdataHeader *)data;
|
||||||
|
void *user = data + sizeof(GstUserdataHeader);
|
||||||
|
header->size = size;
|
||||||
|
header->meta = meta;
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
/****/
|
/****/
|
||||||
/* Dictionary functions */
|
/* Dictionary functions */
|
||||||
/****/
|
/****/
|
||||||
|
8
ds.h
8
ds.h
@ -67,13 +67,19 @@ GstValue ArrayPeek(GstArray *array);
|
|||||||
|
|
||||||
/****/
|
/****/
|
||||||
/* Tuple functions */
|
/* Tuple functions */
|
||||||
/* These really don't do all that much */
|
|
||||||
/****/
|
/****/
|
||||||
|
|
||||||
/* Create an empty tuple. It is expected to be mutated right after
|
/* Create an empty tuple. It is expected to be mutated right after
|
||||||
* creation. */
|
* creation. */
|
||||||
GstValue *gst_tuple(Gst *vm, uint32_t length);
|
GstValue *gst_tuple(Gst *vm, uint32_t length);
|
||||||
|
|
||||||
|
/****/
|
||||||
|
/* Userdataa functions */
|
||||||
|
/****/
|
||||||
|
|
||||||
|
/* Create new userdata */
|
||||||
|
void *gst_userdata(Gst *vm, uint32_t size, GstObject *meta);
|
||||||
|
|
||||||
/****/
|
/****/
|
||||||
/* Object functions */
|
/* Object functions */
|
||||||
/****/
|
/****/
|
||||||
|
10
gc.c
10
gc.c
@ -153,6 +153,16 @@ void gst_mark(Gst *vm, GstValue *x) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case GST_USERDATA:
|
||||||
|
if (gc_header(x->data.string - sizeof(GstUserdataHeader))->color != vm->black) {
|
||||||
|
GstUserdataHeader *userHeader = (GstUserdataHeader *)x->data.string - 1;
|
||||||
|
gc_header(userHeader)->color = vm->black;
|
||||||
|
GstValue temp;
|
||||||
|
temp.type = GST_OBJECT;
|
||||||
|
temp.data.object = userHeader->meta;
|
||||||
|
gst_mark(vm, &temp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
1
gst.h
1
gst.h
@ -7,5 +7,6 @@
|
|||||||
#include "parse.h"
|
#include "parse.h"
|
||||||
#include "compile.h"
|
#include "compile.h"
|
||||||
#include "value.h"
|
#include "value.h"
|
||||||
|
#include "stl.h"
|
||||||
|
|
||||||
#endif // gst_h_INCLUDED
|
#endif // gst_h_INCLUDED
|
||||||
|
17
main.c
17
main.c
@ -3,24 +3,13 @@
|
|||||||
#include "gst.h"
|
#include "gst.h"
|
||||||
|
|
||||||
/* Simple printer for gst strings */
|
/* Simple printer for gst strings */
|
||||||
void string_put(FILE *out, uint8_t * string) {
|
static void string_put(FILE *out, uint8_t * string) {
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
uint32_t len = gst_string_length(string);
|
uint32_t len = gst_string_length(string);
|
||||||
for (i = 0; i < len; ++i)
|
for (i = 0; i < len; ++i)
|
||||||
fputc(string[i], out);
|
fputc(string[i], out);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Test c function */
|
|
||||||
int print(Gst *vm) {
|
|
||||||
uint32_t j, count;
|
|
||||||
count = gst_count_args(vm);
|
|
||||||
for (j = 0; j < count; ++j) {
|
|
||||||
string_put(stdout, gst_to_string(vm, gst_arg(vm, j)));
|
|
||||||
fputc('\n', stdout);
|
|
||||||
}
|
|
||||||
return GST_RETURN_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* A simple repl for debugging */
|
/* A simple repl for debugging */
|
||||||
void debug_repl(FILE *in, FILE *out) {
|
void debug_repl(FILE *in, FILE *out) {
|
||||||
char buffer[1024] = {0};
|
char buffer[1024] = {0};
|
||||||
@ -71,7 +60,9 @@ void debug_repl(FILE *in, FILE *out) {
|
|||||||
|
|
||||||
/* Try to compile generated AST */
|
/* Try to compile generated AST */
|
||||||
gst_compiler(&c, &vm);
|
gst_compiler(&c, &vm);
|
||||||
gst_compiler_add_global_cfunction(&c, "print", print);
|
gst_stl_load(&c);
|
||||||
|
/* Save last expression */
|
||||||
|
gst_compiler_add_global(&c, "_", vm.ret);
|
||||||
func.type = GST_FUNCTION;
|
func.type = GST_FUNCTION;
|
||||||
func.data.function = gst_compiler_compile(&c, p.value);
|
func.data.function = gst_compiler_compile(&c, p.value);
|
||||||
|
|
||||||
|
14
parse.c
14
parse.c
@ -268,15 +268,17 @@ static int string_state(GstParser *p, uint8_t c) {
|
|||||||
top->buf.string.state = STRING_STATE_ESCAPE;
|
top->buf.string.state = STRING_STATE_ESCAPE;
|
||||||
} else if (c == '"') {
|
} else if (c == '"') {
|
||||||
/* Load a quote form to get the string literal */
|
/* Load a quote form to get the string literal */
|
||||||
GstValue x, array;
|
GstValue x, tuplev;
|
||||||
|
GstValue *tuple;
|
||||||
x.type = GST_STRING;
|
x.type = GST_STRING;
|
||||||
x.data.string = gst_buffer_to_string(p->vm, top->buf.string.buffer);
|
x.data.string = gst_buffer_to_string(p->vm, top->buf.string.buffer);
|
||||||
array.type = GST_ARRAY;
|
tuple = gst_tuple(p->vm, 2);
|
||||||
array.data.array = gst_array(p->vm, 2);
|
tuplev.type = GST_TUPLE;
|
||||||
gst_array_push(p->vm, array.data.array, gst_load_cstring(p->vm, "quote"));
|
tuplev.data.tuple = tuple;
|
||||||
gst_array_push(p->vm, array.data.array, x);
|
tuple[0] = gst_load_cstring(p->vm, "quote");
|
||||||
|
tuple[1] = x;
|
||||||
parser_pop(p);
|
parser_pop(p);
|
||||||
parser_append(p, array);
|
parser_append(p, tuplev);
|
||||||
} else {
|
} else {
|
||||||
gst_buffer_push(p->vm, top->buf.string.buffer, c);
|
gst_buffer_push(p->vm, top->buf.string.buffer, c);
|
||||||
}
|
}
|
||||||
|
61
stl.c
61
stl.c
@ -1,22 +1,50 @@
|
|||||||
/* This implemets a standard library in gst. Some of this
|
/* This implemets a standard library in gst. Some of this
|
||||||
* will eventually be ported over to gst if possible */
|
* will eventually be ported over to gst if possible */
|
||||||
|
#include "stl.h"
|
||||||
#include "gst.h"
|
#include "gst.h"
|
||||||
|
|
||||||
/****/
|
/****/
|
||||||
/* Misc */
|
/* Core */
|
||||||
/****/
|
/****/
|
||||||
|
|
||||||
/* Print values for inspection */
|
/* Print values for inspection */
|
||||||
int print(Gst *vm) {
|
int gst_stl_print(Gst *vm) {
|
||||||
uint32_t j, count;
|
uint32_t j, count;
|
||||||
count = gst_count_args(vm);
|
count = gst_count_args(vm);
|
||||||
for (j = 0; j < count; ++j) {
|
for (j = 0; j < count; ++j) {
|
||||||
string_put(stdout, gst_to_string(vm, gst_arg(vm, j)));
|
uint32_t i;
|
||||||
|
uint8_t *string = gst_to_string(vm, gst_arg(vm, j));
|
||||||
|
uint32_t len = gst_string_length(string);
|
||||||
|
for (i = 0; i < len; ++i)
|
||||||
|
fputc(string[i], stdout);
|
||||||
fputc('\n', stdout);
|
fputc('\n', stdout);
|
||||||
}
|
}
|
||||||
return GST_RETURN_OK;
|
return GST_RETURN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Get class value */
|
||||||
|
int gst_stl_getclass(Gst *vm) {
|
||||||
|
GstValue class = gst_get_class(gst_arg(vm, 0));
|
||||||
|
gst_c_return(vm, class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set class value */
|
||||||
|
int gst_stl_setclass(Gst *vm) {
|
||||||
|
GstValue x = gst_arg(vm, 0);
|
||||||
|
GstValue class = gst_arg(vm, 1);
|
||||||
|
const char *err = gst_set_class(x, class);
|
||||||
|
if (err != NULL)
|
||||||
|
gst_c_throwc(vm, err);
|
||||||
|
gst_c_return(vm, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Load core */
|
||||||
|
void gst_stl_load_core(GstCompiler *c) {
|
||||||
|
gst_compiler_add_global_cfunction(c, "print", gst_stl_print);
|
||||||
|
gst_compiler_add_global_cfunction(c, "get-class", gst_stl_getclass);
|
||||||
|
gst_compiler_add_global_cfunction(c, "set-class", gst_stl_setclass);
|
||||||
|
}
|
||||||
|
|
||||||
/****/
|
/****/
|
||||||
/* Parsing */
|
/* Parsing */
|
||||||
/****/
|
/****/
|
||||||
@ -39,6 +67,11 @@ int gst_stl_parse(Gst *vm) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Load parsing */
|
||||||
|
void gst_stl_load_parse(GstCompiler *c) {
|
||||||
|
gst_compiler_add_global_cfunction(c, "parse", gst_stl_parse);
|
||||||
|
}
|
||||||
|
|
||||||
/****/
|
/****/
|
||||||
/* Compiling */
|
/* Compiling */
|
||||||
/****/
|
/****/
|
||||||
@ -54,22 +87,38 @@ int gst_stl_compile(Gst *vm) {
|
|||||||
/* Check for environment variables */
|
/* Check for environment variables */
|
||||||
if (env.type == GST_OBJECT) {
|
if (env.type == GST_OBJECT) {
|
||||||
/* Iterate through environment, adding globals */
|
/* Iterate through environment, adding globals */
|
||||||
} else if (env.type != GST_NIL) {
|
} else if (env.type != GST_NIL) {
|
||||||
gst_c_throwc(vm, "invalid type for environment");
|
gst_c_throwc(vm, "invalid type for environment");
|
||||||
}
|
}
|
||||||
/* Prepare return value */
|
/* Prepare return value */
|
||||||
ret.type = GST_FUNCTION;
|
ret.type = GST_FUNCTION;
|
||||||
ret.data.function = gst_compiler_compile(&c, ast);
|
ret.data.function = gst_compiler_compile(&c, ast);
|
||||||
/* Check for errors */
|
/* Check for errors */
|
||||||
if (c.error != NULL) {
|
if (c.error == NULL) {
|
||||||
gst_c_return(vm, ret);
|
gst_c_return(vm, ret);
|
||||||
} else {
|
} else {
|
||||||
gst_c_throwc(vm, c.error);
|
gst_c_throwc(vm, c.error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Load compilation */
|
||||||
|
void gst_stl_load_compile(GstCompiler *c) {
|
||||||
|
gst_compiler_add_global_cfunction(c, "compile", gst_stl_compile);
|
||||||
|
}
|
||||||
|
|
||||||
/****/
|
/****/
|
||||||
/* IO */
|
/* IO */
|
||||||
/****/
|
/****/
|
||||||
|
|
||||||
/* TODO - add userdata to allow for manipulation of FILE pointers. */
|
/* TODO - add userdata to allow for manipulation of FILE pointers. */
|
||||||
|
|
||||||
|
/****/
|
||||||
|
/* Bootstraping */
|
||||||
|
/****/
|
||||||
|
|
||||||
|
/* Load all libraries */
|
||||||
|
void gst_stl_load(GstCompiler *c) {
|
||||||
|
gst_stl_load_core(c);
|
||||||
|
gst_stl_load_parse(c);
|
||||||
|
gst_stl_load_compile(c);
|
||||||
|
}
|
||||||
|
11
stl.h
Normal file
11
stl.h
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#ifndef stl_h_INCLUDED
|
||||||
|
#define stl_h_INCLUDED
|
||||||
|
|
||||||
|
#include "datatypes.h"
|
||||||
|
#include "compile.h"
|
||||||
|
|
||||||
|
/* Load the standard library */
|
||||||
|
void gst_stl_load(GstCompiler *c);
|
||||||
|
|
||||||
|
#endif // stl_h_INCLUDED
|
||||||
|
|
10
util.h
10
util.h
@ -3,13 +3,13 @@
|
|||||||
|
|
||||||
/* String utils */
|
/* String utils */
|
||||||
#define gst_string_raw(s) ((uint32_t *)(s) - 2)
|
#define gst_string_raw(s) ((uint32_t *)(s) - 2)
|
||||||
#define gst_string_length(v) (gst_string_raw(v)[0])
|
#define gst_string_length(s) (gst_string_raw(s)[0])
|
||||||
#define gst_string_hash(v) (gst_string_raw(v)[1])
|
#define gst_string_hash(s) (gst_string_raw(s)[1])
|
||||||
|
|
||||||
/* Tuple utils */
|
/* Tuple utils */
|
||||||
#define gst_tuple_raw(s) ((uint32_t *)(s) - 2)
|
#define gst_tuple_raw(t) ((uint32_t *)(t) - 2)
|
||||||
#define gst_tuple_length(v) (gst_tuple_raw(v)[0])
|
#define gst_tuple_length(t) (gst_tuple_raw(t)[0])
|
||||||
#define gst_tuple_hash(v) (gst_tuple_raw(v)[1])
|
#define gst_tuple_hash(t) (gst_tuple_raw(t)[1])
|
||||||
|
|
||||||
/* Memcpy for moving memory */
|
/* Memcpy for moving memory */
|
||||||
#ifndef gst_memcpy
|
#ifndef gst_memcpy
|
||||||
|
45
value.c
45
value.c
@ -30,7 +30,7 @@ static uint8_t * number_to_string(Gst *vm, GstNumber x) {
|
|||||||
uint8_t *data = gst_alloc(vm, SIZE + 2 * sizeof(uint32_t));
|
uint8_t *data = gst_alloc(vm, SIZE + 2 * sizeof(uint32_t));
|
||||||
data += 2 * sizeof(uint32_t);
|
data += 2 * sizeof(uint32_t);
|
||||||
/* TODO - not depend on stdio */
|
/* TODO - not depend on stdio */
|
||||||
snprintf((char *) data, SIZE, "%.17g", x);
|
snprintf((char *) data, SIZE, "%.21g", x);
|
||||||
gst_string_hash(data) = 0;
|
gst_string_hash(data) = 0;
|
||||||
gst_string_length(data) = strlen((char *) data);
|
gst_string_length(data) = strlen((char *) data);
|
||||||
return data;
|
return data;
|
||||||
@ -149,6 +149,8 @@ uint8_t *gst_to_string(Gst *vm, GstValue x) {
|
|||||||
return string_description(vm, "function", 8, x.data.pointer);
|
return string_description(vm, "function", 8, x.data.pointer);
|
||||||
case GST_THREAD:
|
case GST_THREAD:
|
||||||
return string_description(vm, "thread", 6, x.data.pointer);
|
return string_description(vm, "thread", 6, x.data.pointer);
|
||||||
|
case GST_USERDATA:
|
||||||
|
return string_description(vm, "userdata", 8, x.data.pointer);
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -463,3 +465,44 @@ const char *gst_set(Gst *vm, GstValue ds, GstValue key, GstValue value) {
|
|||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Get the class object of a value */
|
||||||
|
GstValue gst_get_class(GstValue x) {
|
||||||
|
GstValue ret;
|
||||||
|
ret.type = GST_NIL;
|
||||||
|
switch (x.type) {
|
||||||
|
case GST_OBJECT:
|
||||||
|
if (x.data.object->meta != NULL) {
|
||||||
|
ret.type = GST_OBJECT;
|
||||||
|
ret.data.object = x.data.object->meta;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case GST_USERDATA:
|
||||||
|
{
|
||||||
|
GstUserdataHeader *header = (GstUserdataHeader *)x.data.pointer - 1;
|
||||||
|
if (header->meta != NULL) {
|
||||||
|
ret.type = GST_OBJECT;
|
||||||
|
ret.data.object = header->meta;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the class object of a value. Returns possible c error string */
|
||||||
|
const char *gst_set_class(GstValue x, GstValue class) {
|
||||||
|
switch (x.type) {
|
||||||
|
case GST_OBJECT:
|
||||||
|
if (class.type != GST_OBJECT) return "class must be of type object";
|
||||||
|
/* TODO - check for class immutability */
|
||||||
|
x.data.object->meta = class.data.object;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return "cannot set class object";
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
6
value.h
6
value.h
@ -29,4 +29,10 @@ uint8_t *gst_to_string(Gst *vm, GstValue x);
|
|||||||
/* Generate a hash value for a gst object */
|
/* Generate a hash value for a gst object */
|
||||||
uint32_t gst_hash(GstValue x);
|
uint32_t gst_hash(GstValue x);
|
||||||
|
|
||||||
|
/* Get the class object of a value */
|
||||||
|
GstValue gst_get_class(GstValue x);
|
||||||
|
|
||||||
|
/* Set the class object of a value. Returns possible c error string */
|
||||||
|
const char *gst_set_class(GstValue obj, GstValue class);
|
||||||
|
|
||||||
#endif /* end of include guard: VALUE_H_1RJPQKFM */
|
#endif /* end of include guard: VALUE_H_1RJPQKFM */
|
||||||
|
Loading…
Reference in New Issue
Block a user