mirror of
https://github.com/janet-lang/janet
synced 2024-11-24 09:17:17 +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 #####
|
||||
###################################
|
||||
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)
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
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) {
|
||||
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 {
|
||||
|
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;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
195
core/serialize.c
195
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 */
|
||||
|
60
core/stl.c
60
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}
|
||||
};
|
||||
|
@ -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
|
||||
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(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) {
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user