mirror of
https://github.com/janet-lang/janet
synced 2024-12-24 23:40:27 +00:00
More work on compiler. Still has memory leak?
This commit is contained in:
parent
6ca5a76286
commit
f817610d4a
@ -32,7 +32,7 @@
|
||||
#include <readline/history.h>
|
||||
|
||||
/* Compile and run an ast */
|
||||
int debug_compile_and_run(Gst *vm, GstValue ast, GstValue env) {
|
||||
int debug_compile_and_run(Gst *vm, GstValue ast, GstValue last) {
|
||||
GstCompiler c;
|
||||
GstValue func;
|
||||
/* Try to compile generated AST */
|
||||
@ -40,7 +40,8 @@ int debug_compile_and_run(Gst *vm, GstValue ast, GstValue env) {
|
||||
gst_compiler_usemodule(&c, "std");
|
||||
gst_compiler_usemodule(&c, "std.io");
|
||||
gst_compiler_usemodule(&c, "std.parse");
|
||||
gst_compiler_globals(&c, env);
|
||||
gst_compiler_usemodule(&c, "std.compile");
|
||||
gst_compiler_global(&c, "_", last);
|
||||
func = gst_wrap_function(gst_compiler_compile(&c, ast));
|
||||
/* Check for compilation errors */
|
||||
if (c.error) {
|
||||
@ -105,7 +106,6 @@ int debug_run(Gst *vm, FILE *in) {
|
||||
int debug_repl(Gst *vm) {
|
||||
const char *buffer, *reader;
|
||||
GstParser p;
|
||||
GstValue *st;
|
||||
for (;;) {
|
||||
/* Init parser */
|
||||
gst_parser(&p, vm);
|
||||
@ -131,10 +131,7 @@ int debug_repl(Gst *vm) {
|
||||
printf("Unexpected end of source\n");
|
||||
continue;
|
||||
}
|
||||
/* Add _ to environemt */
|
||||
st = gst_struct_begin(vm, 1);
|
||||
gst_struct_put(st, gst_string_cv(vm, "_"), vm->ret);
|
||||
if (!debug_compile_and_run(vm, gst_parse_consume(&p), gst_wrap_struct(gst_struct_end(vm, st)))) {
|
||||
if (!debug_compile_and_run(vm, gst_parse_consume(&p), vm->ret)) {
|
||||
printf("%s\n", gst_to_string(vm, vm->ret));
|
||||
}
|
||||
}
|
||||
@ -147,6 +144,7 @@ int main(int argc, const char **argv) {
|
||||
gst_init(&vm);
|
||||
gst_stl_load(&vm);
|
||||
gst_parse_load(&vm);
|
||||
gst_compile_load(&vm);
|
||||
if (argc > 1) {
|
||||
const char *filename;
|
||||
FILE *f;
|
||||
|
239
core/compile.c
239
core/compile.c
@ -72,6 +72,7 @@ struct SlotTracker {
|
||||
Slot *slots;
|
||||
uint32_t count;
|
||||
uint32_t capacity;
|
||||
SlotTracker *next;
|
||||
};
|
||||
|
||||
/* A GstScope is a lexical scope in the program. It is
|
||||
@ -88,6 +89,8 @@ struct GstScope {
|
||||
uint16_t *freeHeap;
|
||||
GstTable *literals;
|
||||
GstArray *literalsArray;
|
||||
GstTable *namedLiterals;
|
||||
GstTable *nilNamedLiterals; /* Work around tables not containg nil */
|
||||
GstTable *locals;
|
||||
GstScope *parent;
|
||||
};
|
||||
@ -142,10 +145,14 @@ static GstScope *compiler_push_scope(GstCompiler *c, int sameFunction) {
|
||||
scope->nextLocal = c->tail->nextLocal;
|
||||
scope->literals = c->tail->literals;
|
||||
scope->literalsArray = c->tail->literalsArray;
|
||||
scope->namedLiterals = c->tail->namedLiterals;
|
||||
scope->nilNamedLiterals = c->tail->nilNamedLiterals;
|
||||
} else {
|
||||
scope->nextLocal = 0;
|
||||
scope->literals = gst_table(c->vm, 10);
|
||||
scope->literalsArray = gst_array(c->vm, 10);
|
||||
scope->namedLiterals = gst_table(c->vm, 10);
|
||||
scope->nilNamedLiterals = gst_table(c->vm, 10);
|
||||
}
|
||||
c->tail = scope;
|
||||
return scope;
|
||||
@ -204,6 +211,9 @@ static void tracker_init(GstCompiler *c, SlotTracker *tracker) {
|
||||
tracker->slots = gst_alloc(c->vm, 10 * sizeof(Slot));
|
||||
tracker->count = 0;
|
||||
tracker->capacity = 10;
|
||||
/* Push to tracker stack */
|
||||
tracker->next = (SlotTracker *) c->trackers;
|
||||
c->trackers = tracker;
|
||||
}
|
||||
|
||||
/* Free up a slot if it is a temporary slot (does not
|
||||
@ -300,6 +310,8 @@ static void compiler_tracker_free(GstCompiler *c, GstScope *scope, SlotTracker *
|
||||
for (i = tracker->count - 1; i < tracker->count; --i) {
|
||||
compiler_drop_slot(c, scope, tracker->slots[i]);
|
||||
}
|
||||
/* Pop from tracker stack */
|
||||
c->trackers = tracker->next;
|
||||
}
|
||||
|
||||
/* Add a new Slot to a slot tracker. */
|
||||
@ -350,7 +362,7 @@ static uint16_t compiler_declare_symbol(GstCompiler *c, GstScope *scope, GstValu
|
||||
|
||||
/* Try to resolve a symbol. If the symbol can be resovled, return true and
|
||||
* pass back the level and index by reference. */
|
||||
static int symbol_resolve(GstCompiler *c, GstValue x, uint16_t *level, uint16_t *index) {
|
||||
static int symbol_resolve(GstCompiler *c, GstValue x, uint16_t *level, uint16_t *index, GstValue *out) {
|
||||
GstScope *scope = c->tail;
|
||||
uint32_t currentLevel = scope->level;
|
||||
while (scope) {
|
||||
@ -360,7 +372,18 @@ static int symbol_resolve(GstCompiler *c, GstValue x, uint16_t *level, uint16_t
|
||||
*index = (uint16_t) check.data.integer;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Check for named literals */
|
||||
check = gst_table_get(scope->namedLiterals, x);
|
||||
if (check.type != GST_NIL) {
|
||||
*out = check;
|
||||
return 2;
|
||||
}
|
||||
/* Check for nil named literal */
|
||||
check = gst_table_get(scope->nilNamedLiterals, x);
|
||||
if (check.type != GST_NIL) {
|
||||
*out = gst_wrap_nil();
|
||||
return 2;
|
||||
}
|
||||
scope = scope->parent;
|
||||
}
|
||||
return 0;
|
||||
@ -377,23 +400,6 @@ static int symbol_resolve(GstCompiler *c, GstValue x, uint16_t *level, uint16_t
|
||||
* as the location on the stack. */
|
||||
static Slot compile_value(GstCompiler *c, FormOptions opts, GstValue x);
|
||||
|
||||
/* Compile a structure that evaluates to a literal value. Useful
|
||||
* for objects like strings, or anything else that cannot be instatiated
|
||||
* from bytecode and doesn't do anything in the AST. */
|
||||
static Slot compile_literal(GstCompiler *c, FormOptions opts, GstValue x) {
|
||||
GstScope *scope = c->tail;
|
||||
GstBuffer *buffer = c->buffer;
|
||||
Slot ret;
|
||||
uint16_t literalIndex;
|
||||
if (opts.resultUnused) return nil_slot();
|
||||
ret = compiler_get_target(c, opts);
|
||||
literalIndex = compiler_add_literal(c, scope, x);
|
||||
gst_buffer_push_u16(c->vm, buffer, GST_OP_CST);
|
||||
gst_buffer_push_u16(c->vm, buffer, ret.index);
|
||||
gst_buffer_push_u16(c->vm, buffer, literalIndex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Compile boolean, nil, and number values. */
|
||||
static Slot compile_nonref_type(GstCompiler *c, FormOptions opts, GstValue x) {
|
||||
GstBuffer *buffer = c->buffer;
|
||||
@ -430,17 +436,48 @@ static Slot compile_nonref_type(GstCompiler *c, FormOptions opts, GstValue x) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Compile a structure that evaluates to a literal value. Useful
|
||||
* for objects like strings, or anything else that cannot be instantiated
|
||||
* from bytecode and doesn't do anything in the AST. */
|
||||
static Slot compile_literal(GstCompiler *c, FormOptions opts, GstValue x) {
|
||||
GstScope *scope = c->tail;
|
||||
GstBuffer *buffer = c->buffer;
|
||||
Slot ret;
|
||||
uint16_t literalIndex;
|
||||
if (opts.resultUnused) return nil_slot();
|
||||
switch (x.type) {
|
||||
case GST_INTEGER:
|
||||
case GST_REAL:
|
||||
case GST_BOOLEAN:
|
||||
case GST_NIL:
|
||||
return compile_nonref_type(c, opts, x);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
ret = compiler_get_target(c, opts);
|
||||
literalIndex = compiler_add_literal(c, scope, x);
|
||||
gst_buffer_push_u16(c->vm, buffer, GST_OP_CST);
|
||||
gst_buffer_push_u16(c->vm, buffer, ret.index);
|
||||
gst_buffer_push_u16(c->vm, buffer, literalIndex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Compile a symbol. Resolves any kind of symbol. */
|
||||
static Slot compile_symbol(GstCompiler *c, FormOptions opts, GstValue sym) {
|
||||
GstValue lit = gst_wrap_nil();
|
||||
GstBuffer * buffer = c->buffer;
|
||||
uint16_t index = 0;
|
||||
uint16_t level = 0;
|
||||
Slot ret;
|
||||
if (opts.resultUnused) return nil_slot();
|
||||
if (!symbol_resolve(c, sym, &level, &index)) {
|
||||
int status = symbol_resolve(c, sym, &level, &index, &lit);
|
||||
if (!status) {
|
||||
c_error(c, "undefined symbol");
|
||||
}
|
||||
if (level > 0) {
|
||||
if (opts.resultUnused) return nil_slot();
|
||||
if (status == 2) {
|
||||
/* We have a named literal */
|
||||
return compile_literal(c, opts, lit);
|
||||
} else if (level > 0) {
|
||||
/* We have an upvalue */
|
||||
ret = compiler_get_target(c, opts);
|
||||
gst_buffer_push_u16(c->vm, buffer, GST_OP_UPV);
|
||||
@ -468,15 +505,20 @@ static Slot compile_symbol(GstCompiler *c, FormOptions opts, GstValue sym) {
|
||||
|
||||
/* Compile an assignment operation */
|
||||
static Slot compile_assign(GstCompiler *c, FormOptions opts, GstValue left, GstValue right) {
|
||||
GstValue lit = gst_wrap_nil();
|
||||
GstScope *scope = c->tail;
|
||||
GstBuffer *buffer = c->buffer;
|
||||
FormOptions subOpts;
|
||||
uint16_t target = 0;
|
||||
uint16_t level = 0;
|
||||
Slot slot;
|
||||
int status;
|
||||
subOpts.isTail = 0;
|
||||
subOpts.resultUnused = 0;
|
||||
if (symbol_resolve(c, left, &level, &target)) {
|
||||
status = symbol_resolve(c, left, &level, &target, &lit);
|
||||
if (status == 2) {
|
||||
c_error(c, "cannot set binding");
|
||||
} else if (status == 1) {
|
||||
/* Check if we have an up value. Otherwise, it's just a normal
|
||||
* local variable */
|
||||
if (level != 0) {
|
||||
@ -783,7 +825,7 @@ static Slot compile_apply(GstCompiler *c, FormOptions opts, const GstValue *form
|
||||
Slot slot = compile_value(c, subOpts, form[i]);
|
||||
compiler_tracker_push(c, &tracker, slot);
|
||||
}
|
||||
/* Write last item */
|
||||
/* Write last item */
|
||||
{
|
||||
Slot slot = compile_value(c, subOpts, form[gst_tuple_length(form) - 1]);
|
||||
slot = compiler_realize_slot(c, slot);
|
||||
@ -1028,39 +1070,32 @@ static Slot compile_value(GstCompiler *c, FormOptions opts, GstValue x) {
|
||||
void gst_compiler(GstCompiler *c, Gst *vm) {
|
||||
c->vm = vm;
|
||||
c->buffer = gst_buffer(vm, 128);
|
||||
c->env = gst_array(vm, 10);
|
||||
c->tail = NULL;
|
||||
c->error = NULL;
|
||||
c->trackers = NULL;
|
||||
compiler_push_scope(c, 0);
|
||||
}
|
||||
|
||||
/* Add a global variable */
|
||||
void gst_compiler_global(GstCompiler *c, const char *name, GstValue x) {
|
||||
GstScope *scope = c->tail;
|
||||
GstValue sym = gst_string_cv(c->vm, name);
|
||||
compiler_declare_symbol(c, c->tail, sym);
|
||||
gst_array_push(c->vm, c->env, x);
|
||||
if (x.type == GST_NIL)
|
||||
gst_table_put(c->vm, scope->nilNamedLiterals, sym, gst_wrap_boolean(1));
|
||||
else
|
||||
gst_table_put(c->vm, scope->namedLiterals, sym, x);
|
||||
}
|
||||
|
||||
/* Add many global variables */
|
||||
void gst_compiler_globals(GstCompiler *c, GstValue env) {
|
||||
GstScope *scope = c->tail;
|
||||
const GstValue *data;
|
||||
uint32_t len;
|
||||
uint32_t i;
|
||||
if (env.type == GST_TABLE) {
|
||||
GstTable *t = env.data.table;
|
||||
for (i = 0; i < t->capacity; i += 2) {
|
||||
if (t->data[i].type == GST_STRING) {
|
||||
compiler_declare_symbol(c, c->tail, t->data[i]);
|
||||
gst_array_push(c->vm, c->env, t->data[i + 1]);
|
||||
}
|
||||
}
|
||||
} else if (env.type == GST_STRUCT) {
|
||||
const GstValue *st = env.data.st;
|
||||
for (i = 0; i < gst_struct_capacity(st); i += 2) {
|
||||
if (st[i].type == GST_STRING) {
|
||||
compiler_declare_symbol(c, c->tail, st[i]);
|
||||
gst_array_push(c->vm, c->env, st[i + 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (gst_hashtable_view(env, &data, &len))
|
||||
for (i = 0; i < len; i += 2)
|
||||
if (data[i].type == GST_STRING)
|
||||
gst_table_put(c->vm, scope->namedLiterals, data[i], data[i + 1]);
|
||||
}
|
||||
|
||||
/* Use a module that was loaded into the vm */
|
||||
@ -1076,6 +1111,7 @@ GstFunction *gst_compiler_compile(GstCompiler *c, GstValue form) {
|
||||
GstFuncDef *def;
|
||||
if (setjmp(c->onError)) {
|
||||
/* Clear all but root scope */
|
||||
c->trackers = NULL;
|
||||
if (c->tail)
|
||||
c->tail->parent = NULL;
|
||||
if (c->error == NULL)
|
||||
@ -1088,16 +1124,10 @@ GstFunction *gst_compiler_compile(GstCompiler *c, GstValue form) {
|
||||
compiler_return(c, compile_value(c, opts, form));
|
||||
def = compiler_gen_funcdef(c, c->buffer->count, 0);
|
||||
{
|
||||
uint32_t envSize = c->env->count;
|
||||
GstFuncEnv *env = gst_alloc(c->vm, sizeof(GstFuncEnv));
|
||||
GstFunction *func = gst_alloc(c->vm, sizeof(GstFunction));
|
||||
if (envSize) {
|
||||
env->values = gst_alloc(c->vm, sizeof(GstValue) * envSize);
|
||||
gst_memcpy(env->values, c->env->data, envSize * sizeof(GstValue));
|
||||
} else {
|
||||
env->values = NULL;
|
||||
}
|
||||
env->stackOffset = envSize;
|
||||
env->values = NULL;
|
||||
env->stackOffset = 0;
|
||||
env->thread = NULL;
|
||||
func->parent = NULL;
|
||||
func->def = def;
|
||||
@ -1105,3 +1135,108 @@ GstFunction *gst_compiler_compile(GstCompiler *c, GstValue form) {
|
||||
return func;
|
||||
}
|
||||
}
|
||||
|
||||
/***/
|
||||
/* Stl */
|
||||
/***/
|
||||
|
||||
/* GC mark mark all memory used by the compiler */
|
||||
static void gst_compiler_mark(Gst *vm, void *data, uint32_t len) {
|
||||
SlotTracker *st;
|
||||
GstScope *scope;
|
||||
GstCompiler *c = (GstCompiler *) data;
|
||||
if (len != sizeof(GstCompiler))
|
||||
return;
|
||||
/* Mark compiler */
|
||||
gst_mark_value(vm, gst_wrap_buffer(c->buffer));
|
||||
/* Mark trackers */
|
||||
st = (SlotTracker *) c->trackers;
|
||||
while (st) {
|
||||
gst_mark_mem(vm, st->slots);
|
||||
st = st->next;
|
||||
}
|
||||
/* Mark scopes */
|
||||
scope = c->tail;
|
||||
while (scope) {
|
||||
gst_mark_mem(vm, scope->freeHeap);
|
||||
gst_mark_value(vm, gst_wrap_array(scope->literalsArray));
|
||||
gst_mark_value(vm, gst_wrap_table(scope->locals));
|
||||
gst_mark_value(vm, gst_wrap_table(scope->literals));
|
||||
gst_mark_value(vm, gst_wrap_table(scope->namedLiterals));
|
||||
gst_mark_value(vm, gst_wrap_table(scope->nilNamedLiterals));
|
||||
scope = scope->parent;
|
||||
}
|
||||
}
|
||||
|
||||
/* Compiler userdata type */
|
||||
static const GstUserType gst_stl_compilertype = {
|
||||
"std.compiler",
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
&gst_compiler_mark
|
||||
};
|
||||
|
||||
/* Create a compiler userdata */
|
||||
static int gst_stl_compiler(Gst *vm) {
|
||||
GstCompiler *c = gst_userdata(vm, sizeof(GstCompiler), &gst_stl_compilertype);
|
||||
gst_compiler(c, vm);
|
||||
gst_c_return(vm, gst_wrap_userdata(c));
|
||||
}
|
||||
|
||||
/* Add a binding to the compiler's current scope. */
|
||||
static int gst_stl_compiler_binding(Gst *vm) {
|
||||
GstCompiler *c = gst_check_userdata(vm, 0, &gst_stl_compilertype);
|
||||
GstScope *scope;
|
||||
GstValue sym;
|
||||
const uint8_t *data;
|
||||
uint32_t len;
|
||||
if (!c)
|
||||
gst_c_throwc(vm, "expected compiler");
|
||||
if (!gst_chararray_view(gst_arg(vm, 1), &data, &len))
|
||||
gst_c_throwc(vm, "expected string/buffer");
|
||||
scope = c->tail;
|
||||
sym = gst_wrap_string(gst_string_b(c->vm, data, len));
|
||||
gst_table_put(c->vm, scope->namedLiterals, sym, gst_arg(vm, 2));
|
||||
gst_c_return(vm, gst_wrap_userdata(c));
|
||||
}
|
||||
|
||||
/* Compile a value */
|
||||
static int gst_stl_compiler_compile(Gst *vm) {
|
||||
GstFunction *ret;
|
||||
GstCompiler *c = gst_check_userdata(vm, 0, &gst_stl_compilertype);
|
||||
if (!c)
|
||||
gst_c_throwc(vm, "expected compiler");
|
||||
ret = gst_compiler_compile(c, gst_arg(vm, 1));
|
||||
if (ret == NULL)
|
||||
gst_c_throwc(vm, c->error);
|
||||
gst_c_return(vm, gst_wrap_function(ret));
|
||||
}
|
||||
|
||||
/* Use an environment during compilation. Names that are declared more than
|
||||
* once should use their final declared value. */
|
||||
static int gst_stl_compiler_bindings(Gst *vm) {
|
||||
GstValue env;
|
||||
GstCompiler *c = gst_check_userdata(vm, 0, &gst_stl_compilertype);
|
||||
if (!c)
|
||||
gst_c_throwc(vm, "expected compiler");
|
||||
env = gst_arg(vm, 1);
|
||||
if (env.type != GST_TABLE && env.type != GST_STRUCT)
|
||||
gst_c_throwc(vm, "expected table/struct");
|
||||
gst_compiler_globals(c, env);
|
||||
gst_c_return(vm, gst_wrap_userdata(c));
|
||||
}
|
||||
|
||||
/* The module stuff */
|
||||
static const GstModuleItem gst_compile_module[] = {
|
||||
{"compiler", gst_stl_compiler},
|
||||
{"compile", gst_stl_compiler_compile},
|
||||
{"binding!", gst_stl_compiler_binding},
|
||||
{"bindings!", gst_stl_compiler_bindings},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
/* Load compiler library */
|
||||
void gst_compile_load(Gst *vm) {
|
||||
gst_module_put(vm, "std.compile", gst_cmodule_struct(vm, gst_compile_module));
|
||||
}
|
||||
|
33
core/value.c
33
core/value.c
@ -96,6 +96,37 @@ static const uint8_t *string_description(Gst *vm, const char *title, void *point
|
||||
return gst_string_b(vm, buf, c - buf);
|
||||
}
|
||||
|
||||
/* Gets the string value of userdata. Allocates memory, so is slower than
|
||||
* string_description. */
|
||||
static const uint8_t *string_udata(Gst *vm, const char *title, void *pointer) {
|
||||
uint32_t strlen = 0;
|
||||
uint8_t *c, *buf;
|
||||
uint32_t i;
|
||||
union {
|
||||
uint8_t bytes[sizeof(void *)];
|
||||
void *p;
|
||||
} pbuf;
|
||||
|
||||
while (title[strlen]) ++strlen;
|
||||
c = buf = gst_alloc(vm, strlen + 5 + 2 * sizeof(void *));
|
||||
pbuf.p = pointer;
|
||||
*c++ = '<';
|
||||
for (i = 0; title[i]; ++i)
|
||||
*c++ = ((uint8_t *)title) [i];
|
||||
*c++ = ' ';
|
||||
*c++ = '0';
|
||||
*c++ = 'x';
|
||||
for (i = sizeof(void *); i > 0; --i) {
|
||||
uint8_t byte = pbuf.bytes[i - 1];
|
||||
if (!byte) continue;
|
||||
*c++ = HEX(byte >> 4);
|
||||
*c++ = HEX(byte & 0xF);
|
||||
}
|
||||
*c++ = '>';
|
||||
return gst_string_b(vm, buf, c - buf);
|
||||
|
||||
}
|
||||
|
||||
#undef GST_BUFSIZE
|
||||
|
||||
/* Returns a string pointer or NULL if could not allocate memory. */
|
||||
@ -131,7 +162,7 @@ const uint8_t *gst_to_string(Gst *vm, GstValue x) {
|
||||
case GST_THREAD:
|
||||
return string_description(vm, "thread", x.data.pointer);
|
||||
case GST_USERDATA:
|
||||
return string_description(vm, "userdata", x.data.pointer);
|
||||
return string_udata(vm, gst_udata_type(x.data.pointer)->name, x.data.pointer);
|
||||
case GST_FUNCENV:
|
||||
return string_description(vm, "funcenv", x.data.pointer);
|
||||
case GST_FUNCDEF:
|
||||
|
@ -35,8 +35,8 @@ struct GstCompiler {
|
||||
const char *error;
|
||||
jmp_buf onError;
|
||||
GstScope *tail;
|
||||
GstArray *env;
|
||||
GstBuffer *buffer;
|
||||
void *trackers;
|
||||
};
|
||||
|
||||
/* Initialize the Compiler */
|
||||
@ -54,4 +54,7 @@ void gst_compiler_usemodule(GstCompiler *c, const char *modulename);
|
||||
/* Compile a function that evaluates the given form. */
|
||||
GstFunction *gst_compiler_compile(GstCompiler *c, GstValue form);
|
||||
|
||||
/* Load the library */
|
||||
void gst_compile_load(Gst *vm);
|
||||
|
||||
#endif /* end of include guard: COMPILE_H_9VXF71HY */
|
||||
|
@ -41,6 +41,11 @@
|
||||
#define gst_struct_capacity(t) (gst_struct_length(t) * 4)
|
||||
#define gst_struct_hash(t) (gst_struct_raw(t)[1])
|
||||
|
||||
/* Userdata utils */
|
||||
#define gst_udata_header(u) ((GstUserdataHeader *)(u) - 1)
|
||||
#define gst_udata_type(u) (gst_udata_header(u)->type)
|
||||
#define gst_udata_size(u) (gst_udata_header(u)->size)
|
||||
|
||||
/* Memcpy for moving memory */
|
||||
#ifndef gst_memcpy
|
||||
#include <string.h>
|
||||
@ -260,7 +265,7 @@ struct GstFunction {
|
||||
|
||||
/* Defines a type for userdata */
|
||||
struct GstUserType {
|
||||
const char *id;
|
||||
const char *name;
|
||||
GstValue (*serialize)(Gst *vm, void *data, uint32_t len);
|
||||
GstValue (*deserialize)(Gst *vm, GstValue in);
|
||||
void (*finalize)(Gst *vm, void *data, uint32_t len);
|
||||
|
Loading…
Reference in New Issue
Block a user