From c6e9f24f829604934e8c142e3f6e5175421f95f0 Mon Sep 17 00:00:00 2001 From: Calvin Rose Date: Wed, 3 May 2017 19:57:06 -0400 Subject: [PATCH] Complete adding parser to scripting. --- client/main.c | 2 + core/gc.c | 11 +++- core/parse.c | 125 ++++++++++++++++++++++++++++++++++++++++++-- core/stl.c | 8 +++ core/util.c | 2 +- include/gst/gst.h | 2 + include/gst/parse.h | 3 ++ 7 files changed, 145 insertions(+), 8 deletions(-) diff --git a/client/main.c b/client/main.c index d2b80f12..1173f503 100644 --- a/client/main.c +++ b/client/main.c @@ -39,6 +39,7 @@ int debug_compile_and_run(Gst *vm, GstValue ast, GstValue env) { gst_compiler(&c, vm); gst_compiler_usemodule(&c, "std"); gst_compiler_usemodule(&c, "std.io"); + gst_compiler_usemodule(&c, "std.parse"); gst_compiler_globals(&c, env); func = gst_wrap_function(gst_compiler_compile(&c, ast)); /* Check for compilation errors */ @@ -145,6 +146,7 @@ int main(int argc, const char **argv) { gst_init(&vm); gst_stl_load(&vm); + gst_parse_load(&vm); if (argc > 1) { const char *filename; FILE *f; diff --git a/core/gc.c b/core/gc.c index 608304b3..eb1c705b 100644 --- a/core/gc.c +++ b/core/gc.c @@ -34,6 +34,11 @@ struct GCMemoryHeader { uint32_t tags : 31; }; +/* Mark a chunk of memory as reachable for the gc */ +void gst_mark_mem(Gst *vm, void *mem) { + gc_header(mem)->color = vm->black; +} + /* Helper to mark function environments */ static void gst_mark_funcenv(Gst *vm, GstFuncEnv *env) { if (gc_header(env)->color != vm->black) { @@ -172,8 +177,10 @@ void gst_mark(Gst *vm, GstValueUnion x, GstType type) { case GST_USERDATA: if (gc_header(x.string - sizeof(GstUserdataHeader))->color != vm->black) { - GstUserdataHeader *userHeader = (GstUserdataHeader *)x.string - 1; - gc_header(userHeader)->color = vm->black; + GstUserdataHeader *h = (GstUserdataHeader *)x.pointer - 1; + gc_header(h)->color = vm->black; + if (h->type->gcmark) + h->type->gcmark(vm, x.pointer, h->size); } break; diff --git a/core/parse.c b/core/parse.c index 236ce2d1..7ccdaa24 100644 --- a/core/parse.c +++ b/core/parse.c @@ -42,11 +42,6 @@ struct GstParseState { uint8_t endDelimiter; GstArray *array; } form; - struct { - GstValue key; - int keyFound; - GstTable *table; - } table; struct { GstBuffer *buffer; uint32_t count; @@ -540,3 +535,123 @@ void gst_parser(GstParser *p, Gst *vm) { p->flags = GST_PARSER_FLAG_EXPECTING_COMMENT; parser_push(p, PTYPE_ROOT, ' '); } + +/* CG finalize a parser */ +static void gst_stl_parser_finalize(Gst *vm, void *data, uint32_t len) { + /* printf("Finalizing parser: %p, %d\n", data, len); */ +} + +/* GC mark a parser */ +static void gst_stl_parser_mark(Gst *vm, void *data, uint32_t len) { + uint32_t i; + GstParser *p = (GstParser *) data; + gst_mark_mem(vm, p->data); + gst_mark_value(vm, p->value); + for (i = 0; i < p->count; ++i) { + GstParseState *ps = p->data + i; + switch (ps->type) { + case PTYPE_ROOT: + break; + case PTYPE_FORM: + gst_mark_value(vm, gst_wrap_array(ps->buf.form.array)); + break; + case PTYPE_STRING: + case PTYPE_TOKEN: + gst_mark_value(vm, gst_wrap_buffer(ps->buf.string.buffer)); + break; + } + } +} + +/***/ +/* Stl functions */ +/***/ + +/* Parse filetype */ +static const GstUserType gst_stl_parsetype = { + "std.parser", + NULL, + NULL, + &gst_stl_parser_finalize, + &gst_stl_parser_mark +}; + +/* Create a parser */ +int gst_stl_parser(Gst *vm) { + GstParser *p = gst_userdata(vm, sizeof(GstParser), &gst_stl_parsetype); + gst_parser(p, vm); + gst_c_return(vm, gst_wrap_userdata(p)); +} + +/* Consume a value from the parser */ +int gst_stl_parser_consume(Gst *vm) { + GstParser *p = gst_check_userdata(vm, 0, &gst_stl_parsetype); + if (p == NULL) + gst_c_throwc(vm, "expected parser"); + if (!gst_parse_hasvalue(p)) + gst_c_throwc(vm, "parser has no pending value"); + gst_c_return(vm, gst_parse_consume(p)); +} + +/* Check if the parser has a value to consume */ +int gst_stl_parser_hasvalue(Gst *vm) { + GstParser *p = gst_check_userdata(vm, 0, &gst_stl_parsetype); + if (p == NULL) + gst_c_throwc(vm, "expected parser"); + gst_c_return(vm, gst_wrap_boolean(gst_parse_hasvalue(p))); +} + +/* Parse a single byte. Returns if the byte was successfully parsed. */ +int gst_stl_parser_byte(Gst *vm) { + GstInteger b; + GstParser *p = gst_check_userdata(vm, 0, &gst_stl_parsetype); + if (p == NULL) + gst_c_throwc(vm, "expected parser"); + if (!gst_check_integer(vm, 1, &b)) + gst_c_throwc(vm, "expected integer"); + if (p->status == GST_PARSER_PENDING || p->status == GST_PARSER_ROOT) { + dispatch_char(p, b); + gst_c_return(vm, gst_wrap_boolean(1)); + } else { + gst_c_return(vm, gst_wrap_boolean(0)); + } +} + +/* Parse a string or buffer. Returns nil if the entire char array is parsed, +* otherwise returns the remainder of what could not be parsed. */ +int gst_stl_parser_charseq(Gst *vm) { + uint32_t i; + uint32_t len; + const uint8_t *data; + GstParser *p = gst_check_userdata(vm, 0, &gst_stl_parsetype); + if (p == NULL) + gst_c_throwc(vm, "expected parser"); + if (!gst_chararray_view(gst_arg(vm, 1), &data, &len)) + gst_c_throwc(vm, "expected string/buffer"); + for (i = 0; i < len; ++i) { + if (p->status != GST_PARSER_PENDING && p->status != GST_PARSER_ROOT) break; + dispatch_char(p, data[i]); + } + if (i == len) { + /* No remainder */ + gst_c_return(vm, gst_wrap_nil()); + } else { + /* We have remaining characters */ + gst_c_return(vm, gst_wrap_string(gst_string_b(vm, data + i, len - i))); + } +} + +/* The module */ +static const GstModuleItem gst_parser_module[] = { + {"parser", gst_stl_parser}, + {"parse-byte", gst_stl_parser_byte}, + {"parse-consume", gst_stl_parser_consume}, + {"parse-hasvalue", gst_stl_parser_hasvalue}, + {"parse-charseq", gst_stl_parser_charseq}, + {NULL, NULL} +}; + +/* Load the module */ +void gst_parse_load(Gst *vm) { + gst_module_put(vm, "std.parse", gst_cmodule_struct(vm, gst_parser_module)); +} diff --git a/core/stl.c b/core/stl.c index 79640c99..89e23881 100644 --- a/core/stl.c +++ b/core/stl.c @@ -524,6 +524,7 @@ static GstUserType gst_stl_filetype = { "io.file", NULL, NULL, + NULL, NULL }; @@ -646,6 +647,12 @@ int gst_stl_dasm(Gst *vm) { return GST_RETURN_OK; } +/* Force garbage collection */ +int gst_stl_gcollect(Gst *vm) { + gst_collect(vm); + return GST_RETURN_OK; +} + /****/ /* Bootstraping */ /****/ @@ -693,6 +700,7 @@ static const GstModuleItem const std_module[] = { {"write", gst_stl_write}, {"close", gst_stl_close}, {"dasm", gst_stl_dasm}, + {"gcollect", gst_stl_gcollect}, {NULL, NULL} }; diff --git a/core/util.c b/core/util.c index dc3aee07..1c5be32e 100644 --- a/core/util.c +++ b/core/util.c @@ -191,7 +191,7 @@ GstInteger gst_real_to_integer(GstReal x) { } GstInteger gst_startrange(GstInteger raw, uint32_t len) { - if (raw > len) + if (raw >= len) return -1; if (raw < 0) return len + raw; diff --git a/include/gst/gst.h b/include/gst/gst.h index a6a35ac0..d9bd3ed9 100644 --- a/include/gst/gst.h +++ b/include/gst/gst.h @@ -264,6 +264,7 @@ struct GstUserType { GstValue (*serialize)(Gst *vm, void *data, uint32_t len); GstValue (*deserialize)(Gst *vm, GstValue in); void (*finalize)(Gst *vm, void *data, uint32_t len); + void (*gcmark)(Gst *vm, void *data, uint32_t len); }; /* Contains information about userdata */ @@ -462,6 +463,7 @@ void gst_mem_tag(void *mem, uint32_t tags); void gst_collect(Gst *vm); void gst_maybe_collect(Gst *vm); void gst_clear_memory(Gst *vm); +void gst_mark_mem(Gst *vm, void *mem); /****/ /* VM */ diff --git a/include/gst/parse.h b/include/gst/parse.h index 80bb98a3..17aa5158 100644 --- a/include/gst/parse.h +++ b/include/gst/parse.h @@ -68,4 +68,7 @@ int gst_parse_hasvalue(GstParser *p); /* Gets a value from the parser */ GstValue gst_parse_consume(GstParser *p); +/* Load the parsing library */ +void gst_parse_load(Gst *vm); + #endif /* end of include guard: PARSE_H_ONYWMADW */