1
0
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:
Calvin Rose 2017-04-26 10:21:03 -04:00
parent d295e281e1
commit bf2c16ccb0
12 changed files with 257 additions and 170 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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