mirror of
https://github.com/janet-lang/janet
synced 2024-11-28 02:59:54 +00:00
Flesh out support for userdata
Add file reading via file objects. Finalizer option for userdata.
This commit is contained in:
parent
d295e281e1
commit
bf2c16ccb0
2
Makefile
2
Makefile
@ -16,7 +16,7 @@ all: $(GST_TARGET)
|
|||||||
##### The core vm and runtime #####
|
##### The core vm and runtime #####
|
||||||
###################################
|
###################################
|
||||||
GST_CORE_SOURCES=$(addprefix core/,\
|
GST_CORE_SOURCES=$(addprefix core/,\
|
||||||
compile.c disasm.c parse.c stl.c strings.c ids.c util.c\
|
compile.c disasm.c parse.c stl.c ids.c util.c\
|
||||||
value.c vm.c ds.c gc.c thread.c serialize.c)
|
value.c vm.c ds.c gc.c thread.c serialize.c)
|
||||||
GST_CORE_OBJECTS=$(patsubst %.c,%.o,$(GST_CORE_SOURCES))
|
GST_CORE_OBJECTS=$(patsubst %.c,%.o,$(GST_CORE_SOURCES))
|
||||||
$(GST_CORELIB): $(GST_CORE_OBJECTS) $(GST_HEADERS)
|
$(GST_CORELIB): $(GST_CORE_OBJECTS) $(GST_HEADERS)
|
||||||
|
@ -28,5 +28,6 @@
|
|||||||
void gst_cache_remove_string(Gst *vm, char *strmem);
|
void gst_cache_remove_string(Gst *vm, char *strmem);
|
||||||
void gst_cache_remove_tuple(Gst *vm, char *tuplemem);
|
void gst_cache_remove_tuple(Gst *vm, char *tuplemem);
|
||||||
void gst_cache_remove_struct(Gst *vm, char *structmem);
|
void gst_cache_remove_struct(Gst *vm, char *structmem);
|
||||||
|
void gst_cache_remove_userdata(Gst *vm, char *usermem);
|
||||||
|
|
||||||
#endif /* end of include guard: CACHE_H_LVYZMBLR */
|
#endif /* end of include guard: CACHE_H_LVYZMBLR */
|
||||||
|
@ -159,12 +159,13 @@ GstValue gst_array_peek(GstArray *array) {
|
|||||||
/****/
|
/****/
|
||||||
|
|
||||||
/* Create new userdata */
|
/* Create new userdata */
|
||||||
void *gst_userdata(Gst *vm, uint32_t size, const GstValue *meta) {
|
void *gst_userdata(Gst *vm, uint32_t size, const GstUserType *utype) {
|
||||||
char *data = gst_alloc(vm, sizeof(GstUserdataHeader) + size);
|
char *data = gst_alloc(vm, sizeof(GstUserdataHeader) + size);
|
||||||
GstUserdataHeader *header = (GstUserdataHeader *)data;
|
GstUserdataHeader *header = (GstUserdataHeader *)data;
|
||||||
void *user = data + sizeof(GstUserdataHeader);
|
void *user = data + sizeof(GstUserdataHeader);
|
||||||
header->size = size;
|
header->size = size;
|
||||||
header->meta = meta;
|
header->type = utype;
|
||||||
|
gst_mem_tag(header, GST_MEMTAG_USER);
|
||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
10
core/gc.c
10
core/gc.c
@ -174,10 +174,8 @@ void gst_mark(Gst *vm, GstValueUnion x, GstType type) {
|
|||||||
if (gc_header(x.string - sizeof(GstUserdataHeader))->color != vm->black) {
|
if (gc_header(x.string - sizeof(GstUserdataHeader))->color != vm->black) {
|
||||||
GstUserdataHeader *userHeader = (GstUserdataHeader *)x.string - 1;
|
GstUserdataHeader *userHeader = (GstUserdataHeader *)x.string - 1;
|
||||||
gc_header(userHeader)->color = vm->black;
|
gc_header(userHeader)->color = vm->black;
|
||||||
GstValueUnion temp;
|
|
||||||
temp.st = userHeader->meta;
|
|
||||||
gst_mark(vm, temp, GST_STRUCT);
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case GST_FUNCENV:
|
case GST_FUNCENV:
|
||||||
gst_mark_funcenv(vm, x.env);
|
gst_mark_funcenv(vm, x.env);
|
||||||
@ -210,6 +208,12 @@ void gst_sweep(Gst *vm) {
|
|||||||
gst_cache_remove_struct(vm, (char *)(current + 1));
|
gst_cache_remove_struct(vm, (char *)(current + 1));
|
||||||
if (current->tags & GST_MEMTAG_TUPLE)
|
if (current->tags & GST_MEMTAG_TUPLE)
|
||||||
gst_cache_remove_tuple(vm, (char *)(current + 1));
|
gst_cache_remove_tuple(vm, (char *)(current + 1));
|
||||||
|
if (current->tags & GST_MEMTAG_USER) {
|
||||||
|
GstUserdataHeader *h = (GstUserdataHeader *)(current + 1);
|
||||||
|
if (h->type->finalize) {
|
||||||
|
h->type->finalize(vm, h + 1, h->size);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
gst_raw_free(current);
|
gst_raw_free(current);
|
||||||
} else {
|
} else {
|
||||||
|
22
core/ids.c
22
core/ids.c
@ -395,3 +395,25 @@ GstValue gst_string_cv(Gst *vm, const char *str) {
|
|||||||
ret.data.string = data;
|
ret.data.string = data;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Compares two strings */
|
||||||
|
int gst_string_compare(const uint8_t *lhs, const uint8_t *rhs) {
|
||||||
|
uint32_t xlen = gst_string_length(lhs);
|
||||||
|
uint32_t ylen = gst_string_length(rhs);
|
||||||
|
uint32_t len = xlen > ylen ? ylen : xlen;
|
||||||
|
uint32_t i;
|
||||||
|
for (i = 0; i < len; ++i) {
|
||||||
|
if (lhs[i] == rhs[i]) {
|
||||||
|
continue;
|
||||||
|
} else if (lhs[i] < rhs[i]) {
|
||||||
|
return -1; /* x is less than y */
|
||||||
|
} else {
|
||||||
|
return 1; /* y is less than x */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (xlen == ylen) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return xlen < ylen ? -1 : 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
193
core/serialize.c
193
core/serialize.c
@ -38,12 +38,12 @@
|
|||||||
* Byte 207: Buffer - [u32 length]*[u8... characters]
|
* Byte 207: Buffer - [u32 length]*[u8... characters]
|
||||||
* Byte 208: Array - [u32 length]*[value... elements]
|
* Byte 208: Array - [u32 length]*[value... elements]
|
||||||
* Byte 209: Tuple - [u32 length]*[value... elements]
|
* Byte 209: Tuple - [u32 length]*[value... elements]
|
||||||
* Byte 210: Thread - [u8 state][u32 frames]*[[value callee][value env]
|
* Byte 210: Thread - [value parent][u8 state][u32 frames]*[[value callee][value env]
|
||||||
* [u32 pcoffset][u16 ret][u16 args][u16 size]*[value ...stack]
|
* [u32 pcoffset][u32 ret][u32 args][u32 size]*[value ...stack]]
|
||||||
* Byte 211: Table - [u32 length]*2*[value... kvs]
|
* Byte 211: Table - [u32 length]*2*[value... kvs]
|
||||||
* Byte 212: FuncDef - [u32 locals][u32 arity][u32 flags][u32 literallen]*[value...
|
* Byte 212: FuncDef - [u32 locals][u32 arity][u32 flags][u32 literallen]*[value...
|
||||||
* literals][u32 bytecodelen]*[u16... bytecode]
|
* literals][u32 bytecodelen]*[u16... bytecode]
|
||||||
* Byte 213: FunEnv - [value thread][u32 length]*[value ...upvalues]
|
* Byte 213: FuncEnv - [value thread][u32 length]*[value ...upvalues]
|
||||||
* (upvalues is not read if thread is a thread object)
|
* (upvalues is not read if thread is a thread object)
|
||||||
* Byte 214: Func - [value parent][value def][value env]
|
* Byte 214: Func - [value parent][value def][value env]
|
||||||
* (nil values indicate empty)
|
* (nil values indicate empty)
|
||||||
@ -232,14 +232,15 @@ static const char *gst_deserialize_impl(
|
|||||||
|
|
||||||
case 210: /* Thread */
|
case 210: /* Thread */
|
||||||
{
|
{
|
||||||
GstValue nil;
|
|
||||||
GstThread *t;
|
GstThread *t;
|
||||||
GstValue *stack;
|
GstValue *stack;
|
||||||
uint16_t prevsize = 0;
|
uint16_t prevsize = 0;
|
||||||
uint8_t statusbyte;
|
uint8_t statusbyte;
|
||||||
nil.type = GST_NIL;
|
t = gst_thread(vm, gst_wrap_nil(), 64);
|
||||||
t = gst_thread(vm, nil, 64);
|
err = gst_deserialize_impl(vm, data, end, &data, visited, &ret);
|
||||||
ret.type = GST_THREAD;
|
if (err != NULL) return err;
|
||||||
|
if (ret.type != GST_THREAD) return "expected thread parent to thread";
|
||||||
|
t->parent = ret.data.thread;
|
||||||
ret.data.thread = t;
|
ret.data.thread = t;
|
||||||
deser_assert(data < end, UEB);
|
deser_assert(data < end, UEB);
|
||||||
statusbyte = *data++;
|
statusbyte = *data++;
|
||||||
@ -258,16 +259,16 @@ static const char *gst_deserialize_impl(
|
|||||||
uint16_t ret, args, size, j;
|
uint16_t ret, args, size, j;
|
||||||
/* Create a new frame */
|
/* Create a new frame */
|
||||||
if (i > 0)
|
if (i > 0)
|
||||||
gst_thread_beginframe(vm, t, nil, 0);
|
gst_thread_beginframe(vm, t, gst_wrap_nil(), 0);
|
||||||
/* Read the stack */
|
/* Read the stack */
|
||||||
err = gst_deserialize_impl(vm, data, end, &data, visited, &callee);
|
err = gst_deserialize_impl(vm, data, end, &data, visited, &callee);
|
||||||
if (err != NULL) return err;
|
if (err != NULL) return err;
|
||||||
err = gst_deserialize_impl(vm, data, end, &data, visited, &env);
|
err = gst_deserialize_impl(vm, data, end, &data, visited, &env);
|
||||||
if (err != NULL) return err;
|
if (err != NULL) return err;
|
||||||
read_u32(pcoffset);
|
read_u32(pcoffset);
|
||||||
read_u16(ret);
|
read_u32(ret);
|
||||||
read_u16(args);
|
read_u32(args);
|
||||||
read_u16(size);
|
read_u32(size);
|
||||||
/* Set up the stack */
|
/* Set up the stack */
|
||||||
stack = gst_thread_stack(t);
|
stack = gst_thread_stack(t);
|
||||||
if (callee.type == GST_FUNCTION) {
|
if (callee.type == GST_FUNCTION) {
|
||||||
@ -295,7 +296,7 @@ static const char *gst_deserialize_impl(
|
|||||||
ret.type = GST_TABLE;
|
ret.type = GST_TABLE;
|
||||||
read_u32(length);
|
read_u32(length);
|
||||||
ret.data.table = gst_table(vm, 2 * length);
|
ret.data.table = gst_table(vm, 2 * length);
|
||||||
for (i = 0; i < length; i += 2) {
|
for (i = 0; i < length; ++i) {
|
||||||
GstValue key, value;
|
GstValue key, value;
|
||||||
err = gst_deserialize_impl(vm, data, end, &data, visited, &key);
|
err = gst_deserialize_impl(vm, data, end, &data, visited, &key);
|
||||||
if (err != NULL) return err;
|
if (err != NULL) return err;
|
||||||
@ -393,16 +394,8 @@ static const char *gst_deserialize_impl(
|
|||||||
|
|
||||||
case 215: /* LUdata */
|
case 215: /* LUdata */
|
||||||
{
|
{
|
||||||
GstValue meta;
|
/* TODO enable deserialization of userdata through registration
|
||||||
ret.type = GST_USERDATA;
|
* to names in vm. */
|
||||||
err = gst_deserialize_impl(vm, data, end, &data, visited, &meta);
|
|
||||||
if (err != NULL) return err;
|
|
||||||
deser_assert(meta.type == GST_STRUCT, "userdata requires valid meta struct");
|
|
||||||
read_u32(length);
|
|
||||||
deser_datacheck(length);
|
|
||||||
ret.data.pointer = gst_userdata(vm, length, meta.data.st);
|
|
||||||
gst_memcpy(ret.data.pointer, data, length);
|
|
||||||
gst_array_push(vm, visited, ret);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -508,56 +501,124 @@ const char *gst_serialize_impl(
|
|||||||
/* Check reference types */
|
/* Check reference types */
|
||||||
switch (x.type) {
|
switch (x.type) {
|
||||||
default:
|
default:
|
||||||
return "unable to serialize type";
|
return "unable to serialize type";
|
||||||
case GST_STRING:
|
case GST_STRING:
|
||||||
write_byte(205);
|
write_byte(205);
|
||||||
count = gst_string_length(x.data.string);
|
count = gst_string_length(x.data.string);
|
||||||
write_u32(count);
|
write_u32(count);
|
||||||
for (i = 0; i < count; ++i) {
|
for (i = 0; i < count; ++i) {
|
||||||
write_byte(x.data.string[i]);
|
write_byte(x.data.string[i]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case GST_STRUCT:
|
case GST_STRUCT:
|
||||||
write_byte(206);
|
write_byte(206);
|
||||||
count = gst_struct_length(x.data.st);
|
count = gst_struct_length(x.data.st);
|
||||||
write_u32(count);
|
write_u32(count);
|
||||||
for (i = 0; i < gst_struct_capacity(x.data.st); i += 2) {
|
for (i = 0; i < gst_struct_capacity(x.data.st); i += 2) {
|
||||||
if (x.data.st[i].type != GST_NIL) {
|
if (x.data.st[i].type != GST_NIL) {
|
||||||
err = gst_serialize_impl(vm, buffer, visited, nextId, x.data.st[i]);
|
err = gst_serialize_impl(vm, buffer, visited, nextId, x.data.st[i]);
|
||||||
if (err != NULL) return err;
|
if (err != NULL) return err;
|
||||||
err = gst_serialize_impl(vm, buffer, visited, nextId, x.data.st[i + 1]);
|
err = gst_serialize_impl(vm, buffer, visited, nextId, x.data.st[i + 1]);
|
||||||
if (err != NULL) return err;
|
if (err != NULL) return err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case GST_BYTEBUFFER:
|
case GST_BYTEBUFFER:
|
||||||
write_byte(207);
|
write_byte(207);
|
||||||
count = x.data.buffer->count;
|
count = x.data.buffer->count;
|
||||||
write_u32(count);
|
write_u32(count);
|
||||||
for (i = 0; i < count; ++i) {
|
for (i = 0; i < count; ++i) {
|
||||||
write_byte(x.data.buffer->data[i]);
|
write_byte(x.data.buffer->data[i]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case GST_ARRAY:
|
case GST_ARRAY:
|
||||||
write_byte(208);
|
write_byte(208);
|
||||||
count = x.data.array->count;
|
count = x.data.array->count;
|
||||||
write_u32(count);
|
write_u32(count);
|
||||||
for (i = 0; i < count; ++i) {
|
for (i = 0; i < count; ++i) {
|
||||||
err = gst_serialize_impl(vm, buffer, visited, nextId, x.data.array->data[i]);
|
err = gst_serialize_impl(vm, buffer, visited, nextId, x.data.array->data[i]);
|
||||||
if (err != NULL) return err;
|
if (err != NULL) return err;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case GST_TUPLE:
|
case GST_TUPLE:
|
||||||
write_byte(209);
|
write_byte(209);
|
||||||
count = gst_tuple_length(x.data.tuple);
|
count = gst_tuple_length(x.data.tuple);
|
||||||
write_u32(count);
|
write_u32(count);
|
||||||
for (i = 0; i < count; ++i) {
|
for (i = 0; i < count; ++i) {
|
||||||
err = gst_serialize_impl(vm, buffer, visited, nextId, x.data.tuple[i]);
|
err = gst_serialize_impl(vm, buffer, visited, nextId, x.data.tuple[i]);
|
||||||
if (err != NULL) return err;
|
if (err != NULL) return err;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
/*case GST_THREAD:*/
|
case GST_THREAD:
|
||||||
/*break;*/
|
{
|
||||||
|
GstThread *t = x.data.thread;
|
||||||
|
const GstValue *stack;
|
||||||
|
uint32_t framecount = gst_thread_countframes(t);
|
||||||
|
uint32_t i;
|
||||||
|
err = gst_serialize_impl(vm, buffer, visited, nextId, gst_wrap_thread(t->parent));
|
||||||
|
if (err != NULL) return err;
|
||||||
|
/* Write the status byte */
|
||||||
|
if (t->status == GST_THREAD_PENDING) write_byte(0);
|
||||||
|
else if (t->status == GST_THREAD_ALIVE) write_byte(1);
|
||||||
|
else write_byte(2);
|
||||||
|
/* Write number of stack frames */
|
||||||
|
write_u32(framecount);
|
||||||
|
/* Write stack frames */
|
||||||
|
for (i = 0; i < framecount; ++i) {
|
||||||
|
uint32_t j, size;
|
||||||
|
GstValue callee = gst_frame_callee(stack);
|
||||||
|
GstFuncEnv *env = gst_frame_env(stack);
|
||||||
|
err = gst_serialize_impl(vm, buffer, visited, nextId, callee);
|
||||||
|
if (err != NULL) return err;
|
||||||
|
err = gst_serialize_impl(vm, buffer, visited, nextId, gst_wrap_funcenv(env));
|
||||||
|
if (err != NULL) return err;
|
||||||
|
if (callee.type == GST_FUNCTION) {
|
||||||
|
write_u32(gst_frame_pc(stack) - callee.data.function->def->byteCode);
|
||||||
|
} else {
|
||||||
|
write_u32(0);
|
||||||
|
}
|
||||||
|
write_u32(gst_frame_ret(stack));
|
||||||
|
write_u32(gst_frame_args(stack));
|
||||||
|
size = gst_frame_size(stack);
|
||||||
|
write_u32(size);
|
||||||
|
for (j = 0; j < size; ++j) {
|
||||||
|
err = gst_serialize_impl(vm, buffer, visited, nextId, stack[j]);
|
||||||
|
if (err != NULL) return err;
|
||||||
|
}
|
||||||
|
/* Next stack frame */
|
||||||
|
stack = t->data + GST_FRAME_SIZE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case GST_TABLE:
|
||||||
|
write_byte(211);
|
||||||
|
count = x.data.table->count;
|
||||||
|
write_u32(count);
|
||||||
|
for (i = 0; i < x.data.table->capacity; i += 2) {
|
||||||
|
if (x.data.table->data[i].type == GST_NIL) continue;
|
||||||
|
err = gst_serialize_impl(vm, buffer, visited, nextId, x.data.tuple[i]);
|
||||||
|
if (err != NULL) return err;
|
||||||
|
err = gst_serialize_impl(vm, buffer, visited, nextId, x.data.tuple[i+1]);
|
||||||
|
if (err != NULL) return err;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case GST_FUNCDEF: /* Funcdef */
|
||||||
|
{
|
||||||
|
/* TODO */
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GST_FUNCENV: /* Funcenv */
|
||||||
|
{
|
||||||
|
/* TODO */
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GST_FUNCTION: /* Function */
|
||||||
|
{
|
||||||
|
/* TODO */
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Record reference */
|
/* Record reference */
|
||||||
|
60
core/stl.c
60
core/stl.c
@ -328,17 +328,21 @@ int gst_stl_struct(Gst *vm) {
|
|||||||
/* Create a buffer */
|
/* Create a buffer */
|
||||||
int gst_stl_buffer(Gst *vm) {
|
int gst_stl_buffer(Gst *vm) {
|
||||||
uint32_t i, count;
|
uint32_t i, count;
|
||||||
|
const uint8_t *dat;
|
||||||
|
uint32_t slen;
|
||||||
GstBuffer *buf = gst_buffer(vm, 10);
|
GstBuffer *buf = gst_buffer(vm, 10);
|
||||||
count = gst_count_args(vm);
|
count = gst_count_args(vm);
|
||||||
for (i = 0; i < count; ++i) {
|
for (i = 0; i < count; ++i) {
|
||||||
const uint8_t *string = gst_to_string(vm, gst_arg(vm, i));
|
if (gst_chararray_view(gst_arg(vm, i), &dat, &slen))
|
||||||
gst_buffer_append(vm, buf, string, gst_string_length(string));
|
gst_buffer_append(vm, buf, dat, slen);
|
||||||
|
else
|
||||||
|
gst_c_throwc(vm, GST_EXPECTED_STRING);
|
||||||
}
|
}
|
||||||
gst_c_return(vm, gst_wrap_buffer(buf));
|
gst_c_return(vm, gst_wrap_buffer(buf));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Concatenate strings */
|
/* Create a string */
|
||||||
int gst_stl_strcat(Gst *vm) {
|
int gst_stl_string(Gst *vm) {
|
||||||
uint32_t j;
|
uint32_t j;
|
||||||
uint32_t count = gst_count_args(vm);
|
uint32_t count = gst_count_args(vm);
|
||||||
uint32_t length = 0;
|
uint32_t length = 0;
|
||||||
@ -515,7 +519,13 @@ int gst_stl_setglobal(Gst *vm) {
|
|||||||
/* IO */
|
/* IO */
|
||||||
/****/
|
/****/
|
||||||
|
|
||||||
/* TODO - add userdata to allow for manipulation of FILE pointers. */
|
/* File type definition */
|
||||||
|
static GstUserType gst_stl_filetype = {
|
||||||
|
"io.file",
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
/* Open a a file and return a userdata wrapper arounf the C file API. */
|
/* Open a a file and return a userdata wrapper arounf the C file API. */
|
||||||
int gst_stl_open(Gst *vm) {
|
int gst_stl_open(Gst *vm) {
|
||||||
@ -523,20 +533,44 @@ int gst_stl_open(Gst *vm) {
|
|||||||
const uint8_t *fmode = gst_to_string(vm, gst_arg(vm, 1));
|
const uint8_t *fmode = gst_to_string(vm, gst_arg(vm, 1));
|
||||||
FILE *f;
|
FILE *f;
|
||||||
FILE **fp;
|
FILE **fp;
|
||||||
GstValue *st;
|
|
||||||
if (gst_count_args(vm) < 2 || gst_arg(vm, 0).type != GST_STRING
|
if (gst_count_args(vm) < 2 || gst_arg(vm, 0).type != GST_STRING
|
||||||
|| gst_arg(vm, 1).type != GST_STRING)
|
|| gst_arg(vm, 1).type != GST_STRING)
|
||||||
gst_c_throwc(vm, "expected filename and filemode");
|
gst_c_throwc(vm, "expected filename and filemode");
|
||||||
f = fopen((const char *)fname, (const char *)fmode);
|
f = fopen((const char *)fname, (const char *)fmode);
|
||||||
if (!f)
|
if (!f)
|
||||||
gst_c_throwc(vm, "could not open file");
|
gst_c_throwc(vm, "could not open file");
|
||||||
st = gst_struct_begin(vm, 0);
|
fp = gst_userdata(vm, sizeof(FILE *), &gst_stl_filetype);
|
||||||
fp = gst_userdata(vm, sizeof(FILE *), gst_struct_end(vm, st));
|
|
||||||
*fp = f;
|
*fp = f;
|
||||||
gst_c_return(vm, gst_wrap_userdata(fp));
|
gst_c_return(vm, gst_wrap_userdata(fp));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Write a string to a file in one go. Overwrites an existing file. */
|
/* Read an entire file into memory */
|
||||||
|
int gst_stl_slurp(Gst *vm) {
|
||||||
|
GstBuffer *b;
|
||||||
|
long fsize;
|
||||||
|
FILE *f;
|
||||||
|
FILE **fp = gst_check_userdata(vm, 0, &gst_stl_filetype);
|
||||||
|
if (fp == NULL) gst_c_throwc(vm, "expected file");
|
||||||
|
if (!gst_check_buffer(vm, 1, &b)) b = gst_buffer(vm, 10);
|
||||||
|
f = *fp;
|
||||||
|
/* Read whole file */
|
||||||
|
fseek(f, 0, SEEK_END);
|
||||||
|
fsize = ftell(f);
|
||||||
|
fseek(f, 0, SEEK_SET);
|
||||||
|
/* Ensure buffer size */
|
||||||
|
gst_buffer_ensure(vm, b, b->count + fsize);
|
||||||
|
fread((char *)(b->data + b->count), fsize, 1, f);
|
||||||
|
b->count += fsize;
|
||||||
|
gst_c_return(vm, gst_wrap_buffer(b));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Close a file */
|
||||||
|
int gst_stl_close(Gst *vm) {
|
||||||
|
FILE **fp = gst_check_userdata(vm, 0, &gst_stl_filetype);
|
||||||
|
if (fp == NULL) gst_c_throwc(vm, "expected file");
|
||||||
|
fclose(*fp);
|
||||||
|
gst_c_return(vm, gst_wrap_nil());
|
||||||
|
}
|
||||||
|
|
||||||
/****/
|
/****/
|
||||||
/* Temporary */
|
/* Temporary */
|
||||||
@ -576,8 +610,8 @@ static const GstModuleItem const std_module[] = {
|
|||||||
{"not", gst_stl_not},
|
{"not", gst_stl_not},
|
||||||
{"length", gst_stl_length},
|
{"length", gst_stl_length},
|
||||||
{"hash", gst_stl_hash},
|
{"hash", gst_stl_hash},
|
||||||
{"to-integer", gst_stl_to_int},
|
{"integer", gst_stl_to_int},
|
||||||
{"to-real", gst_stl_to_real},
|
{"real", gst_stl_to_real},
|
||||||
{"type", gst_stl_type},
|
{"type", gst_stl_type},
|
||||||
{"slice", gst_stl_slice},
|
{"slice", gst_stl_slice},
|
||||||
{"array", gst_stl_array},
|
{"array", gst_stl_array},
|
||||||
@ -585,7 +619,7 @@ static const GstModuleItem const std_module[] = {
|
|||||||
{"table", gst_stl_table},
|
{"table", gst_stl_table},
|
||||||
{"struct", gst_stl_struct},
|
{"struct", gst_stl_struct},
|
||||||
{"buffer", gst_stl_buffer},
|
{"buffer", gst_stl_buffer},
|
||||||
{"strcat", gst_stl_strcat},
|
{"string", gst_stl_string},
|
||||||
{"print", gst_stl_print},
|
{"print", gst_stl_print},
|
||||||
{"tostring", gst_stl_tostring},
|
{"tostring", gst_stl_tostring},
|
||||||
{"exit", gst_stl_exit},
|
{"exit", gst_stl_exit},
|
||||||
@ -601,6 +635,8 @@ static const GstModuleItem const std_module[] = {
|
|||||||
{"peek", gst_stl_peek},
|
{"peek", gst_stl_peek},
|
||||||
{"ensure", gst_stl_ensure},
|
{"ensure", gst_stl_ensure},
|
||||||
{"open", gst_stl_open},
|
{"open", gst_stl_open},
|
||||||
|
{"slurp", gst_stl_slurp},
|
||||||
|
{"close", gst_stl_close},
|
||||||
{"dasm", gst_stl_dasm},
|
{"dasm", gst_stl_dasm},
|
||||||
{NULL, NULL}
|
{NULL, NULL}
|
||||||
};
|
};
|
||||||
|
@ -1,45 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2017 Calvin Rose
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to
|
|
||||||
* deal in the Software without restriction, including without limitation the
|
|
||||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
||||||
* sell copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in
|
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
||||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
||||||
* IN THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <gst/gst.h>
|
|
||||||
|
|
||||||
/* Compares two strings */
|
|
||||||
int gst_string_compare(const uint8_t *lhs, const uint8_t *rhs) {
|
|
||||||
uint32_t xlen = gst_string_length(lhs);
|
|
||||||
uint32_t ylen = gst_string_length(rhs);
|
|
||||||
uint32_t len = xlen > ylen ? ylen : xlen;
|
|
||||||
uint32_t i;
|
|
||||||
for (i = 0; i < len; ++i) {
|
|
||||||
if (lhs[i] == rhs[i]) {
|
|
||||||
continue;
|
|
||||||
} else if (lhs[i] < rhs[i]) {
|
|
||||||
return -1; /* x is less than y */
|
|
||||||
} else {
|
|
||||||
return 1; /* y is less than x */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (xlen == ylen) {
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
return xlen < ylen ? -1 : 1;
|
|
||||||
}
|
|
||||||
}
|
|
@ -173,3 +173,15 @@ GstValue *gst_thread_popframe(Gst *vm, GstThread *thread) {
|
|||||||
else
|
else
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Count the number of stack frames in a thread */
|
||||||
|
uint32_t gst_thread_countframes(GstThread *thread) {
|
||||||
|
uint32_t count = 0;
|
||||||
|
const GstValue *stack = thread->data + GST_FRAME_SIZE;
|
||||||
|
const GstValue *laststack = thread->data + thread->count;
|
||||||
|
while (stack <= laststack) {
|
||||||
|
++count;
|
||||||
|
stack += gst_frame_size(stack) + GST_FRAME_SIZE;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
17
core/util.c
17
core/util.c
@ -63,12 +63,27 @@ GST_WRAP_DEFINE(buffer, GstBuffer *, GST_BYTEBUFFER, buffer)
|
|||||||
GST_WRAP_DEFINE(function, GstFunction *, GST_FUNCTION, function)
|
GST_WRAP_DEFINE(function, GstFunction *, GST_FUNCTION, function)
|
||||||
GST_WRAP_DEFINE(cfunction, GstCFunction, GST_CFUNCTION, cfunction)
|
GST_WRAP_DEFINE(cfunction, GstCFunction, GST_CFUNCTION, cfunction)
|
||||||
GST_WRAP_DEFINE(table, GstTable *, GST_TABLE, table)
|
GST_WRAP_DEFINE(table, GstTable *, GST_TABLE, table)
|
||||||
GST_WRAP_DEFINE(userdata, void *, GST_USERDATA, pointer)
|
|
||||||
GST_WRAP_DEFINE(funcenv, GstFuncEnv *, GST_FUNCENV, env)
|
GST_WRAP_DEFINE(funcenv, GstFuncEnv *, GST_FUNCENV, env)
|
||||||
GST_WRAP_DEFINE(funcdef, GstFuncDef *, GST_FUNCDEF, def)
|
GST_WRAP_DEFINE(funcdef, GstFuncDef *, GST_FUNCDEF, def)
|
||||||
|
|
||||||
#undef GST_WRAP_DEFINE
|
#undef GST_WRAP_DEFINE
|
||||||
|
|
||||||
|
GstValue gst_wrap_userdata(void *x) {
|
||||||
|
GstValue ret;
|
||||||
|
ret.type = GST_USERDATA;
|
||||||
|
ret.data.pointer = x;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *gst_check_userdata(Gst *vm, uint32_t i, const GstUserType *type) {
|
||||||
|
GstValue x = gst_arg(vm, i);
|
||||||
|
GstUserdataHeader *h;
|
||||||
|
if (x.type != GST_USERDATA) return NULL;
|
||||||
|
h = ((GstUserdataHeader *)x.data.pointer) - 1;
|
||||||
|
if (h->type != type) return NULL;
|
||||||
|
return x.data.pointer;
|
||||||
|
}
|
||||||
|
|
||||||
GstValue gst_cmodule_table(Gst *vm, const GstModuleItem *mod) {
|
GstValue gst_cmodule_table(Gst *vm, const GstModuleItem *mod) {
|
||||||
GstTable *module = gst_table(vm, 10);
|
GstTable *module = gst_table(vm, 10);
|
||||||
while (mod->name != NULL) {
|
while (mod->name != NULL) {
|
||||||
|
@ -148,14 +148,13 @@ typedef struct GstTable GstTable;
|
|||||||
typedef struct GstThread GstThread;
|
typedef struct GstThread GstThread;
|
||||||
typedef int (*GstCFunction)(Gst * vm);
|
typedef int (*GstCFunction)(Gst * vm);
|
||||||
|
|
||||||
/* Implementation details */
|
/* Other structs */
|
||||||
typedef struct GstUserdataHeader GstUserdataHeader;
|
typedef struct GstUserdataHeader GstUserdataHeader;
|
||||||
typedef struct GstFuncDef GstFuncDef;
|
typedef struct GstFuncDef GstFuncDef;
|
||||||
typedef struct GstFuncEnv GstFuncEnv;
|
typedef struct GstFuncEnv GstFuncEnv;
|
||||||
typedef union GstValueUnion GstValueUnion;
|
typedef union GstValueUnion GstValueUnion;
|
||||||
|
|
||||||
/* API Types */
|
|
||||||
typedef struct GstModuleItem GstModuleItem;
|
typedef struct GstModuleItem GstModuleItem;
|
||||||
|
typedef struct GstUserType GstUserType;
|
||||||
|
|
||||||
/* C Api data types */
|
/* C Api data types */
|
||||||
struct GstModuleItem {
|
struct GstModuleItem {
|
||||||
@ -259,10 +258,18 @@ struct GstFunction {
|
|||||||
GstFunction *parent;
|
GstFunction *parent;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Defines a type for userdata */
|
||||||
|
struct GstUserType {
|
||||||
|
const char *id;
|
||||||
|
GstValue (*serialize)(Gst *vm, void *data, uint32_t len);
|
||||||
|
GstValue (*deserialize)(Gst *vm, GstValue in);
|
||||||
|
void (*finalize)(Gst *vm, void *data, uint32_t len);
|
||||||
|
};
|
||||||
|
|
||||||
/* Contains information about userdata */
|
/* Contains information about userdata */
|
||||||
struct GstUserdataHeader {
|
struct GstUserdataHeader {
|
||||||
uint32_t size;
|
uint32_t size;
|
||||||
const GstValue *meta;
|
const GstUserType *type;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* VM return status from c function */
|
/* VM return status from c function */
|
||||||
@ -356,7 +363,7 @@ GstValue gst_array_peek(GstArray *array);
|
|||||||
/* Userdata functions */
|
/* Userdata functions */
|
||||||
/****/
|
/****/
|
||||||
|
|
||||||
void *gst_userdata(Gst *vm, uint32_t size, const GstValue *meta);
|
void *gst_userdata(Gst *vm, uint32_t size, const GstUserType *utype);
|
||||||
|
|
||||||
/****/
|
/****/
|
||||||
/* Tuple functions */
|
/* Tuple functions */
|
||||||
@ -409,6 +416,7 @@ void gst_thread_tuplepack(Gst *vm, GstThread *thread, uint32_t n);
|
|||||||
GstValue *gst_thread_beginframe(Gst *vm, GstThread *thread, GstValue callee, uint32_t arity);
|
GstValue *gst_thread_beginframe(Gst *vm, GstThread *thread, GstValue callee, uint32_t arity);
|
||||||
void gst_thread_endframe(Gst *vm, GstThread *thread);
|
void gst_thread_endframe(Gst *vm, GstThread *thread);
|
||||||
GstValue *gst_thread_popframe(Gst *vm, GstThread *thread);
|
GstValue *gst_thread_popframe(Gst *vm, GstThread *thread);
|
||||||
|
uint32_t gst_thread_countframes(GstThread *thread);
|
||||||
|
|
||||||
/****/
|
/****/
|
||||||
/* Value manipulation */
|
/* Value manipulation */
|
||||||
@ -427,43 +435,13 @@ GstInteger gst_length(Gst *vm, GstValue x);
|
|||||||
/* Serialization */
|
/* Serialization */
|
||||||
/****/
|
/****/
|
||||||
|
|
||||||
/**
|
|
||||||
* Data format
|
|
||||||
* State is encoded as a string of unsigned bytes.
|
|
||||||
*
|
|
||||||
* Types:
|
|
||||||
*
|
|
||||||
* Byte 0 to 200: small integer byte - 100
|
|
||||||
* Byte 201: Nil
|
|
||||||
* Byte 202: True
|
|
||||||
* Byte 203: False
|
|
||||||
* Byte 204: Number - double format
|
|
||||||
* Byte 205: String - [u32 length]*[u8... characters]
|
|
||||||
* Byte 206: Symbol - [u32 length]*[u8... characters]
|
|
||||||
* Byte 207: Buffer - [u32 length]*[u8... characters]
|
|
||||||
* Byte 208: Array - [u32 length]*[value... elements]
|
|
||||||
* Byte 209: Tuple - [u32 length]*[value... elements]
|
|
||||||
* Byte 210: Thread - [u8 state][u32 frames]*[[value callee][value env]
|
|
||||||
* [u32 pcoffset][u32 erroffset][u16 ret][u16 errloc][u16 size]*[value ...stack]
|
|
||||||
* Byte 211: Table - [u32 length]*2*[value... kvs]
|
|
||||||
* Byte 212: FuncDef - [u32 locals][u32 arity][u32 flags][u32 literallen]*[value...
|
|
||||||
* literals][u32 bytecodelen]*[u16... bytecode]
|
|
||||||
* Byte 213: FunEnv - [value thread][u32 length]*[value ...upvalues]
|
|
||||||
* (upvalues is not read if thread is a thread object)
|
|
||||||
* Byte 214: Func - [value parent][value def][value env]
|
|
||||||
* (nil values indicate empty)
|
|
||||||
* Byte 215: LUdata - [value meta][u32 length]*[u8... bytes]
|
|
||||||
* Byte 216: CFunc - [u32 length]*[u8... idstring]
|
|
||||||
* Byte 217: Ref - [u32 id]
|
|
||||||
* Byte 218: Integer - [i64 value]
|
|
||||||
*/
|
|
||||||
|
|
||||||
const char *gst_deserialize(
|
const char *gst_deserialize(
|
||||||
Gst *vm,
|
Gst *vm,
|
||||||
const uint8_t *data,
|
const uint8_t *data,
|
||||||
uint32_t len,
|
uint32_t len,
|
||||||
GstValue *out,
|
GstValue *out,
|
||||||
const uint8_t *nextData);
|
const uint8_t *nextData);
|
||||||
|
|
||||||
const char *gst_serialize(Gst *vm, GstBuffer *buffer, GstValue x);
|
const char *gst_serialize(Gst *vm, GstBuffer *buffer, GstValue x);
|
||||||
|
|
||||||
/****/
|
/****/
|
||||||
@ -473,6 +451,7 @@ const char *gst_serialize(Gst *vm, GstBuffer *buffer, GstValue x);
|
|||||||
#define GST_MEMTAG_STRING 4
|
#define GST_MEMTAG_STRING 4
|
||||||
#define GST_MEMTAG_TUPLE 8
|
#define GST_MEMTAG_TUPLE 8
|
||||||
#define GST_MEMTAG_STRUCT 16
|
#define GST_MEMTAG_STRUCT 16
|
||||||
|
#define GST_MEMTAG_USER 32
|
||||||
|
|
||||||
void gst_mark_value(Gst *vm, GstValue x);
|
void gst_mark_value(Gst *vm, GstValue x);
|
||||||
void gst_mark(Gst *vm, GstValueUnion x, GstType type);
|
void gst_mark(Gst *vm, GstValueUnion x, GstType type);
|
||||||
@ -539,10 +518,11 @@ int gst_check_buffer(Gst *vm, uint32_t i, GstBuffer *(*x));
|
|||||||
int gst_check_function(Gst *vm, uint32_t i, GstFunction *(*x));
|
int gst_check_function(Gst *vm, uint32_t i, GstFunction *(*x));
|
||||||
int gst_check_cfunction(Gst *vm, uint32_t i, GstCFunction (*x));
|
int gst_check_cfunction(Gst *vm, uint32_t i, GstCFunction (*x));
|
||||||
int gst_check_table(Gst *vm, uint32_t i, GstTable *(*x));
|
int gst_check_table(Gst *vm, uint32_t i, GstTable *(*x));
|
||||||
int gst_check_userdata(Gst *vm, uint32_t i, void *(*x));
|
|
||||||
int gst_check_funcenv(Gst *vm, uint32_t i, GstFuncEnv *(*x));
|
int gst_check_funcenv(Gst *vm, uint32_t i, GstFuncEnv *(*x));
|
||||||
int gst_check_funcdef(Gst *vm, uint32_t i, GstFuncDef *(*x));
|
int gst_check_funcdef(Gst *vm, uint32_t i, GstFuncDef *(*x));
|
||||||
|
void *gst_check_userdata(Gst *vm, uint32_t i, const GstUserType *type);
|
||||||
|
|
||||||
|
/* Treat similar types through uniform interfaces */
|
||||||
int gst_seq_view(GstValue seq, const GstValue **data, uint32_t *len);
|
int gst_seq_view(GstValue seq, const GstValue **data, uint32_t *len);
|
||||||
int gst_chararray_view(GstValue str, const uint8_t **data, uint32_t *len);
|
int gst_chararray_view(GstValue str, const uint8_t **data, uint32_t *len);
|
||||||
int gst_hashtable_view(GstValue tab, const GstValue **data, uint32_t *cap);
|
int gst_hashtable_view(GstValue tab, const GstValue **data, uint32_t *cap);
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
(: i (+ 1 i)))
|
(: i (+ 1 i)))
|
||||||
(if (> len 0) (pop parts))
|
(if (> len 0) (pop parts))
|
||||||
(push parts end)
|
(push parts end)
|
||||||
(apply strcat start parts)))
|
(apply string start parts)))
|
||||||
|
|
||||||
# Pretty print an object or struct
|
# Pretty print an object or struct
|
||||||
(: print-struct (fn [start end s]
|
(: print-struct (fn [start end s]
|
||||||
@ -28,7 +28,7 @@
|
|||||||
(: key (next s key)))
|
(: key (next s key)))
|
||||||
(if (> (length parts) 0) (pop parts))
|
(if (> (length parts) 0) (pop parts))
|
||||||
(push parts end)
|
(push parts end)
|
||||||
(apply strcat start parts)))
|
(apply string start parts)))
|
||||||
|
|
||||||
# Pretty
|
# Pretty
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user