diff options
-rw-r--r-- | CMakeLists.txt | 5 | ||||
-rw-r--r-- | chunk.h | 28 | ||||
-rw-r--r-- | compiler.c | 33 | ||||
-rw-r--r-- | lexer.c | 77 | ||||
-rw-r--r-- | lexer.h | 6 | ||||
-rw-r--r-- | lib.c | 52 | ||||
-rw-r--r-- | lib/uci.c | 14 | ||||
-rw-r--r-- | main.c | 9 | ||||
-rw-r--r-- | source.h | 10 | ||||
-rw-r--r-- | tests/cram/test_basic.t | 5 | ||||
-rw-r--r-- | types.c | 11 | ||||
-rw-r--r-- | types.h | 144 | ||||
-rw-r--r-- | util.h | 2 | ||||
-rw-r--r-- | value.c | 2 | ||||
-rw-r--r-- | value.h | 15 | ||||
-rw-r--r-- | vm.c | 37 | ||||
-rw-r--r-- | vm.h | 49 |
17 files changed, 278 insertions, 221 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index c6bfec9..0d5fe54 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -107,8 +107,9 @@ IF(UNIT_TESTING) LIST(APPEND CMAKE_CTEST_ARGUMENTS "--output-on-failure") IF(CMAKE_C_COMPILER_ID STREQUAL "Clang") - ADD_EXECUTABLE(ucode-san ${UCODE_SOURCES}) - TARGET_LINK_LIBRARIES(ucode-san ${json}) + ADD_EXECUTABLE(ucode-san ${UCODE_SOURCES}) + SET_PROPERTY(TARGET ucode-san PROPERTY ENABLE_EXPORTS 1) + TARGET_LINK_LIBRARIES(ucode-san ${json}) TARGET_COMPILE_OPTIONS(ucode-san PRIVATE -g -fno-omit-frame-pointer -fsanitize=undefined,address,leak -fno-sanitize-recover=all) TARGET_LINK_OPTIONS(ucode-san PRIVATE -fsanitize=undefined,address,leak) ENDIF() @@ -22,38 +22,12 @@ #include "value.h" #include "util.h" - - -typedef struct { - size_t from, to, target, slot; -} uc_ehrange; - -typedef struct { - size_t from, to, slot, nameidx; -} uc_varrange; - -uc_declare_vector(uc_ehranges, uc_ehrange); -uc_declare_vector(uc_variables, uc_varrange); -uc_declare_vector(uc_offsetinfo, uint8_t); - -typedef struct { - size_t count; - uint8_t *entries; - uc_value_list constants; - uc_ehranges ehranges; - struct { - uc_variables variables; - uc_value_list varnames; - uc_offsetinfo offsets; - } debuginfo; -} uc_chunk; +#include "types.h" void uc_chunk_init(uc_chunk *chunk); void uc_chunk_free(uc_chunk *chunk); size_t uc_chunk_add(uc_chunk *chunk, uint8_t byte, size_t line); -typedef struct uc_value_t uc_value_t; - ssize_t uc_chunk_add_constant(uc_chunk *chunk, uc_value_t *value); uc_value_t *uc_chunk_get_constant(uc_chunk *chunk, size_t idx); void uc_chunk_pop(uc_chunk *chunk); @@ -468,7 +468,12 @@ uc_compiler_emit_s32(uc_compiler *compiler, size_t srcpos, int32_t n) { uc_chunk *chunk = uc_compiler_current_chunk(compiler); size_t lineoff = uc_compiler_set_srcpos(compiler, srcpos); - uint32_t v = n + 0x7fffffff; + uint32_t v; + + if (n <= 0) + v = n + 0x7fffffff; + else + v = (uint32_t)n + 0x7fffffff; uc_chunk_add(chunk, v / 0x1000000, lineoff); uc_chunk_add(chunk, (v / 0x10000) % 0x100, 0); @@ -555,9 +560,9 @@ uc_compiler_get_jmpaddr(uc_compiler *compiler, size_t off) assert(off + 4 < chunk->count); return ( - chunk->entries[off + 1] * 0x1000000 + - chunk->entries[off + 2] * 0x10000 + - chunk->entries[off + 3] * 0x100 + + chunk->entries[off + 1] * 0x1000000UL + + chunk->entries[off + 2] * 0x10000UL + + chunk->entries[off + 3] * 0x100UL + chunk->entries[off + 4] ) - 0x7fffffff; } @@ -1065,7 +1070,7 @@ static bool uc_compiler_compile_arrowfn(uc_compiler *compiler, uc_value_t *args, bool restarg) { bool array = (ucv_type(args) == UC_ARRAY); - uc_compiler fncompiler = {}; + uc_compiler fncompiler = { 0 }; size_t i, pos, load_off; uc_function_t *fn; ssize_t slot; @@ -1283,7 +1288,7 @@ static void uc_compiler_compile_call(uc_compiler *compiler, bool assignable) { uc_chunk *chunk = uc_compiler_current_chunk(compiler); - uc_jmplist spreads = {}; + uc_jmplist spreads = { 0 }; enum insn_type type; size_t i, nargs = 0; @@ -1422,7 +1427,7 @@ uc_compiler_compile_delimitted_block(uc_compiler *compiler, uc_tokentype_t endty static void uc_compiler_compile_function(uc_compiler *compiler, bool assignable) { - uc_compiler fncompiler = {}; + uc_compiler fncompiler = { 0 }; uc_value_t *name = NULL; ssize_t slot = -1, pos; uc_tokentype_t type; @@ -1891,7 +1896,7 @@ uc_compiler_compile_if(uc_compiler *compiler) uc_chunk *chunk = uc_compiler_current_chunk(compiler); size_t jmpz_off, jmp_off, i; bool expect_endif = false; - uc_jmplist elifs = {}; + uc_jmplist elifs = { 0 }; uc_tokentype_t type; /* parse & compile condition expression */ @@ -1996,7 +2001,7 @@ uc_compiler_compile_while(uc_compiler *compiler) { uc_chunk *chunk = uc_compiler_current_chunk(compiler); size_t cond_off, jmpz_off, end_off; - uc_patchlist p = {}; + uc_patchlist p = { 0 }; p.parent = compiler->patchlist; compiler->patchlist = &p; @@ -2044,7 +2049,7 @@ uc_compiler_compile_for_in(uc_compiler *compiler, bool local, uc_token *kvar, uc { uc_chunk *chunk = uc_compiler_current_chunk(compiler); size_t skip_jmp, test_jmp, key_slot, val_slot; - uc_patchlist p = {}; + uc_patchlist p = { 0 }; p.parent = compiler->patchlist; compiler->patchlist = &p; @@ -2154,7 +2159,7 @@ uc_compiler_compile_for_count(uc_compiler *compiler, bool local, uc_token *var) { uc_chunk *chunk = uc_compiler_current_chunk(compiler); size_t test_off = 0, incr_off, skip_off, cond_off = 0; - uc_patchlist p = {}; + uc_patchlist p = { 0 }; p.parent = compiler->patchlist; compiler->patchlist = &p; @@ -2254,7 +2259,7 @@ uc_compiler_compile_for_count(uc_compiler *compiler, bool local, uc_token *var) static void uc_compiler_compile_for(uc_compiler *compiler) { - uc_token keyvar = {}, valvar = {}; + uc_token keyvar = { 0 }, valvar = { 0 }; bool local; uc_compiler_parse_consume(compiler, TK_LPAREN); @@ -2309,8 +2314,8 @@ uc_compiler_compile_switch(uc_compiler *compiler) size_t i, test_jmp, skip_jmp, next_jmp, value_slot, default_off = 0; uc_chunk *chunk = uc_compiler_current_chunk(compiler); uc_locals *locals = &compiler->locals; - uc_jmplist cases = {}; - uc_patchlist p = {}; + uc_jmplist cases = { 0 }; + uc_patchlist p = { 0 }; p.parent = compiler->patchlist; compiler->patchlist = &p; @@ -38,7 +38,7 @@ struct keyword { union { double d; bool b; - }; + } u; }; struct token { @@ -46,7 +46,7 @@ struct token { union { uint32_t patn; char pat[4]; - }; + } u; unsigned plen; uc_token *(*parse)(uc_lexer *, bool); }; @@ -135,33 +135,33 @@ static const struct token tokens[] = { }; static const struct keyword reserved_words[] = { - { TK_ENDFUNC, "endfunction", 11, {} }, + { TK_ENDFUNC, "endfunction", 11, { 0 } }, { TK_DOUBLE, "Infinity", 8, { .d = INFINITY } }, - { TK_CONTINUE, "continue", 8, {} }, - { TK_ENDWHILE, "endwhile", 8, {} }, - { TK_FUNC, "function", 8, {} }, - { TK_DEFAULT, "default", 7, {} }, - { TK_RETURN, "return", 6, {} }, - { TK_ENDFOR, "endfor", 6, {} }, - { TK_SWITCH, "switch", 6, {} }, - { TK_LOCAL, "local", 5, {} }, - { TK_ENDIF, "endif", 5, {} }, - { TK_WHILE, "while", 5, {} }, - { TK_BREAK, "break", 5, {} }, - { TK_CATCH, "catch", 5, {} }, + { TK_CONTINUE, "continue", 8, { 0 } }, + { TK_ENDWHILE, "endwhile", 8, { 0 } }, + { TK_FUNC, "function", 8, { 0 } }, + { TK_DEFAULT, "default", 7, { 0 } }, + { TK_RETURN, "return", 6, { 0 } }, + { TK_ENDFOR, "endfor", 6, { 0 } }, + { TK_SWITCH, "switch", 6, { 0 } }, + { TK_LOCAL, "local", 5, { 0 } }, + { TK_ENDIF, "endif", 5, { 0 } }, + { TK_WHILE, "while", 5, { 0 } }, + { TK_BREAK, "break", 5, { 0 } }, + { TK_CATCH, "catch", 5, { 0 } }, { TK_BOOL, "false", 5, { .b = false } }, { TK_BOOL, "true", 4, { .b = true } }, - { TK_ELIF, "elif", 4, {} }, - { TK_ELSE, "else", 4, {} }, - { TK_THIS, "this", 4, {} }, - { TK_NULL, "null", 4, {} }, - { TK_CASE, "case", 4, {} }, + { TK_ELIF, "elif", 4, { 0 } }, + { TK_ELSE, "else", 4, { 0 } }, + { TK_THIS, "this", 4, { 0 } }, + { TK_NULL, "null", 4, { 0 } }, + { TK_CASE, "case", 4, { 0 } }, { TK_DOUBLE, "NaN", 3, { .d = NAN } }, - { TK_TRY, "try", 3, {} }, - { TK_FOR, "for", 3, {} }, - { TK_LOCAL, "let", 3, {} }, - { TK_IF, "if", 2, {} }, - { TK_IN, "in", 2, {} }, + { TK_TRY, "try", 3, { 0 } }, + { TK_FOR, "for", 3, { 0 } }, + { TK_LOCAL, "let", 3, { 0 } }, + { TK_IF, "if", 2, { 0 } }, + { TK_IN, "in", 2, { 0 } }, }; @@ -362,7 +362,7 @@ parse_comment(uc_lexer *lex, bool no_regexp) if (!buf_remaining(lex)) return emit_op(lex, lex->lastoff, TK_ERROR, ucv_string_new("Unterminated comment")); - if (!strcmp(tok->pat, "//")) { + if (!strcmp(tok->u.pat, "//")) { end = "\n"; elen = 1; } @@ -400,7 +400,7 @@ static uc_token * parse_string(uc_lexer *lex, bool no_regexp) { const struct token *tok = lex->tok; - char q = tok->pat[0]; + char q = tok->u.pat[0]; char *ptr, *c; uc_token *rv; int code; @@ -438,7 +438,7 @@ parse_string(uc_lexer *lex, bool no_regexp) default: lex->is_escape = false; - c = strchr("a\ab\be\ef\fn\nr\rt\tv\v", *ptr); + c = strchr("a\ab\be\033f\fn\nr\rt\tv\v", *ptr); if (c && *c >= 'a') { lookbehind_append(lex, c + 1, 1); @@ -725,7 +725,7 @@ parse_label(uc_lexer *lex, bool no_regexp) size_t i; if (!lex->lookbehind && tok->plen) - lookbehind_append(lex, tok->pat, tok->plen); + lookbehind_append(lex, tok->u.pat, tok->plen); if (!buf_remaining(lex) || (lex->bufstart[0] != '_' && !isalnum(lex->bufstart[0]))) { for (i = 0, word = &reserved_words[0]; i < ARRAY_SIZE(reserved_words); i++, word = &reserved_words[i]) { @@ -734,11 +734,11 @@ parse_label(uc_lexer *lex, bool no_regexp) switch (word->type) { case TK_DOUBLE: - rv = emit_op(lex, lex->source->off - word->plen, word->type, ucv_double_new(word->d)); + rv = emit_op(lex, lex->source->off - word->plen, word->type, ucv_double_new(word->u.d)); break; case TK_BOOL: - rv = emit_op(lex, lex->source->off - word->plen, word->type, ucv_boolean_new(word->b)); + rv = emit_op(lex, lex->source->off - word->plen, word->type, ucv_boolean_new(word->u.b)); break; default: @@ -803,7 +803,7 @@ parse_number(uc_lexer *lex, bool no_regexp) if (*e == '.' || *e == 'e' || *e == 'E') { d = strtod(lex->lookbehind, &e); - if (tok->pat[0] == '-') + if (tok->u.pat[0] == '-') d = -d; if (e > lex->lookbehind && *e == 0) @@ -812,7 +812,7 @@ parse_number(uc_lexer *lex, bool no_regexp) rv = emit_op(lex, lex->source->off - (lex->lookbehindlen - (e - lex->lookbehind) - 1), TK_ERROR, ucv_string_new("Invalid number literal")); } else if (*e == 0) { - if (tok->pat[0] == '-') + if (tok->u.pat[0] == '-') n = (errno == ERANGE) ? INT64_MIN : -n; rv = emit_op(lex, lex->source->off - (e - lex->lookbehind), TK_NUMBER, ucv_int64_new(n)); @@ -857,7 +857,8 @@ lex_step(uc_lexer *lex, FILE *fp, bool no_regexp) rem = lex->bufend - lex->bufstart; - memcpy(lex->buf, lex->bufstart, rem); + if (rem) + memcpy(lex->buf, lex->bufstart, rem); rlen = fread(lex->buf + rem, 1, lex->buflen - rem, fp); @@ -1042,8 +1043,8 @@ lex_step(uc_lexer *lex, FILE *fp, bool no_regexp) c = buf_remaining(lex) ? lex->bufstart[0] : 0; - if (tok->plen ? ((search.n & masks[tok->plen]) == tok->patn) - : (c >= tok->pat[0] && c <= tok->pat[1])) { + if (tok->plen ? ((search.n & masks[tok->plen]) == tok->u.patn) + : (c >= tok->u.pat[0] && c <= tok->u.pat[1])) { lex->lastoff = lex->source->off; /* token has a parse method, switch state */ @@ -1067,7 +1068,7 @@ lex_step(uc_lexer *lex, FILE *fp, bool no_regexp) else if ((lex->block == STATEMENTS && tok->type == TK_RSTM) || (lex->block == EXPRESSION && tok->type == TK_REXP)) { /* strip whitespace after block */ - if (tok->pat[0] == '-') + if (tok->u.pat[0] == '-') lex->modifier = MINUS; /* strip newline after statement block */ @@ -1207,7 +1208,7 @@ uc_get_tokenname(unsigned type) if (tokens[i].type != type) continue; - snprintf(buf, sizeof(buf), "'%s'", tokens[i].pat); + snprintf(buf, sizeof(buf), "'%s'", tokens[i].u.pat); return buf; } @@ -127,12 +127,6 @@ typedef struct { } uc_token; typedef struct { - bool lstrip_blocks; - bool trim_blocks; - bool strict_declarations; -} uc_parse_config; - -typedef struct { uc_lex_state_t state; uc_parse_config *config; uc_source *source; @@ -35,6 +35,7 @@ #include "compiler.h" #include "vm.h" #include "lib.h" +#include "source.h" static void format_context_line(uc_stringbuf_t *buf, const char *line, size_t off, bool compact) @@ -454,9 +455,11 @@ static uc_value_t * uc_delete(uc_vm *vm, size_t nargs) { uc_value_t *obj = uc_get_arg(0); + uc_value_t *key = NULL; uc_value_t *rv = NULL; - const char *key; + bool freeable; size_t i; + char *k; if (ucv_type(obj) != UC_OBJECT) return NULL; @@ -464,10 +467,14 @@ uc_delete(uc_vm *vm, size_t nargs) for (i = 1; i < nargs; i++) { ucv_put(rv); - key = ucv_string_get(uc_get_arg(i)); - rv = ucv_get(ucv_object_get(obj, key ? key : "null", NULL)); + key = uc_get_arg(i); + k = uc_cast_string(vm, &key, &freeable); + rv = ucv_get(ucv_object_get(obj, k, NULL)); + + ucv_object_delete(obj, k); - ucv_object_delete(obj, key ? key : "null"); + if (freeable) + free(k); } return rv; @@ -482,7 +489,7 @@ uc_die(uc_vm *vm, size_t nargs) s = msg ? uc_cast_string(vm, &msg, &freeable) : "Died"; - uc_vm_raise_exception(vm, EXCEPTION_USER, s); + uc_vm_raise_exception(vm, EXCEPTION_USER, "%s", s); if (freeable) free(s); @@ -494,13 +501,19 @@ static uc_value_t * uc_exists(uc_vm *vm, size_t nargs) { uc_value_t *obj = uc_get_arg(0); - const char *key = ucv_string_get(uc_get_arg(1)); - bool found; + uc_value_t *key = uc_get_arg(1); + bool found, freeable; + char *k; if (ucv_type(obj) != UC_OBJECT) return false; - ucv_object_get(obj, key ? key : "null", &found); + k = uc_cast_string(vm, &key, &freeable); + + ucv_object_get(obj, k, &found); + + if (freeable) + free(k); return ucv_boolean_new(found); } @@ -516,8 +529,9 @@ uc_exit(uc_vm *vm, size_t nargs) static uc_value_t * uc_getenv(uc_vm *vm, size_t nargs) { - const char *key = ucv_string_get(uc_get_arg(0)); - char *val = key ? getenv(key) : NULL; + uc_value_t *key = uc_get_arg(0); + char *k = ucv_string_get(key); + char *val = k ? getenv(k) : NULL; return val ? ucv_string_new(val) : NULL; } @@ -562,16 +576,18 @@ uc_filter(uc_vm *vm, size_t nargs) static uc_value_t * uc_hex(uc_vm *vm, size_t nargs) { - const char *val = ucv_string_get(uc_get_arg(0)); + uc_value_t *val = uc_get_arg(0); + char *e, *v; int64_t n; - char *e; - if (!val || !isxdigit(*val)) + v = ucv_string_get(val); + + if (!v || !isxdigit(*v)) return ucv_double_new(NAN); - n = strtoll(val, &e, 16); + n = strtoll(v, &e, 16); - if (e == val || *e) + if (e == v || *e) return ucv_double_new(NAN); return ucv_int64_new(n); @@ -622,8 +638,10 @@ uc_keys(uc_vm *vm, size_t nargs) arr = ucv_array_new(vm); - ucv_object_foreach(obj, key, val) + ucv_object_foreach(obj, key, val) { + (void)val; ucv_array_push(arr, ucv_string_new(key)); + } return arr; } @@ -1423,7 +1441,7 @@ uc_require_so(uc_vm *vm, const char *path, uc_value_t **res) return true; } - init = dlsym(dlh, "uc_module_entry"); + *(void **)(&init) = dlsym(dlh, "uc_module_entry"); if (!init) { uc_vm_raise_exception(vm, EXCEPTION_RUNTIME, @@ -255,7 +255,7 @@ uc_uci_get_any(uc_vm *vm, size_t nargs, bool all) uc_value_t *conf = uc_get_arg(0); uc_value_t *sect = uc_get_arg(1); uc_value_t *opt = uc_get_arg(2); - struct uci_ptr ptr = {}; + struct uci_ptr ptr = { 0 }; int rv; if (!c || !*c) @@ -330,7 +330,7 @@ uc_uci_get_first(uc_vm *vm, size_t nargs) struct uci_package *p = NULL; struct uci_section *sc; struct uci_element *e; - struct uci_ptr ptr = {}; + struct uci_ptr ptr = { 0 }; int rv; if (ucv_type(conf) != UC_STRING || @@ -465,7 +465,7 @@ uc_uci_set(uc_vm *vm, size_t nargs) uc_value_t *conf = uc_get_arg(0); uc_value_t *sect = uc_get_arg(1); uc_value_t *opt = NULL, *val = NULL; - struct uci_ptr ptr = {}; + struct uci_ptr ptr = { 0 }; bool is_list = false; size_t i; int rv; @@ -570,7 +570,7 @@ uc_uci_delete(uc_vm *vm, size_t nargs) uc_value_t *conf = uc_get_arg(0); uc_value_t *sect = uc_get_arg(1); uc_value_t *opt = uc_get_arg(2); - struct uci_ptr ptr = {}; + struct uci_ptr ptr = { 0 }; int rv; if (ucv_type(conf) != UC_STRING || @@ -605,7 +605,7 @@ uc_uci_rename(uc_vm *vm, size_t nargs) uc_value_t *conf = uc_get_arg(0); uc_value_t *sect = uc_get_arg(1); uc_value_t *opt = NULL, *val = NULL; - struct uci_ptr ptr = {}; + struct uci_ptr ptr = { 0 }; int rv; if (ucv_type(conf) != UC_STRING || @@ -665,7 +665,7 @@ uc_uci_reorder(uc_vm *vm, size_t nargs) uc_value_t *conf = uc_get_arg(0); uc_value_t *sect = uc_get_arg(1); uc_value_t *val = uc_get_arg(2); - struct uci_ptr ptr = {}; + struct uci_ptr ptr = { 0 }; int64_t n; int rv; @@ -705,7 +705,7 @@ uc_uci_pkg_command(uc_vm *vm, size_t nargs, enum pkg_cmd cmd) uc_value_t *conf = uc_get_arg(0); struct uci_element *e, *tmp; struct uci_package *p; - struct uci_ptr ptr = {}; + struct uci_ptr ptr = { 0 }; int rv, res = UCI_OK; if (cmd != CMD_REVERT && conf) @@ -98,7 +98,7 @@ parse(uc_parse_config *config, uc_source *src, { uc_value_t *globals = NULL; uc_function_t *entry; - uc_vm vm = {}; + uc_vm vm = { 0 }; int c, c2, rc = 0; char *err; @@ -285,7 +285,12 @@ main(int argc, char **argv) if (source) fprintf(stderr, "Options -i and -s are exclusive\n"); - source = uc_source_new_buffer("[-s argument]", xstrdup(optarg), strlen(optarg)); + c = xstrdup(optarg); + source = uc_source_new_buffer("[-s argument]", c, strlen(c)); + + if (!source) + free(c); + break; case 'S': @@ -22,17 +22,9 @@ #include <stdio.h> #include "util.h" +#include "types.h" -uc_declare_vector(uc_lineinfo, uint8_t); - -typedef struct { - char *filename, *buffer; - FILE *fp; - size_t usecount, off; - uc_lineinfo lineinfo; -} uc_source; - uc_source *uc_source_new_file(const char *path); uc_source *uc_source_new_buffer(const char *name, char *buf, size_t len); diff --git a/tests/cram/test_basic.t b/tests/cram/test_basic.t index 982d58a..3d4cd9e 100644 --- a/tests/cram/test_basic.t +++ b/tests/cram/test_basic.t @@ -35,7 +35,7 @@ check that ucode provides proper error messages: One of -i or -s is required [1] - $ ucode -m foo -s '' + $ ucode -m foo -s ' ' Runtime error: No module named 'foo' could be found At start of program @@ -53,6 +53,7 @@ check that ucode can load fs module: One of -i or -s is required [1] - $ ucode -m fs -s '' + $ ucode -m fs -s ' ' + (no-eol) $ touch moo; ucode -m fs -i moo @@ -927,7 +927,7 @@ ucv_closure_new(uc_vm *vm, uc_function_t *function, bool arrow_fn) closure->header.refcount = 1; closure->function = function; closure->is_arrow = arrow_fn; - closure->upvals = function->nupvals ? ((void *)closure + ALIGN(sizeof(*closure))) : NULL; + closure->upvals = function->nupvals ? (uc_upvalref_t **)((uintptr_t)closure + ALIGN(sizeof(*closure))) : NULL; if (vm) ucv_ref(&vm->values, &closure->ref); @@ -1590,8 +1590,8 @@ ucv_to_stringbuf(uc_vm *vm, uc_stringbuf_t *pb, uc_value_t *uv, bool json) ucv_stringbuf_printf(pb, "%sfunction%s%s(...) { [native code] }%s", json ? "\"" : "", - cfunction->name ? " " : "", - cfunction->name ? cfunction->name : "", + cfunction->name[0] ? " " : "", + cfunction->name[0] ? cfunction->name : "", json ? "\"" : ""); break; @@ -1739,6 +1739,7 @@ ucv_equal(uc_value_t *uv1, uc_value_t *uv2) } ucv_object_foreach(uv2, key2, val2) { + (void)val2; ucv_object_get(uv1, key2, &b1); if (!b1) @@ -1772,7 +1773,7 @@ ucv_gc(uc_vm *vm, bool final) /* unref unreachable objects */ for (ref = vm->values.next; ref != &vm->values; ref = ref->next) { - val = (void *)ref - offsetof(uc_array_t, ref); + val = (uc_value_t *)((uintptr_t)ref - offsetof(uc_array_t, ref)); if (ucv_is_marked(val)) ucv_clear_mark(val); @@ -1782,7 +1783,7 @@ ucv_gc(uc_vm *vm, bool final) /* free destroyed objects */ for (ref = vm->values.next, tmp = ref->next; ref != &vm->values; ref = tmp, tmp = tmp->next) { - val = (void *)ref - offsetof(uc_array_t, ref); + val = (uc_value_t *)((uintptr_t)ref - offsetof(uc_array_t, ref)); if (val->type == UC_NULL) { ucv_unref(ref); @@ -22,8 +22,10 @@ #include <regex.h> #include <json-c/json.h> -#include "source.h" -#include "chunk.h" +#include "util.h" + + +/* Value types and generic value header */ typedef enum uc_type_t { UC_NULL, @@ -48,6 +50,58 @@ typedef struct uc_value_t { uint32_t refcount:26; } uc_value_t; + +/* Constant list defintions */ + +typedef struct { + size_t isize; + size_t dsize; + uint64_t *index; + char *data; +} uc_value_list; + + +/* Source buffer defintions */ + +uc_declare_vector(uc_lineinfo, uint8_t); + +typedef struct { + char *filename, *buffer; + FILE *fp; + size_t usecount, off; + uc_lineinfo lineinfo; +} uc_source; + + +/* Bytecode chunk defintions */ + +typedef struct { + size_t from, to, target, slot; +} uc_ehrange; + +typedef struct { + size_t from, to, slot, nameidx; +} uc_varrange; + +uc_declare_vector(uc_ehranges, uc_ehrange); +uc_declare_vector(uc_variables, uc_varrange); +uc_declare_vector(uc_offsetinfo, uint8_t); + +typedef struct { + size_t count; + uint8_t *entries; + uc_value_list constants; + uc_ehranges ehranges; + struct { + uc_variables variables; + uc_value_list varnames; + uc_offsetinfo offsets; + } debuginfo; +} uc_chunk; + + +/* Value type structures */ + typedef struct uc_weakref_t { struct uc_weakref_t *prev; struct uc_weakref_t *next; @@ -144,6 +198,69 @@ typedef struct { uc_declare_vector(uc_ressource_types_t, uc_ressource_type_t); + +/* Parser definitions */ + +typedef struct { + bool lstrip_blocks; + bool trim_blocks; + bool strict_declarations; +} uc_parse_config; + + +/* VM definitions */ + +typedef enum { + EXCEPTION_NONE, + EXCEPTION_SYNTAX, + EXCEPTION_RUNTIME, + EXCEPTION_TYPE, + EXCEPTION_REFERENCE, + EXCEPTION_USER +} uc_exception_type_t; + +typedef struct { + uc_exception_type_t type; + uc_value_t *stacktrace; + char *message; +} uc_exception; + +typedef struct { + uint8_t *ip; + uc_closure_t *closure; + uc_cfunction_t *cfunction; + size_t stackframe; + uc_value_t *ctx; + bool mcall; +} uc_callframe; + +uc_declare_vector(uc_callframes, uc_callframe); +uc_declare_vector(uc_stack, uc_value_t *); + +struct uc_vm { + uc_stack stack; + uc_exception exception; + uc_callframes callframes; + uc_upvalref_t *open_upvals; + uc_parse_config *config; + uc_value_t *globals; + uc_source *sources; + uc_weakref_t values; + union { + uint32_t u32; + int32_t s32; + uint16_t u16; + int16_t s16; + uint8_t u8; + int8_t s8; + } arg; + size_t spread_values; + uint8_t trace; +}; + + +/* Value API */ + typedef struct printbuf uc_stringbuf_t; void ucv_free(uc_value_t *, bool); @@ -162,7 +279,7 @@ uc_value_t *ucv_string_new_length(const char *, size_t); size_t ucv_string_length(uc_value_t *); char *_ucv_string_get(uc_value_t **); -#define ucv_string_get(uv) ({ uc_value_t * volatile p = (uv); _ucv_string_get((uc_value_t **)&p); }) +#define ucv_string_get(uv) _ucv_string_get((uc_value_t **)&uv) uc_stringbuf_t *ucv_stringbuf_new(void); uc_value_t *ucv_stringbuf_finish(uc_stringbuf_t *); @@ -200,16 +317,17 @@ bool ucv_object_add(uc_value_t *, const char *, uc_value_t *); bool ucv_object_delete(uc_value_t *, const char *); size_t ucv_object_length(uc_value_t *); -#define ucv_object_foreach(obj, key, val) \ - char *key; \ - uc_value_t *val __attribute__((__unused__)); \ - for (struct lh_entry *entry ## key = (ucv_type(obj) == UC_OBJECT) ? ((uc_object_t *)obj)->table->head : NULL, *entry_next ## key = NULL; \ - ({ if (entry ## key) { \ - key = (char *)entry ## key->k; \ - val = (uc_value_t *)entry ## key->v; \ - entry_next ## key = entry ## key->next; \ - } ; entry ## key; }); \ - entry ## key = entry_next ## key) +#define ucv_object_foreach(obj, key, val) \ + char *key = NULL; \ + uc_value_t *val = NULL; \ + struct lh_entry *entry##key; \ + struct lh_entry *entry_next##key = NULL; \ + for (entry##key = (ucv_type(obj) == UC_OBJECT) ? ((uc_object_t *)obj)->table->head : NULL; \ + (entry##key ? (key = (char *)lh_entry_k(entry##key), \ + val = (uc_value_t *)lh_entry_v(entry##key), \ + entry_next##key = entry##key->next, entry##key) \ + : 0); \ + entry##key = entry_next##key) uc_value_t *ucv_function_new(const char *, size_t, uc_source *); size_t ucv_function_srcpos(uc_value_t *, size_t); @@ -218,6 +218,7 @@ static inline struct json_tokener *xjs_new_tokener(void) { return tok; } +__attribute__((format(printf, 2, 0))) static inline int xasprintf(char **strp, const char *fmt, ...) { va_list ap; int len; @@ -234,6 +235,7 @@ static inline int xasprintf(char **strp, const char *fmt, ...) { return len; } +__attribute__((format(printf, 2, 0))) static inline int xvasprintf(char **strp, const char *fmt, va_list ap) { int len = vasprintf(strp, fmt, ap); @@ -260,7 +260,7 @@ uc_cmp(int how, uc_value_t *v1, uc_value_t *v2) } else { if (t1 == t2 && !ucv_is_scalar(v1)) { - delta = (void *)v1 - (void *)v2; + delta = (intptr_t)v1 - (intptr_t)v2; } else { t1 = uc_cast_number(v1, &n1, &d1); @@ -29,6 +29,8 @@ #include <stdio.h> +#include "types.h" + typedef enum { TAG_INVAL = 0, TAG_NUM = 1, @@ -39,24 +41,11 @@ typedef enum { TAG_PTR = 6 } uc_value_type_t; -typedef struct { - size_t isize; - size_t dsize; - uint64_t *index; - char *data; -} uc_value_list; - -typedef struct uc_value_t uc_value_t; - bool uc_cmp(int how, uc_value_t *v1, uc_value_t *v2); bool uc_val_is_truish(uc_value_t *val); -typedef enum uc_type_t uc_type_t; -typedef struct uc_value_t uc_value_t; uc_type_t uc_cast_number(uc_value_t *v, int64_t *n, double *d); -typedef struct uc_vm uc_vm; - uc_value_t *uc_getval(uc_vm *, uc_value_t *scope, uc_value_t *key); uc_value_t *uc_setval(uc_vm *, uc_value_t *scope, uc_value_t *key, uc_value_t *val); @@ -232,9 +232,9 @@ uc_vm_decode_insn(uc_vm *vm, uc_callframe *frame, uc_chunk *chunk) case -4: vm->arg.s32 = ( - frame->ip[0] * 0x1000000 + - frame->ip[1] * 0x10000 + - frame->ip[2] * 0x100 + + frame->ip[0] * 0x1000000UL + + frame->ip[1] * 0x10000UL + + frame->ip[2] * 0x100UL + frame->ip[3] ) - 0x7fffffff; frame->ip += 4; @@ -247,9 +247,9 @@ uc_vm_decode_insn(uc_vm *vm, uc_callframe *frame, uc_chunk *chunk) case 4: vm->arg.u32 = ( - frame->ip[0] * 0x1000000 + - frame->ip[1] * 0x10000 + - frame->ip[2] * 0x100 + + frame->ip[0] * 0x1000000UL + + frame->ip[1] * 0x10000UL + + frame->ip[2] * 0x100UL + frame->ip[3] ); frame->ip += 4; @@ -307,7 +307,7 @@ uc_vm_frame_dump(uc_vm *vm, uc_callframe *frame) ref = closure->upvals[i]; v = uc_chunk_debug_get_variable(chunk, 0, i, true); s = ucv_to_string(NULL, v); - fprintf(stderr, " [%zu] <%p> %s ", i, ref, s); + fprintf(stderr, " [%zu] <%p> %s ", i, (void *)ref, s); free(s); if (ref->closed) { @@ -588,13 +588,13 @@ uc_dump_insn(uc_vm *vm, uint8_t *pos, enum insn_type insn) case -2: fprintf(stderr, " {%c0x%hx}", vm->arg.s16 < 0 ? '-' : '+', - vm->arg.s16 < 0 ? -(unsigned)vm->arg.s16 : (unsigned)vm->arg.s16); + (uint16_t)(vm->arg.s16 < 0 ? -vm->arg.s16 : vm->arg.s16)); break; case -4: fprintf(stderr, " {%c0x%x}", vm->arg.s32 < 0 ? '-' : '+', - vm->arg.s32 < 0 ? -(unsigned)vm->arg.s32 : (unsigned)vm->arg.s32); + (uint32_t)(vm->arg.s32 < 0 ? -vm->arg.s32 : vm->arg.s32)); break; case 1: @@ -1035,7 +1035,7 @@ uc_vm_capture_upval(uc_vm *vm, size_t slot) if (curr && curr->slot == slot) { if (vm->trace) { s = ucv_to_string(NULL, vm->stack.entries[slot]); - fprintf(stderr, " {+%zu} <%p> %s\n", slot, curr, s); + fprintf(stderr, " {+%zu} <%p> %s\n", slot, (void *)curr, s); free(s); } @@ -1047,7 +1047,7 @@ uc_vm_capture_upval(uc_vm *vm, size_t slot) if (vm->trace) { s = ucv_to_string(NULL, vm->stack.entries[slot]); - fprintf(stderr, " {*%zu} <%p> %s\n", slot, created, s); + fprintf(stderr, " {*%zu} <%p> %s\n", slot, (void *)created, s); free(s); } @@ -1072,7 +1072,7 @@ uc_vm_close_upvals(uc_vm *vm, size_t slot) if (vm->trace) { s = ucv_to_string(NULL, ref->value); - fprintf(stderr, " {!%zu} <%p> %s\n", ref->slot, ref, s); + fprintf(stderr, " {!%zu} <%p> %s\n", ref->slot, (void *)ref, s); free(s); } @@ -1528,11 +1528,13 @@ static void uc_vm_insn_sobj(uc_vm *vm, enum insn_type insn) { uc_value_t *obj = uc_vm_stack_peek(vm, vm->arg.u32); + uc_value_t *val; size_t idx; for (idx = 0; idx < vm->arg.u32; idx += 2) { + val = uc_vm_stack_peek(vm, vm->arg.u32 - idx - 1); ucv_object_add(obj, - ucv_string_get(uc_vm_stack_peek(vm, vm->arg.u32 - idx - 1)), + ucv_string_get(val), ucv_get(uc_vm_stack_peek(vm, vm->arg.u32 - idx - 2))); } @@ -1972,6 +1974,8 @@ uc_vm_callframe_pop(uc_vm *vm) static void uc_vm_output_exception(uc_vm *vm) { + uc_value_t *ctx; + if (vm->exception.type == EXCEPTION_USER) fprintf(stderr, "%s\n", vm->exception.message); else @@ -1979,10 +1983,9 @@ uc_vm_output_exception(uc_vm *vm) exception_type_strings[vm->exception.type] ? exception_type_strings[vm->exception.type] : "Error", vm->exception.message); - fprintf(stderr, "%s\n\n", - ucv_string_get( - ucv_object_get( - ucv_array_get(vm->exception.stacktrace, 0), "context", NULL))); + ctx = ucv_object_get(ucv_array_get(vm->exception.stacktrace, 0), "context", NULL); + + fprintf(stderr, "%s\n\n", ucv_string_get(ctx)); } static uc_vm_status_t @@ -23,6 +23,7 @@ #include "chunk.h" #include "util.h" #include "lexer.h" +#include "types.h" #define __insns \ __insn(NOOP) \ @@ -104,54 +105,6 @@ typedef struct { } uc_insn_definition; typedef enum { - EXCEPTION_NONE, - EXCEPTION_SYNTAX, - EXCEPTION_RUNTIME, - EXCEPTION_TYPE, - EXCEPTION_REFERENCE, - EXCEPTION_USER -} uc_exception_type_t; - -typedef struct { - uc_exception_type_t type; - uc_value_t *stacktrace; - char *message; -} uc_exception; - -typedef struct { - uint8_t *ip; - uc_closure_t *closure; - uc_cfunction_t *cfunction; - size_t stackframe; - uc_value_t *ctx; - bool mcall; -} uc_callframe; - -uc_declare_vector(uc_callframes, uc_callframe); -uc_declare_vector(uc_stack, uc_value_t *); - -typedef struct uc_vm { - uc_stack stack; - uc_exception exception; - uc_callframes callframes; - uc_upvalref_t *open_upvals; - uc_parse_config *config; - uc_value_t *globals; - uc_source *sources; - uc_weakref_t values; - union { - uint32_t u32; - int32_t s32; - uint16_t u16; - int16_t s16; - uint8_t u8; - int8_t s8; - } arg; - size_t spread_values; - uint8_t trace; -} uc_vm; - -typedef enum { STATUS_OK, ERROR_COMPILE, ERROR_RUNTIME |