From bf2c16ccb0eab8ee34a547deeeefaf4d0b33ff54 Mon Sep 17 00:00:00 2001 From: Calvin Rose Date: Wed, 26 Apr 2017 10:21:03 -0400 Subject: [PATCH] Flesh out support for userdata Add file reading via file objects. Finalizer option for userdata. --- Makefile | 2 +- core/cache.h | 1 + core/ds.c | 5 +- core/gc.c | 10 ++- core/ids.c | 22 ++++++ core/serialize.c | 195 ++++++++++++++++++++++++++++++---------------- core/stl.c | 60 +++++++++++--- core/strings.c | 45 ----------- core/thread.c | 12 +++ core/util.c | 17 +++- include/gst/gst.h | 54 ++++--------- libs/pp.gst | 4 +- 12 files changed, 257 insertions(+), 170 deletions(-) delete mode 100644 core/strings.c diff --git a/Makefile b/Makefile index 6842e0ee..103c3307 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,7 @@ all: $(GST_TARGET) ##### The core vm and runtime ##### ################################### 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) GST_CORE_OBJECTS=$(patsubst %.c,%.o,$(GST_CORE_SOURCES)) $(GST_CORELIB): $(GST_CORE_OBJECTS) $(GST_HEADERS) diff --git a/core/cache.h b/core/cache.h index 2c80210b..b9ca4f9a 100644 --- a/core/cache.h +++ b/core/cache.h @@ -28,5 +28,6 @@ void gst_cache_remove_string(Gst *vm, char *strmem); void gst_cache_remove_tuple(Gst *vm, char *tuplemem); 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 */ diff --git a/core/ds.c b/core/ds.c index b40c9e95..61a391f8 100644 --- a/core/ds.c +++ b/core/ds.c @@ -159,12 +159,13 @@ GstValue gst_array_peek(GstArray *array) { /****/ /* 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); GstUserdataHeader *header = (GstUserdataHeader *)data; void *user = data + sizeof(GstUserdataHeader); header->size = size; - header->meta = meta; + header->type = utype; + gst_mem_tag(header, GST_MEMTAG_USER); return user; } diff --git a/core/gc.c b/core/gc.c index e6f0d377..608304b3 100644 --- a/core/gc.c +++ b/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) { GstUserdataHeader *userHeader = (GstUserdataHeader *)x.string - 1; gc_header(userHeader)->color = vm->black; - GstValueUnion temp; - temp.st = userHeader->meta; - gst_mark(vm, temp, GST_STRUCT); } + break; case GST_FUNCENV: gst_mark_funcenv(vm, x.env); @@ -210,6 +208,12 @@ void gst_sweep(Gst *vm) { gst_cache_remove_struct(vm, (char *)(current + 1)); if (current->tags & GST_MEMTAG_TUPLE) 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); } else { diff --git a/core/ids.c b/core/ids.c index bc9e6601..0728ebdc 100644 --- a/core/ids.c +++ b/core/ids.c @@ -395,3 +395,25 @@ GstValue gst_string_cv(Gst *vm, const char *str) { ret.data.string = data; 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; + } +} diff --git a/core/serialize.c b/core/serialize.c index 5f714bee..12265be3 100644 --- a/core/serialize.c +++ b/core/serialize.c @@ -38,12 +38,12 @@ * 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][u16 ret][u16 args][u16 size]*[value ...stack] + * Byte 210: Thread - [value parent][u8 state][u32 frames]*[[value callee][value env] + * [u32 pcoffset][u32 ret][u32 args][u32 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] + * Byte 213: FuncEnv - [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) @@ -232,14 +232,15 @@ static const char *gst_deserialize_impl( case 210: /* Thread */ { - GstValue nil; GstThread *t; GstValue *stack; uint16_t prevsize = 0; uint8_t statusbyte; - nil.type = GST_NIL; - t = gst_thread(vm, nil, 64); - ret.type = GST_THREAD; + t = gst_thread(vm, gst_wrap_nil(), 64); + err = gst_deserialize_impl(vm, data, end, &data, visited, &ret); + 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; deser_assert(data < end, UEB); statusbyte = *data++; @@ -258,16 +259,16 @@ static const char *gst_deserialize_impl( uint16_t ret, args, size, j; /* Create a new frame */ if (i > 0) - gst_thread_beginframe(vm, t, nil, 0); + gst_thread_beginframe(vm, t, gst_wrap_nil(), 0); /* Read the stack */ err = gst_deserialize_impl(vm, data, end, &data, visited, &callee); if (err != NULL) return err; err = gst_deserialize_impl(vm, data, end, &data, visited, &env); if (err != NULL) return err; read_u32(pcoffset); - read_u16(ret); - read_u16(args); - read_u16(size); + read_u32(ret); + read_u32(args); + read_u32(size); /* Set up the stack */ stack = gst_thread_stack(t); if (callee.type == GST_FUNCTION) { @@ -295,7 +296,7 @@ static const char *gst_deserialize_impl( ret.type = GST_TABLE; read_u32(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; err = gst_deserialize_impl(vm, data, end, &data, visited, &key); if (err != NULL) return err; @@ -393,16 +394,8 @@ static const char *gst_deserialize_impl( case 215: /* LUdata */ { - GstValue meta; - ret.type = GST_USERDATA; - 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); + /* TODO enable deserialization of userdata through registration + * to names in vm. */ } break; @@ -445,7 +438,7 @@ const char *gst_deserialize( *out = ret; return NULL; } - + /* Allow appending other types to buffers */ BUFFER_DEFINE(real, GstReal) BUFFER_DEFINE(integer, GstInteger) @@ -508,56 +501,124 @@ const char *gst_serialize_impl( /* Check reference types */ switch (x.type) { default: - return "unable to serialize type"; + return "unable to serialize type"; case GST_STRING: - write_byte(205); - count = gst_string_length(x.data.string); - write_u32(count); - for (i = 0; i < count; ++i) { - write_byte(x.data.string[i]); - } - break; + write_byte(205); + count = gst_string_length(x.data.string); + write_u32(count); + for (i = 0; i < count; ++i) { + write_byte(x.data.string[i]); + } + break; case GST_STRUCT: - write_byte(206); - count = gst_struct_length(x.data.st); - write_u32(count); - for (i = 0; i < gst_struct_capacity(x.data.st); i += 2) { - if (x.data.st[i].type != GST_NIL) { - err = gst_serialize_impl(vm, buffer, visited, nextId, x.data.st[i]); - if (err != NULL) return err; - err = gst_serialize_impl(vm, buffer, visited, nextId, x.data.st[i + 1]); - if (err != NULL) return err; - } - } - break; + write_byte(206); + count = gst_struct_length(x.data.st); + write_u32(count); + for (i = 0; i < gst_struct_capacity(x.data.st); i += 2) { + if (x.data.st[i].type != GST_NIL) { + err = gst_serialize_impl(vm, buffer, visited, nextId, x.data.st[i]); + if (err != NULL) return err; + err = gst_serialize_impl(vm, buffer, visited, nextId, x.data.st[i + 1]); + if (err != NULL) return err; + } + } + break; case GST_BYTEBUFFER: - write_byte(207); - count = x.data.buffer->count; - write_u32(count); - for (i = 0; i < count; ++i) { + write_byte(207); + count = x.data.buffer->count; + write_u32(count); + for (i = 0; i < count; ++i) { write_byte(x.data.buffer->data[i]); - } - break; + } + break; case GST_ARRAY: - write_byte(208); - count = x.data.array->count; - write_u32(count); - for (i = 0; i < count; ++i) { - err = gst_serialize_impl(vm, buffer, visited, nextId, x.data.array->data[i]); - if (err != NULL) return err; - } - break; + write_byte(208); + count = x.data.array->count; + write_u32(count); + for (i = 0; i < count; ++i) { + err = gst_serialize_impl(vm, buffer, visited, nextId, x.data.array->data[i]); + if (err != NULL) return err; + } + break; case GST_TUPLE: - write_byte(209); - count = gst_tuple_length(x.data.tuple); - write_u32(count); - for (i = 0; i < count; ++i) { - err = gst_serialize_impl(vm, buffer, visited, nextId, x.data.tuple[i]); - if (err != NULL) return err; - } - break; - /*case GST_THREAD:*/ - /*break;*/ + write_byte(209); + count = gst_tuple_length(x.data.tuple); + write_u32(count); + for (i = 0; i < count; ++i) { + err = gst_serialize_impl(vm, buffer, visited, nextId, x.data.tuple[i]); + if (err != NULL) return err; + } + break; + case GST_THREAD: + { + 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 */ diff --git a/core/stl.c b/core/stl.c index 6fca43e0..1d1aa83d 100644 --- a/core/stl.c +++ b/core/stl.c @@ -328,17 +328,21 @@ int gst_stl_struct(Gst *vm) { /* Create a buffer */ int gst_stl_buffer(Gst *vm) { uint32_t i, count; + const uint8_t *dat; + uint32_t slen; GstBuffer *buf = gst_buffer(vm, 10); count = gst_count_args(vm); for (i = 0; i < count; ++i) { - const uint8_t *string = gst_to_string(vm, gst_arg(vm, i)); - gst_buffer_append(vm, buf, string, gst_string_length(string)); + if (gst_chararray_view(gst_arg(vm, i), &dat, &slen)) + gst_buffer_append(vm, buf, dat, slen); + else + gst_c_throwc(vm, GST_EXPECTED_STRING); } gst_c_return(vm, gst_wrap_buffer(buf)); } -/* Concatenate strings */ -int gst_stl_strcat(Gst *vm) { +/* Create a string */ +int gst_stl_string(Gst *vm) { uint32_t j; uint32_t count = gst_count_args(vm); uint32_t length = 0; @@ -515,7 +519,13 @@ int gst_stl_setglobal(Gst *vm) { /* 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. */ 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)); FILE *f; FILE **fp; - GstValue *st; if (gst_count_args(vm) < 2 || gst_arg(vm, 0).type != GST_STRING || gst_arg(vm, 1).type != GST_STRING) gst_c_throwc(vm, "expected filename and filemode"); f = fopen((const char *)fname, (const char *)fmode); if (!f) gst_c_throwc(vm, "could not open file"); - st = gst_struct_begin(vm, 0); - fp = gst_userdata(vm, sizeof(FILE *), gst_struct_end(vm, st)); + fp = gst_userdata(vm, sizeof(FILE *), &gst_stl_filetype); *fp = f; 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 */ @@ -576,8 +610,8 @@ static const GstModuleItem const std_module[] = { {"not", gst_stl_not}, {"length", gst_stl_length}, {"hash", gst_stl_hash}, - {"to-integer", gst_stl_to_int}, - {"to-real", gst_stl_to_real}, + {"integer", gst_stl_to_int}, + {"real", gst_stl_to_real}, {"type", gst_stl_type}, {"slice", gst_stl_slice}, {"array", gst_stl_array}, @@ -585,7 +619,7 @@ static const GstModuleItem const std_module[] = { {"table", gst_stl_table}, {"struct", gst_stl_struct}, {"buffer", gst_stl_buffer}, - {"strcat", gst_stl_strcat}, + {"string", gst_stl_string}, {"print", gst_stl_print}, {"tostring", gst_stl_tostring}, {"exit", gst_stl_exit}, @@ -601,6 +635,8 @@ static const GstModuleItem const std_module[] = { {"peek", gst_stl_peek}, {"ensure", gst_stl_ensure}, {"open", gst_stl_open}, + {"slurp", gst_stl_slurp}, + {"close", gst_stl_close}, {"dasm", gst_stl_dasm}, {NULL, NULL} }; diff --git a/core/strings.c b/core/strings.c deleted file mode 100644 index a10a3d94..00000000 --- a/core/strings.c +++ /dev/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 - -/* 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; - } -} diff --git a/core/thread.c b/core/thread.c index f7551873..9cc4422f 100644 --- a/core/thread.c +++ b/core/thread.c @@ -173,3 +173,15 @@ GstValue *gst_thread_popframe(Gst *vm, GstThread *thread) { else 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; +} diff --git a/core/util.c b/core/util.c index 3062ee5b..dc3aee07 100644 --- a/core/util.c +++ b/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(cfunction, GstCFunction, GST_CFUNCTION, cfunction) 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(funcdef, GstFuncDef *, GST_FUNCDEF, def) #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) { GstTable *module = gst_table(vm, 10); while (mod->name != NULL) { diff --git a/include/gst/gst.h b/include/gst/gst.h index f4e12610..a6a35ac0 100644 --- a/include/gst/gst.h +++ b/include/gst/gst.h @@ -148,14 +148,13 @@ typedef struct GstTable GstTable; typedef struct GstThread GstThread; typedef int (*GstCFunction)(Gst * vm); -/* Implementation details */ +/* Other structs */ typedef struct GstUserdataHeader GstUserdataHeader; typedef struct GstFuncDef GstFuncDef; typedef struct GstFuncEnv GstFuncEnv; typedef union GstValueUnion GstValueUnion; - -/* API Types */ typedef struct GstModuleItem GstModuleItem; +typedef struct GstUserType GstUserType; /* C Api data types */ struct GstModuleItem { @@ -259,10 +258,18 @@ struct GstFunction { 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 */ struct GstUserdataHeader { uint32_t size; - const GstValue *meta; + const GstUserType *type; }; /* VM return status from c function */ @@ -356,7 +363,7 @@ GstValue gst_array_peek(GstArray *array); /* 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 */ @@ -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); void gst_thread_endframe(Gst *vm, GstThread *thread); GstValue *gst_thread_popframe(Gst *vm, GstThread *thread); +uint32_t gst_thread_countframes(GstThread *thread); /****/ /* Value manipulation */ @@ -427,43 +435,13 @@ GstInteger gst_length(Gst *vm, GstValue x); /* 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( Gst *vm, const uint8_t *data, uint32_t len, GstValue *out, const uint8_t *nextData); + 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_TUPLE 8 #define GST_MEMTAG_STRUCT 16 +#define GST_MEMTAG_USER 32 void gst_mark_value(Gst *vm, GstValue x); 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_cfunction(Gst *vm, uint32_t i, GstCFunction (*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_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_chararray_view(GstValue str, const uint8_t **data, uint32_t *len); int gst_hashtable_view(GstValue tab, const GstValue **data, uint32_t *cap); diff --git a/libs/pp.gst b/libs/pp.gst index a6ded9d7..be47fd13 100644 --- a/libs/pp.gst +++ b/libs/pp.gst @@ -14,7 +14,7 @@ (: i (+ 1 i))) (if (> len 0) (pop parts)) (push parts end) - (apply strcat start parts))) + (apply string start parts))) # Pretty print an object or struct (: print-struct (fn [start end s] @@ -28,7 +28,7 @@ (: key (next s key))) (if (> (length parts) 0) (pop parts)) (push parts end) - (apply strcat start parts))) + (apply string start parts))) # Pretty