diff options
author | Jo-Philipp Wich <jo@mein.io> | 2021-04-21 15:07:16 +0200 |
---|---|---|
committer | Jo-Philipp Wich <jo@mein.io> | 2021-04-25 20:48:40 +0200 |
commit | 35af4ba4fc21a4b2357c50e6b02a2e3e4b236e88 (patch) | |
tree | 445f9fdf2e96e490cd681dca36d5cc9912474ed3 | |
parent | f2c4b79feaffd7b2fdb4041f47c9cd0f4cc3bc6e (diff) |
treewide: rework internal data type system
Instead of relying on json_object values internally, use custom types to
represent the different ucode value types which brings a number of
advantages compared to the previous approach:
- Due to the use of tagged pointers, small integer, string and bool
values can be stored directly in the pointer addresses, vastly
reducing required heap memory
- Ability to create circular data structures such as
`let o; o = { test: o };`
- Ability to register custom `tostring()` function through prototypes
- Initial mark/sweep GC implementation to tear down circular object
graphs on VM deinit
The change also paves the way for possible future extensions such as
constant variables and meta methods for custom ressource types.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
-rw-r--r-- | CMakeLists.txt | 5 | ||||
-rw-r--r-- | chunk.c | 11 | ||||
-rw-r--r-- | chunk.h | 10 | ||||
-rw-r--r-- | compiler.c | 261 | ||||
-rw-r--r-- | compiler.h | 12 | ||||
-rw-r--r-- | lexer.c | 55 | ||||
-rw-r--r-- | lexer.h | 5 | ||||
-rw-r--r-- | lib.c | 1427 | ||||
-rw-r--r-- | lib.h | 151 | ||||
-rw-r--r-- | lib/fs.c | 312 | ||||
-rw-r--r-- | lib/math.c | 66 | ||||
-rw-r--r-- | lib/ubus.c | 127 | ||||
-rw-r--r-- | lib/uci.c | 431 | ||||
-rw-r--r-- | main.c | 77 | ||||
-rw-r--r-- | module.h | 15 | ||||
-rw-r--r-- | object.c | 493 | ||||
-rw-r--r-- | object.h | 201 | ||||
-rw-r--r-- | tests/custom/00_syntax/21_regex_literals | 2 | ||||
-rw-r--r-- | types.c | 1755 | ||||
-rw-r--r-- | types.h | 310 | ||||
-rw-r--r-- | util.h | 11 | ||||
-rw-r--r-- | value.c | 345 | ||||
-rw-r--r-- | value.h | 35 | ||||
-rw-r--r-- | vm.c | 1039 | ||||
-rw-r--r-- | vm.h | 25 |
25 files changed, 4174 insertions, 3007 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 88ee376..52d6262 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -38,8 +38,9 @@ IF(JSONC_FOUND) INCLUDE_DIRECTORIES(${JSONC_INCLUDE_DIRS}) ENDIF() -SET(UCODE_SOURCES main.c lexer.c lib.c vm.c chunk.c value.c object.c compiler.c source.c) +SET(UCODE_SOURCES main.c lexer.c lib.c vm.c chunk.c value.c compiler.c source.c types.c) ADD_EXECUTABLE(ucode ${UCODE_SOURCES}) +SET_PROPERTY(TARGET ucode PROPERTY ENABLE_EXPORTS 1) TARGET_LINK_LIBRARIES(ucode ${json}) CHECK_FUNCTION_EXISTS(dlopen DLOPEN_FUNCTION_EXISTS) @@ -113,4 +114,4 @@ IF(UNIT_TESTING) ENDIF() INSTALL(TARGETS ucode RUNTIME DESTINATION bin) -INSTALL(TARGETS ${LIBRARIES} LIBRARY DESTINATION ucode) +INSTALL(TARGETS ${LIBRARIES} LIBRARY DESTINATION lib/ucode) @@ -17,6 +17,7 @@ #include <assert.h> #include "chunk.h" +#include "types.h" #include "util.h" #define OFFSETINFO_BITS (sizeof(((uc_offsetinfo *)NULL)->entries[0]) * 8) @@ -135,14 +136,14 @@ uc_chunk_pop(uc_chunk *chunk) } } -struct json_object * +uc_value_t * uc_chunk_get_constant(uc_chunk *chunk, size_t idx) { return uc_vallist_get(&chunk->constants, idx); } ssize_t -uc_chunk_add_constant(uc_chunk *chunk, struct json_object *val) +uc_chunk_add_constant(uc_chunk *chunk, uc_value_t *val) { return uc_vallist_add(&chunk->constants, val); } @@ -165,7 +166,7 @@ uc_chunk_debug_get_srcpos(uc_chunk *chunk, size_t off) } void -uc_chunk_debug_add_variable(uc_chunk *chunk, size_t from, size_t to, size_t slot, bool upval, json_object *name) +uc_chunk_debug_add_variable(uc_chunk *chunk, size_t from, size_t to, size_t slot, bool upval, uc_value_t *name) { uc_variables *variables = &chunk->debuginfo.variables; uc_value_list *varnames = &chunk->debuginfo.varnames; @@ -185,12 +186,12 @@ uc_chunk_debug_add_variable(uc_chunk *chunk, size_t from, size_t to, size_t slot variables->count++; } -json_object * +uc_value_t * uc_chunk_debug_get_variable(uc_chunk *chunk, size_t off, size_t slot, bool upval) { uc_variables *variables = &chunk->debuginfo.variables; uc_value_list *varnames = &chunk->debuginfo.varnames; - json_object *name = NULL; + uc_value_t *name = NULL; size_t i; assert(slot <= ((size_t)-1 / 2)); @@ -52,12 +52,14 @@ 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); -ssize_t uc_chunk_add_constant(uc_chunk *chunk, struct json_object *value); -struct json_object *uc_chunk_get_constant(uc_chunk *chunk, size_t idx); +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); size_t uc_chunk_debug_get_srcpos(uc_chunk *chunk, size_t off); -void uc_chunk_debug_add_variable(uc_chunk *chunk, size_t from, size_t to, size_t slot, bool upval, json_object *name); -json_object *uc_chunk_debug_get_variable(uc_chunk *chunk, size_t off, size_t slot, bool upval); +void uc_chunk_debug_add_variable(uc_chunk *chunk, size_t from, size_t to, size_t slot, bool upval, uc_value_t *name); +uc_value_t *uc_chunk_debug_get_variable(uc_chunk *chunk, size_t off, size_t slot, bool upval); #endif /* __CHUNK_H_ */ @@ -88,7 +88,7 @@ uc_compiler_parse_rules[TK_ERROR + 1] = { }; static ssize_t -uc_compiler_declare_local(uc_compiler *compiler, json_object *name); +uc_compiler_declare_local(uc_compiler *compiler, uc_value_t *name); static ssize_t uc_compiler_initialize_local(uc_compiler *compiler); @@ -96,11 +96,11 @@ uc_compiler_initialize_local(uc_compiler *compiler); static void uc_compiler_init(uc_compiler *compiler, const char *name, size_t srcpos, uc_source *source) { - json_object *varname = xjs_new_string("(callee)"); + uc_value_t *varname = ucv_string_new("(callee)"); compiler->scope_depth = 0; - compiler->function = uc_function_new(name, srcpos, source); + compiler->function = ucv_function_new(name, srcpos, source); compiler->locals.count = 0; compiler->locals.entries = NULL; @@ -117,69 +117,65 @@ uc_compiler_init(uc_compiler *compiler, const char *name, size_t srcpos, uc_sour /* reserve stack slot 0 */ uc_compiler_declare_local(compiler, varname); uc_compiler_initialize_local(compiler); - uc_value_put(varname); + ucv_put(varname); } static uc_chunk * uc_compiler_current_chunk(uc_compiler *compiler) { - return &compiler->function->chunk; + uc_function_t *fn = (uc_function_t *)compiler->function; + + return &fn->chunk; +} + +static uc_source * +uc_compiler_current_source(uc_compiler *compiler) +{ + uc_function_t *fn = (uc_function_t *)compiler->function; + + return fn->source; } __attribute__((format(printf, 3, 0))) static void uc_compiler_syntax_error(uc_compiler *compiler, size_t off, const char *fmt, ...) { + uc_stringbuf_t *buf = compiler->parser->error; size_t line = 0, byte = 0, len = 0; - char *context = NULL; - char *s, *tmp; va_list ap; + char *s; if (compiler->parser->synchronizing) return; compiler->parser->synchronizing = true; + if (!buf) + buf = compiler->parser->error = xprintbuf_new(); + if (!off) - off = uc_function_get_srcpos(compiler->function, + off = ucv_function_srcpos(compiler->function, uc_compiler_current_chunk(compiler)->count); if (off) { byte = off; - line = uc_source_get_line(compiler->function->source, &byte); - - format_error_context(&context, &len, compiler->function->source, NULL, off); + line = uc_source_get_line(uc_compiler_current_source(compiler), &byte); } va_start(ap, fmt); - xvasprintf(&s, fmt, ap); + len = xvasprintf(&s, fmt, ap); va_end(ap); - xasprintf(&tmp, "Syntax error: %s\n", s); - free(s); - s = tmp; + ucv_stringbuf_append(buf, "Syntax error: "); + ucv_stringbuf_addstr(buf, s, len); + ucv_stringbuf_append(buf, "\n"); - if (line) { - xasprintf(&tmp, "%sIn line %zu, byte %zu:\n", s, line, byte); - free(s); - s = tmp; - } + free(s); - if (context) { - xasprintf(&tmp, "%s%s\n\n", s, context); - free(context); - free(s); - s = tmp; - } + if (line) + ucv_stringbuf_printf(buf, "In line %zu, byte %zu:\n", line, byte); - if (compiler->parser->error) { - xasprintf(&tmp, "%s%s", compiler->parser->error, s); - free(compiler->parser->error); - free(s); - compiler->parser->error = tmp; - } - else { - compiler->parser->error = s; - } + if (format_error_context(buf, uc_compiler_current_source(compiler), NULL, off)) + ucv_stringbuf_append(buf, "\n\n"); } static size_t @@ -201,7 +197,7 @@ uc_compiler_parse_advance(uc_compiler *compiler) { bool no_regexp; - uc_value_put(compiler->parser->prev.val); + ucv_put(compiler->parser->prev.uv); compiler->parser->prev = compiler->parser->curr; while (true) { @@ -262,10 +258,10 @@ uc_compiler_parse_advance(uc_compiler *compiler) break; uc_compiler_syntax_error(compiler, compiler->parser->curr.pos, "%s", - json_object_get_string(compiler->parser->curr.val)); + ucv_string_get(compiler->parser->curr.uv)); - uc_value_put(compiler->parser->curr.val); - compiler->parser->curr.val = NULL; + ucv_put(compiler->parser->curr.uv); + compiler->parser->curr.uv = NULL; } } @@ -505,7 +501,7 @@ uc_compiler_set_u32(uc_compiler *compiler, size_t off, uint32_t n) } static size_t -uc_compiler_emit_constant(uc_compiler *compiler, size_t srcpos, json_object *val) +uc_compiler_emit_constant(uc_compiler *compiler, size_t srcpos, uc_value_t *val) { uc_chunk *chunk = uc_compiler_current_chunk(compiler); size_t cidx = uc_chunk_add_constant(chunk, val); @@ -517,7 +513,7 @@ uc_compiler_emit_constant(uc_compiler *compiler, size_t srcpos, json_object *val } static size_t -uc_compiler_emit_regexp(uc_compiler *compiler, size_t srcpos, json_object *val) +uc_compiler_emit_regexp(uc_compiler *compiler, size_t srcpos, uc_value_t *val) { uc_chunk *chunk = uc_compiler_current_chunk(compiler); size_t cidx = uc_chunk_add_constant(chunk, val); @@ -581,7 +577,7 @@ uc_compiler_set_jmpaddr(uc_compiler *compiler, size_t off, uint32_t dest) chunk->entries[off + 4] = addr % 0x100; } -static uc_function * +static uc_function_t * uc_compiler_finish(uc_compiler *compiler) { uc_chunk *chunk = uc_compiler_current_chunk(compiler); @@ -600,7 +596,7 @@ uc_compiler_finish(uc_compiler *compiler) false, locals->entries[i].name); - uc_value_put(locals->entries[i].name); + ucv_put(locals->entries[i].name); } for (i = 0; i < upvals->count; i++) { @@ -611,19 +607,19 @@ uc_compiler_finish(uc_compiler *compiler) true, upvals->entries[i].name); - uc_value_put(upvals->entries[i].name); + ucv_put(upvals->entries[i].name); } uc_vector_clear(locals); uc_vector_clear(upvals); if (compiler->parser->error) { - uc_value_put(compiler->function->header.jso); + ucv_put(compiler->function); return NULL; } - return compiler->function; + return (uc_function_t *)compiler->function; } static void @@ -640,7 +636,7 @@ uc_compiler_leave_scope(uc_compiler *compiler) compiler->scope_depth--; - while (locals->count > 0 && locals->entries[locals->count - 1].depth > compiler->scope_depth) { + while (locals->count > 0 && locals->entries[locals->count - 1].depth > (ssize_t)compiler->scope_depth) { locals->count--; uc_chunk_debug_add_variable(chunk, @@ -650,7 +646,7 @@ uc_compiler_leave_scope(uc_compiler *compiler) false, locals->entries[locals->count].name); - uc_value_put(locals->entries[locals->count].name); + ucv_put(locals->entries[locals->count].name); locals->entries[locals->count].name = NULL; uc_compiler_emit_insn(compiler, 0, @@ -659,7 +655,7 @@ uc_compiler_leave_scope(uc_compiler *compiler) } static ssize_t -uc_compiler_declare_local(uc_compiler *compiler, json_object *name) +uc_compiler_declare_local(uc_compiler *compiler, uc_value_t *name) { uc_chunk *chunk = uc_compiler_current_chunk(compiler); uc_locals *locals = &compiler->locals; @@ -675,15 +671,15 @@ uc_compiler_declare_local(uc_compiler *compiler, json_object *name) return -1; } - str1 = json_object_get_string(name); - len1 = json_object_get_string_len(name); + str1 = ucv_string_get(name); + len1 = ucv_string_length(name); for (i = locals->count; i > 0; i--) { - if (locals->entries[i - 1].depth != -1 && locals->entries[i - 1].depth < compiler->scope_depth) + if (locals->entries[i - 1].depth != -1 && locals->entries[i - 1].depth < (ssize_t)compiler->scope_depth) break; - str2 = json_object_get_string(locals->entries[i - 1].name); - len2 = json_object_get_string_len(locals->entries[i - 1].name); + str2 = ucv_string_get(locals->entries[i - 1].name); + len2 = ucv_string_length(locals->entries[i - 1].name); if (len1 == len2 && !strcmp(str1, str2)) { if (compiler->parser->config && @@ -699,7 +695,7 @@ uc_compiler_declare_local(uc_compiler *compiler, json_object *name) uc_vector_grow(locals); - locals->entries[locals->count].name = uc_value_get(name); + locals->entries[locals->count].name = ucv_get(name); locals->entries[locals->count].depth = -1; locals->entries[locals->count].captured = false; locals->entries[locals->count].from = chunk->count; @@ -719,18 +715,18 @@ uc_compiler_initialize_local(uc_compiler *compiler) } static ssize_t -uc_compiler_resolve_local(uc_compiler *compiler, json_object *name) +uc_compiler_resolve_local(uc_compiler *compiler, uc_value_t *name) { uc_locals *locals = &compiler->locals; const char *str1, *str2; size_t i, len1, len2; - str1 = json_object_get_string(name); - len1 = json_object_get_string_len(name); + str1 = ucv_string_get(name); + len1 = ucv_string_length(name); for (i = locals->count; i > 0; i--) { - str2 = json_object_get_string(locals->entries[i - 1].name); - len2 = json_object_get_string_len(locals->entries[i - 1].name); + str2 = ucv_string_get(locals->entries[i - 1].name); + len2 = ucv_string_length(locals->entries[i - 1].name); if (len1 != len2 || strcmp(str1, str2)) continue; @@ -749,9 +745,9 @@ uc_compiler_resolve_local(uc_compiler *compiler, json_object *name) } static ssize_t -uc_compiler_add_upval(uc_compiler *compiler, ssize_t idx, bool local, json_object *name) +uc_compiler_add_upval(uc_compiler *compiler, size_t idx, bool local, uc_value_t *name) { - uc_function *function = compiler->function; + uc_function_t *function = (uc_function_t *)compiler->function; uc_upvals *upvals = &compiler->upvals; uc_upval *uv; size_t i; @@ -771,7 +767,7 @@ uc_compiler_add_upval(uc_compiler *compiler, ssize_t idx, bool local, json_objec upvals->entries[upvals->count].local = local; upvals->entries[upvals->count].index = idx; - upvals->entries[upvals->count].name = uc_value_get(name); + upvals->entries[upvals->count].name = ucv_get(name); function->nupvals++; @@ -779,7 +775,7 @@ uc_compiler_add_upval(uc_compiler *compiler, ssize_t idx, bool local, json_objec } static ssize_t -uc_compiler_resolve_upval(uc_compiler *compiler, json_object *name) +uc_compiler_resolve_upval(uc_compiler *compiler, uc_value_t *name) { ssize_t idx; @@ -989,7 +985,7 @@ uc_compiler_compile_binary(uc_compiler *compiler, bool assignable) } static enum insn_type -uc_compiler_emit_variable_rw(uc_compiler *compiler, json_object *varname, uc_tokentype_t type) +uc_compiler_emit_variable_rw(uc_compiler *compiler, uc_value_t *varname, uc_tokentype_t type) { enum insn_type insn; uint32_t sub_insn; @@ -1050,7 +1046,7 @@ uc_compiler_compile_expression(uc_compiler *compiler) } static bool -uc_compiler_compile_assignment(uc_compiler *compiler, json_object *var) +uc_compiler_compile_assignment(uc_compiler *compiler, uc_value_t *var) { uc_tokentype_t type = compiler->parser->curr.type; @@ -1066,12 +1062,12 @@ uc_compiler_compile_assignment(uc_compiler *compiler, json_object *var) } static bool -uc_compiler_compile_arrowfn(uc_compiler *compiler, json_object *args, bool restarg) +uc_compiler_compile_arrowfn(uc_compiler *compiler, uc_value_t *args, bool restarg) { - bool array = json_object_is_type(args, json_type_array); + bool array = (ucv_type(args) == UC_ARRAY); uc_compiler fncompiler = {}; size_t i, pos, load_off; - uc_function *fn; + uc_function_t *fn; ssize_t slot; if (!uc_compiler_parse_match(compiler, TK_ARROW)) @@ -1080,21 +1076,22 @@ uc_compiler_compile_arrowfn(uc_compiler *compiler, json_object *args, bool resta pos = compiler->parser->prev.pos; uc_compiler_init(&fncompiler, NULL, compiler->parser->prev.pos, - compiler->function->source); + uc_compiler_current_source(compiler)); fncompiler.parent = compiler; fncompiler.parser = compiler->parser; - fncompiler.function->arrow = true; - fncompiler.function->vararg = args ? restarg : false; - fncompiler.function->nargs = array ? json_object_array_length(args) : !!args; + fn = (uc_function_t *)fncompiler.function; + fn->arrow = true; + fn->vararg = args ? restarg : false; + fn->nargs = array ? ucv_array_length(args) : !!args; uc_compiler_enter_scope(&fncompiler); /* declare local variables for arguments */ - for (i = 0; i < fncompiler.function->nargs; i++) { + for (i = 0; i < fn->nargs; i++) { slot = uc_compiler_declare_local(&fncompiler, - array ? json_object_array_get_idx(args, i) : args); + array ? ucv_array_get(args, i) : args); if (slot != -1) uc_compiler_syntax_error(&fncompiler, pos, @@ -1112,8 +1109,8 @@ uc_compiler_compile_arrowfn(uc_compiler *compiler, json_object *args, bool resta uc_compiler_parse_consume(&fncompiler, TK_RBRACE); /* overwrite last pop result with return */ - if (fncompiler.function->chunk.count) { - uc_chunk_pop(&fncompiler.function->chunk); + if (fn->chunk.count) { + uc_chunk_pop(&fn->chunk); uc_compiler_emit_insn(&fncompiler, 0, I_RETURN); } } @@ -1127,7 +1124,7 @@ uc_compiler_compile_arrowfn(uc_compiler *compiler, json_object *args, bool resta load_off = uc_compiler_emit_u32(compiler, 0, 0); /* encode upvalue information */ - for (i = 0; i < fncompiler.function->nupvals; i++) + for (i = 0; i < fn->nupvals; i++) uc_compiler_emit_s32(compiler, 0, fncompiler.upvals.entries[i].local ? -(fncompiler.upvals.entries[i].index + 1) @@ -1139,13 +1136,13 @@ uc_compiler_compile_arrowfn(uc_compiler *compiler, json_object *args, bool resta if (fn) uc_compiler_set_u32(compiler, load_off, uc_chunk_add_constant(uc_compiler_current_chunk(compiler), - fn->header.jso)); + &fn->header)); return true; } static uc_tokentype_t -uc_compiler_compile_var_or_arrowfn(uc_compiler *compiler, bool assignable, json_object *name) +uc_compiler_compile_var_or_arrowfn(uc_compiler *compiler, bool assignable, uc_value_t *name) { uc_tokentype_t rv; @@ -1166,7 +1163,7 @@ uc_compiler_compile_var_or_arrowfn(uc_compiler *compiler, bool assignable, json_ static void uc_compiler_compile_paren(uc_compiler *compiler, bool assignable) { - json_object *varnames = NULL, *varname; + uc_value_t *varnames = NULL, *varname; bool maybe_arrowfn = false; bool restarg = false; @@ -1175,17 +1172,17 @@ uc_compiler_compile_paren(uc_compiler *compiler, bool assignable) while (true) { if (uc_compiler_parse_match(compiler, TK_LABEL)) { if (!varnames) - varnames = xjs_new_array(); + varnames = ucv_array_new(NULL); - json_object_array_add(varnames, uc_value_get(compiler->parser->prev.val)); + ucv_array_push(varnames, ucv_get(compiler->parser->prev.uv)); } else if (uc_compiler_parse_match(compiler, TK_ELLIP)) { uc_compiler_parse_consume(compiler, TK_LABEL); if (!varnames) - varnames = xjs_new_array(); + varnames = ucv_array_new(NULL); - json_object_array_add(varnames, uc_value_get(compiler->parser->prev.val)); + ucv_array_push(varnames, ucv_get(compiler->parser->prev.uv)); uc_compiler_parse_consume(compiler, TK_RPAREN); @@ -1232,8 +1229,8 @@ uc_compiler_compile_paren(uc_compiler *compiler, bool assignable) * consecutive labels. */ if (varnames) { /* Get last variable name */ - varname = json_object_array_get_idx(varnames, - json_object_array_length(varnames) - 1); + varname = ucv_array_get(varnames, + ucv_array_length(varnames) - 1); /* If we consumed the right paren, the expression is complete and we * only need to emit a variable read operation for the last parsed @@ -1279,7 +1276,7 @@ uc_compiler_compile_paren(uc_compiler *compiler, bool assignable) uc_compiler_parse_consume(compiler, TK_RPAREN); out: - uc_value_put(varnames); + ucv_put(varnames); } static void @@ -1358,20 +1355,20 @@ uc_compiler_compile_constant(uc_compiler *compiler, bool assignable) case TK_BOOL: uc_compiler_emit_insn(compiler, compiler->parser->prev.pos, - json_object_get_boolean(compiler->parser->prev.val) ? I_LTRUE : I_LFALSE); + ucv_boolean_get(compiler->parser->prev.uv) ? I_LTRUE : I_LFALSE); break; case TK_DOUBLE: case TK_STRING: - uc_compiler_emit_constant(compiler, compiler->parser->prev.pos, compiler->parser->prev.val); + uc_compiler_emit_constant(compiler, compiler->parser->prev.pos, compiler->parser->prev.uv); break; case TK_REGEXP: - uc_compiler_emit_regexp(compiler, compiler->parser->prev.pos, compiler->parser->prev.val); + uc_compiler_emit_regexp(compiler, compiler->parser->prev.pos, compiler->parser->prev.uv); break; case TK_NUMBER: - n = json_object_get_int64(compiler->parser->prev.val); + n = ucv_int64_get(compiler->parser->prev.uv); if (n >= -0x7f && n <= 0x7f) { uc_compiler_emit_insn(compiler, compiler->parser->prev.pos, I_LOAD8); @@ -1386,7 +1383,7 @@ uc_compiler_compile_constant(uc_compiler *compiler, bool assignable) uc_compiler_emit_s32(compiler, compiler->parser->prev.pos, n); } else { - uc_compiler_emit_constant(compiler, compiler->parser->prev.pos, compiler->parser->prev.val); + uc_compiler_emit_constant(compiler, compiler->parser->prev.pos, compiler->parser->prev.uv); } break; @@ -1406,10 +1403,10 @@ uc_compiler_compile_comma(uc_compiler *compiler, bool assignable) static void uc_compiler_compile_labelexpr(uc_compiler *compiler, bool assignable) { - json_object *label = uc_value_get(compiler->parser->prev.val); + uc_value_t *label = ucv_get(compiler->parser->prev.uv); uc_compiler_compile_var_or_arrowfn(compiler, assignable, label); - uc_value_put(label); + ucv_put(label); } static bool @@ -1426,17 +1423,17 @@ static void uc_compiler_compile_function(uc_compiler *compiler, bool assignable) { uc_compiler fncompiler = {}; - json_object *name = NULL; + uc_value_t *name = NULL; ssize_t slot = -1, pos; uc_tokentype_t type; size_t i, load_off; - uc_function *fn; + uc_function_t *fn; pos = compiler->parser->prev.pos; type = compiler->parser->prev.type; if (uc_compiler_parse_match(compiler, TK_LABEL)) { - name = compiler->parser->prev.val; + name = compiler->parser->prev.uv; /* Named functions are syntactic sugar for local variable declaration * with function value assignment. If a name token was encountered, @@ -1448,11 +1445,12 @@ uc_compiler_compile_function(uc_compiler *compiler, bool assignable) } uc_compiler_init(&fncompiler, - name ? json_object_get_string(name) : NULL, compiler->parser->prev.pos, - compiler->function->source); + name ? ucv_string_get(name) : NULL, compiler->parser->prev.pos, + uc_compiler_current_source(compiler)); fncompiler.parent = compiler; fncompiler.parser = compiler->parser; + fn = (uc_function_t *)fncompiler.function; uc_compiler_parse_consume(&fncompiler, TK_LPAREN); @@ -1464,15 +1462,15 @@ uc_compiler_compile_function(uc_compiler *compiler, bool assignable) break; if (uc_compiler_parse_match(&fncompiler, TK_ELLIP)) - fncompiler.function->vararg = true; + fn->vararg = true; if (uc_compiler_parse_match(&fncompiler, TK_LABEL)) { - fncompiler.function->nargs++; + fn->nargs++; - uc_compiler_declare_local(&fncompiler, fncompiler.parser->prev.val); + uc_compiler_declare_local(&fncompiler, fncompiler.parser->prev.uv); uc_compiler_initialize_local(&fncompiler); - if (fncompiler.function->vararg || + if (fn->vararg || !uc_compiler_parse_match(&fncompiler, TK_COMMA)) break; } @@ -1505,7 +1503,7 @@ uc_compiler_compile_function(uc_compiler *compiler, bool assignable) load_off = uc_compiler_emit_u32(compiler, 0, 0); /* encode upvalue information */ - for (i = 0; i < fncompiler.function->nupvals; i++) + for (i = 0; i < fn->nupvals; i++) uc_compiler_emit_s32(compiler, 0, fncompiler.upvals.entries[i].local ? -(fncompiler.upvals.entries[i].index + 1) @@ -1517,7 +1515,7 @@ uc_compiler_compile_function(uc_compiler *compiler, bool assignable) if (fn) uc_compiler_set_u32(compiler, load_off, uc_chunk_add_constant(uc_compiler_current_chunk(compiler), - fn->header.jso)); + &fn->header)); /* if a local variable of the same name already existed, overwrite its value * with the compiled function here */ @@ -1563,7 +1561,7 @@ uc_compiler_compile_dot(uc_compiler *compiler, bool assignable) { /* parse label lhs */ uc_compiler_parse_consume(compiler, TK_LABEL); - uc_compiler_emit_constant(compiler, compiler->parser->prev.pos, compiler->parser->prev.val); + uc_compiler_emit_constant(compiler, compiler->parser->prev.pos, compiler->parser->prev.uv); /* depending on context, compile into I_UVAL, I_SVAL or I_LVAL operation */ if (!assignable || !uc_compiler_compile_assignment(compiler, NULL)) @@ -1718,7 +1716,7 @@ uc_compiler_compile_object(uc_compiler *compiler, bool assignable) /* load label */ uc_compiler_emit_constant(compiler, compiler->parser->prev.pos, - compiler->parser->prev.val); + compiler->parser->prev.uv); /* If the property name is a plain label followed by a comma or * closing curly brace, treat it as ES2015 property shorthand @@ -1727,7 +1725,7 @@ uc_compiler_compile_object(uc_compiler *compiler, bool assignable) (uc_compiler_parse_check(compiler, TK_COMMA) || uc_compiler_parse_check(compiler, TK_RBRACE))) { uc_compiler_emit_variable_rw(compiler, - compiler->parser->prev.val, 0); + compiler->parser->prev.uv, 0); } /* ... otherwise treat it as ordinary `key: value` tuple */ @@ -1765,7 +1763,7 @@ uc_compiler_compile_object(uc_compiler *compiler, bool assignable) static void -uc_compiler_declare_local_null(uc_compiler *compiler, size_t srcpos, json_object *varname) +uc_compiler_declare_local_null(uc_compiler *compiler, size_t srcpos, uc_value_t *varname) { ssize_t existing_slot = uc_compiler_declare_local(compiler, varname); @@ -1819,7 +1817,7 @@ uc_compiler_declare_internal(uc_compiler *compiler, size_t srcpos, const char *n uc_vector_grow(locals); - locals->entries[locals->count].name = xjs_new_string(name); + locals->entries[locals->count].name = ucv_string_new(name); locals->entries[locals->count].depth = compiler->scope_depth; locals->entries[locals->count].captured = false; locals->entries[locals->count].from = chunk->count; @@ -1838,7 +1836,7 @@ uc_compiler_compile_local(uc_compiler *compiler) uc_compiler_parse_consume(compiler, TK_LABEL); /* declare local variable */ - slot = uc_compiler_declare_local(compiler, compiler->parser->prev.val); + slot = uc_compiler_declare_local(compiler, compiler->parser->prev.uv); /* if followed by '=', parse initializer expression */ if (uc_compiler_parse_match(compiler, TK_ASSIGN)) @@ -2062,10 +2060,10 @@ uc_compiler_compile_for_in(uc_compiler *compiler, bool local, uc_token *kvar, uc /* declare loop variables */ if (local) { - uc_compiler_declare_local_null(compiler, kvar->pos, kvar->val); + uc_compiler_declare_local_null(compiler, kvar->pos, kvar->uv); if (vvar) - uc_compiler_declare_local_null(compiler, vvar->pos, vvar->val); + uc_compiler_declare_local_null(compiler, vvar->pos, vvar->uv); } /* value to iterate */ @@ -2109,12 +2107,12 @@ uc_compiler_compile_for_in(uc_compiler *compiler, bool local, uc_token *kvar, uc /* set key and value variables */ if (vvar) { - uc_compiler_emit_variable_rw(compiler, vvar->val, TK_ASSIGN); + uc_compiler_emit_variable_rw(compiler, vvar->uv, TK_ASSIGN); uc_compiler_emit_insn(compiler, 0, I_POP); } /* set key variable */ - uc_compiler_emit_variable_rw(compiler, kvar->val, TK_ASSIGN); + uc_compiler_emit_variable_rw(compiler, kvar->uv, TK_ASSIGN); uc_compiler_emit_insn(compiler, 0, I_POP); /* compile loop body */ @@ -2171,7 +2169,7 @@ uc_compiler_compile_for_count(uc_compiler *compiler, bool local, uc_token *var) /* We parsed a `local x` or `local x, y` expression, so (re)declare * last label as local initializer variable */ if (local) - uc_compiler_declare_local_null(compiler, var->pos, var->val); + uc_compiler_declare_local_null(compiler, var->pos, var->uv); uc_compiler_compile_labelexpr(compiler, true); uc_compiler_emit_insn(compiler, 0, I_POP); @@ -2269,13 +2267,13 @@ uc_compiler_compile_for(uc_compiler *compiler) if (uc_compiler_parse_match(compiler, TK_LABEL)) { keyvar = compiler->parser->prev; - uc_value_get(keyvar.val); + ucv_get(keyvar.uv); if (uc_compiler_parse_match(compiler, TK_COMMA)) { uc_compiler_parse_consume(compiler, TK_LABEL); valvar = compiler->parser->prev; - uc_value_get(valvar.val); + ucv_get(valvar.uv); } /* is a for-in loop */ @@ -2298,11 +2296,11 @@ uc_compiler_compile_for(uc_compiler *compiler) * as counting for loop... */ uc_compiler_compile_for_count(compiler, local, - valvar.val ? &valvar : (keyvar.val ? &keyvar : NULL)); + valvar.uv ? &valvar : (keyvar.uv ? &keyvar : NULL)); out: - uc_value_put(keyvar.val); - uc_value_put(valvar.val); + ucv_put(keyvar.uv); + ucv_put(valvar.uv); } static void @@ -2523,7 +2521,7 @@ uc_compiler_compile_try(uc_compiler *compiler) if (uc_compiler_parse_match(compiler, TK_LPAREN)) { uc_compiler_parse_consume(compiler, TK_LABEL); - uc_compiler_declare_local(compiler, compiler->parser->prev.val); + uc_compiler_declare_local(compiler, compiler->parser->prev.uv); uc_compiler_initialize_local(compiler); uc_compiler_parse_consume(compiler, TK_RPAREN); @@ -2565,7 +2563,7 @@ uc_compiler_compile_control(uc_compiler *compiler) } /* pop locals in scope up to this point */ - for (i = locals->count; i > 0 && locals->entries[i - 1].depth == compiler->scope_depth; i--) + for (i = locals->count; i > 0 && (size_t)locals->entries[i - 1].depth == compiler->scope_depth; i--) uc_compiler_emit_insn(compiler, 0, I_POP); uc_vector_grow(p); @@ -2614,7 +2612,7 @@ uc_compiler_compile_tplexp(uc_compiler *compiler) static void uc_compiler_compile_text(uc_compiler *compiler) { - uc_compiler_emit_constant(compiler, compiler->parser->prev.pos, compiler->parser->prev.val); + uc_compiler_emit_constant(compiler, compiler->parser->prev.pos, compiler->parser->prev.uv); uc_compiler_emit_insn(compiler, 0, I_PRINT); } @@ -2705,12 +2703,12 @@ uc_compiler_compile_declaration(uc_compiler *compiler) uc_compiler_parse_synchronize(compiler); } -uc_function * +uc_function_t * uc_compile(uc_parse_config *config, uc_source *source, char **errp) { uc_parser parser = { .config = config }; uc_compiler compiler = { .parser = &parser }; - uc_function *fn; + uc_function_t *fn; uc_lexer_init(&parser.lex, config, source); uc_compiler_init(&compiler, "main", 0, source); @@ -2722,8 +2720,13 @@ uc_compile(uc_parse_config *config, uc_source *source, char **errp) fn = uc_compiler_finish(&compiler); - if (errp) - *errp = parser.error; + if (errp) { + *errp = parser.error ? parser.error->buf : NULL; + free(parser.error); + } + else { + printbuf_free(parser.error); + } uc_lexer_free(&parser.lex); @@ -28,8 +28,8 @@ #endif #include "source.h" -#include "object.h" #include "lexer.h" +#include "types.h" #include "util.h" typedef enum { @@ -72,14 +72,14 @@ struct uc_patchlist { typedef struct uc_patchlist uc_patchlist; typedef struct { - json_object *name; + uc_value_t *name; ssize_t depth; size_t from; bool captured; } uc_local; typedef struct { - json_object *name; + uc_value_t *name; size_t index; bool local; } uc_upval; @@ -93,7 +93,7 @@ typedef struct { uc_lexer lex; uc_token prev, curr; bool synchronizing; - char *error; + uc_stringbuf_t *error; } uc_parser; struct uc_compiler { @@ -101,7 +101,7 @@ struct uc_compiler { uc_locals locals; uc_upvals upvals; uc_patchlist *patchlist; - uc_function *function; + uc_value_t *function; uc_parser *parser; size_t scope_depth, current_srcpos, last_insn; bool statement_emitted; @@ -115,6 +115,6 @@ typedef struct { uc_precedence_t precedence; } uc_parse_rule; -uc_function *uc_compile(uc_parse_config *config, uc_source *source, char **errp); +uc_function_t *uc_compile(uc_parse_config *config, uc_source *source, char **errp); #endif /* __COMPILER_H_ */ @@ -32,9 +32,9 @@ #define UC_LEX_CONTINUE_PARSING (void *)1 struct keyword { - int type; + unsigned type; const char *pat; - int plen; + unsigned plen; union { double d; bool b; @@ -42,12 +42,12 @@ struct keyword { }; struct token { - int type; + unsigned type; union { uint32_t patn; char pat[4]; }; - int plen; + unsigned plen; uc_token *(*parse)(uc_lexer *, bool); }; @@ -223,10 +223,10 @@ utf8enc(char **out, int *rem, int code) #define UT_LEX_MAX_TOKEN_LEN 3 static uc_token * -emit_op(uc_lexer *lex, uint32_t pos, int type, struct json_object *val) +emit_op(uc_lexer *lex, uint32_t pos, int type, uc_value_t *uv) { lex->curr.type = type; - lex->curr.val = val; + lex->curr.uv = uv; lex->curr.pos = pos; return &lex->curr; @@ -257,7 +257,7 @@ lookbehind_to_text(uc_lexer *lex, uint32_t pos, int type, const char *strip_trai lex->lookbehindlen--; } - rv = emit_op(lex, pos, type, xjs_new_string_len(lex->lookbehind, lex->lookbehindlen)); + rv = emit_op(lex, pos, type, ucv_string_new_length(lex->lookbehind, lex->lookbehindlen)); lookbehind_reset(lex); } @@ -360,7 +360,7 @@ parse_comment(uc_lexer *lex, bool no_regexp) size_t elen; if (!buf_remaining(lex)) - return emit_op(lex, lex->lastoff, TK_ERROR, xjs_new_string("Unterminated comment")); + return emit_op(lex, lex->lastoff, TK_ERROR, ucv_string_new("Unterminated comment")); if (!strcmp(tok->pat, "//")) { end = "\n"; @@ -406,7 +406,7 @@ parse_string(uc_lexer *lex, bool no_regexp) int code; if (!buf_remaining(lex)) - return emit_op(lex, lex->lastoff, TK_ERROR, xjs_new_string("Unterminated string")); + return emit_op(lex, lex->lastoff, TK_ERROR, ucv_string_new("Unterminated string")); for (ptr = lex->bufstart; ptr < lex->bufend; ptr++) { /* continuation of escape sequence */ @@ -461,7 +461,7 @@ parse_string(uc_lexer *lex, bool no_regexp) case 'u': if (lex->esclen < 5) { if (!isxdigit(*ptr)) - return emit_op(lex, lex->source->off + lex->esclen + 1, TK_ERROR, xjs_new_string("Invalid escape sequence")); + return emit_op(lex, lex->source->off + lex->esclen + 1, TK_ERROR, ucv_string_new("Invalid escape sequence")); lex->esc[lex->esclen++] = *ptr; } @@ -513,7 +513,7 @@ parse_string(uc_lexer *lex, bool no_regexp) case 'x': if (lex->esclen < 3) { if (!isxdigit(*ptr)) - return emit_op(lex, lex->source->off + lex->esclen + 1, TK_ERROR, xjs_new_string("Invalid escape sequence")); + return emit_op(lex, lex->source->off + lex->esclen + 1, TK_ERROR, ucv_string_new("Invalid escape sequence")); lex->esc[lex->esclen++] = *ptr; } @@ -564,7 +564,7 @@ parse_string(uc_lexer *lex, bool no_regexp) dec(lex->esc[3]); if (code > 255) - return emit_op(lex, lex->source->off + lex->esclen + 1, TK_ERROR, xjs_new_string("Invalid escape sequence")); + return emit_op(lex, lex->source->off + lex->esclen + 1, TK_ERROR, ucv_string_new("Invalid escape sequence")); append_utf8(lex, code); @@ -585,7 +585,7 @@ parse_string(uc_lexer *lex, bool no_regexp) rv = lookbehind_to_text(lex, lex->lastoff, TK_STRING, NULL); if (!rv) - rv = emit_op(lex, lex->lastoff, TK_STRING, xjs_new_string_len("", 0)); + rv = emit_op(lex, lex->lastoff, TK_STRING, ucv_string_new_length("", 0)); return rv; } @@ -685,10 +685,11 @@ parse_regexp(uc_lexer *lex, bool no_regexp) len = xasprintf(&s, "%c%*s", (is_reg_global << 0) | (is_reg_icase << 1) | (is_reg_newline << 2), - json_object_get_string_len(rv->val), - json_object_get_string(rv->val)); + ucv_string_length(rv->uv), + ucv_string_get(rv->uv)); - json_object_set_string_len(rv->val, s, len); + ucv_free(rv->uv, false); + rv->uv = ucv_string_new_length(s, len); free(s); rv->type = TK_REGEXP; @@ -733,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, uc_double_new(word->d)); + rv = emit_op(lex, lex->source->off - word->plen, word->type, ucv_double_new(word->d)); break; case TK_BOOL: - rv = emit_op(lex, lex->source->off - word->plen, word->type, xjs_new_boolean(word->b)); + rv = emit_op(lex, lex->source->off - word->plen, word->type, ucv_boolean_new(word->b)); break; default: @@ -806,19 +807,19 @@ parse_number(uc_lexer *lex, bool no_regexp) d = -d; if (e > lex->lookbehind && *e == 0) - rv = emit_op(lex, lex->source->off - (e - lex->lookbehind), TK_DOUBLE, uc_double_new(d)); + rv = emit_op(lex, lex->source->off - (e - lex->lookbehind), TK_DOUBLE, ucv_double_new(d)); else - rv = emit_op(lex, lex->source->off - (lex->lookbehindlen - (e - lex->lookbehind) - 1), TK_ERROR, xjs_new_string("Invalid number literal")); + 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] == '-') n = (errno == ERANGE) ? INT64_MIN : -n; - rv = emit_op(lex, lex->source->off - (e - lex->lookbehind), TK_NUMBER, xjs_new_int64(n)); + rv = emit_op(lex, lex->source->off - (e - lex->lookbehind), TK_NUMBER, ucv_int64_new(n)); //OP(rv)->is_overflow = (errno == ERANGE); } else { - rv = emit_op(lex, lex->source->off - (lex->lookbehindlen - (e - lex->lookbehind) - 1), TK_ERROR, xjs_new_string("Invalid number literal")); + rv = emit_op(lex, lex->source->off - (lex->lookbehindlen - (e - lex->lookbehind) - 1), TK_ERROR, ucv_string_new("Invalid number literal")); } lookbehind_reset(lex); @@ -1008,7 +1009,7 @@ lex_step(uc_lexer *lex, FILE *fp, bool no_regexp) buf_consume(lex, lex->bufend - lex->bufstart); - return emit_op(lex, lex->lastoff, TK_ERROR, xjs_new_string("Unterminated template block")); + return emit_op(lex, lex->lastoff, TK_ERROR, ucv_string_new("Unterminated template block")); } break; @@ -1059,7 +1060,7 @@ lex_step(uc_lexer *lex, FILE *fp, bool no_regexp) if (tok->type == TK_LSTM || tok->type == TK_LEXP) { buf_consume(lex, tok->plen); - return emit_op(lex, lex->source->off - tok->plen, TK_ERROR, xjs_new_string("Template blocks may not be nested")); + return emit_op(lex, lex->source->off - tok->plen, TK_ERROR, ucv_string_new("Template blocks may not be nested")); } /* found end of block */ @@ -1093,7 +1094,7 @@ lex_step(uc_lexer *lex, FILE *fp, bool no_regexp) /* no token matched and we do have remaining data, junk */ if (buf_remaining(lex)) - return emit_op(lex, lex->source->off, TK_ERROR, xjs_new_string("Unexpected character")); + return emit_op(lex, lex->source->off, TK_ERROR, ucv_string_new("Unexpected character")); /* we're at eof, allow unclosed statement blocks */ if (lex->block == STATEMENTS) { @@ -1103,7 +1104,7 @@ lex_step(uc_lexer *lex, FILE *fp, bool no_regexp) } /* premature EOF */ - return emit_op(lex, lex->source->off, TK_ERROR, xjs_new_string("Unterminated template block")); + return emit_op(lex, lex->source->off, TK_ERROR, ucv_string_new("Unterminated template block")); case UT_LEX_PARSE_TOKEN: @@ -1188,7 +1189,7 @@ uc_lexer_next_token(uc_lexer *lex, bool no_regexp) } const char * -uc_get_tokenname(int type) +uc_get_tokenname(unsigned type) { static char buf[sizeof("'endfunction'")]; size_t i; @@ -18,6 +18,7 @@ #define __LEXER_H_ #include "source.h" +#include "types.h" typedef enum { @@ -121,7 +122,7 @@ typedef enum { typedef struct { uc_tokentype_t type; - json_object *val; + uc_value_t *uv; size_t pos; } uc_token; @@ -170,6 +171,6 @@ uc_token *uc_lexer_next_token(uc_lexer *lex, bool no_regexp); bool utf8enc(char **out, int *rem, int code); const char * -uc_get_tokenname(int type); +uc_get_tokenname(unsigned type); #endif /* __LEXER_H_ */ @@ -35,116 +35,59 @@ #include "compiler.h" #include "vm.h" #include "lib.h" -#include "object.h" - - -const uc_ops uc = { - .value = { - .proto = uc_prototype_new, - .cfunc = uc_cfunction_new, - .dbl = uc_double_new, - .regexp = uc_regexp_new, - .tonumber = uc_cast_number, - .ressource = uc_ressource_new - }, - - .ressource = { - .define = uc_ressource_type_add, - .create = uc_ressource_new, - .data = uc_ressource_dataptr, - .proto = uc_ressource_prototype - }, - - .vm = { - .call = uc_vm_call, - .peek = uc_vm_stack_peek, - .pop = uc_vm_stack_pop, - .push = uc_vm_stack_push, - .raise = uc_vm_raise_exception - } -}; - -const uc_ops *ops = &uc; - -__attribute__((format(printf, 3, 5))) static void -snprintf_append(char **dptr, size_t *dlen, const char *fmt, ssize_t sz, ...) -{ - va_list ap; - char *tmp; - int n; - - va_start(ap, sz); - n = vsnprintf(NULL, 0, fmt, ap); - va_end(ap); - - if (sz >= 0 && n > sz) - n = sz; - - tmp = xrealloc(*dptr, *dlen + n + 1); - - va_start(ap, sz); - vsnprintf(tmp + *dlen, n + 1, fmt, ap); - va_end(ap); - - *dptr = tmp; - *dlen += n; -} - -#define sprintf_append(dptr, dlen, fmt, ...) \ - snprintf_append(dptr, dlen, fmt, -1, ##__VA_ARGS__) static void -format_context_line(char **msg, size_t *msglen, const char *line, size_t off, bool compact) +format_context_line(uc_stringbuf_t *buf, const char *line, size_t off, bool compact) { + unsigned padlen, i; const char *p; - int padlen, i; for (p = line, padlen = 0; *p != '\n' && *p != '\0'; p++) { - if (compact && (p - line) == off) - sprintf_append(msg, msglen, "\033[22m"); + if (compact && (p - line) == (ptrdiff_t)off) + ucv_stringbuf_append(buf, "\033[22m"); switch (*p) { case '\t': - sprintf_append(msg, msglen, " "); + ucv_stringbuf_append(buf, " "); if (p < line + off) padlen += 4; break; case '\r': case '\v': - sprintf_append(msg, msglen, " "); + ucv_stringbuf_append(buf, " "); if (p < line + off) padlen++; break; default: - sprintf_append(msg, msglen, "%c", *p); + ucv_stringbuf_addstr(buf, p, 1); if (p < line + off) padlen++; } } if (compact) { - sprintf_append(msg, msglen, "\033[m\n"); + ucv_stringbuf_append(buf, "\033[m\n"); return; } - sprintf_append(msg, msglen, "`\n "); + ucv_stringbuf_append(buf, "`\n "); if (padlen < strlen("Near here ^")) { for (i = 0; i < padlen; i++) - sprintf_append(msg, msglen, " "); + ucv_stringbuf_append(buf, " "); - sprintf_append(msg, msglen, "^-- Near here\n"); + ucv_stringbuf_append(buf, "^-- Near here\n"); } else { - sprintf_append(msg, msglen, "Near here "); + ucv_stringbuf_append(buf, "Near here "); for (i = strlen("Near here "); i < padlen; i++) - sprintf_append(msg, msglen, "-"); + ucv_stringbuf_append(buf, "-"); - sprintf_append(msg, msglen, "^\n"); + ucv_stringbuf_append(buf, "^\n"); } } @@ -163,19 +106,19 @@ source_filename(uc_source *src, uint32_t line) return buf; } -void -format_source_context(char **msg, size_t *msglen, uc_source *src, size_t off, bool compact) +bool +format_source_context(uc_stringbuf_t *buf, uc_source *src, size_t off, bool compact) { size_t len, rlen; bool truncated; - char buf[256]; + char line[256]; long srcpos; int eline; srcpos = ftell(src->fp); if (srcpos == -1) - return; + return false; fseek(src->fp, 0, SEEK_SET); @@ -183,93 +126,105 @@ format_source_context(char **msg, size_t *msglen, uc_source *src, size_t off, bo eline = 1; rlen = 0; - while (fgets(buf, sizeof(buf), src->fp)) { - len = strlen(buf); + while (fgets(line, sizeof(line), src->fp)) { + len = strlen(line); rlen += len; if (rlen > off) { if (compact) - sprintf_append(msg, msglen, "\033[2;40;97m%17s %s", + ucv_stringbuf_printf(buf, "\033[2;40;97m%17s %s", source_filename(src, eline), truncated ? "..." : ""); else - sprintf_append(msg, msglen, "\n `%s", + ucv_stringbuf_printf(buf, "\n `%s", truncated ? "..." : ""); - format_context_line(msg, msglen, buf, len - (rlen - off) + (truncated ? 3 : 0), compact); + format_context_line(buf, line, len - (rlen - off) + (truncated ? 3 : 0), compact); break; } - truncated = (len > 0 && buf[len-1] != '\n'); + truncated = (len > 0 && line[len-1] != '\n'); eline += !truncated; } fseek(src->fp, srcpos, SEEK_SET); + + return true; } -void -format_error_context(char **msg, size_t *msglen, uc_source *src, json_object *stacktrace, size_t off) +bool +format_error_context(uc_stringbuf_t *buf, uc_source *src, uc_value_t *stacktrace, size_t off) { - json_object *e, *fn, *file, *line, *byte; + uc_value_t *e, *fn, *file, *line, *byte; const char *path; size_t idx; - for (idx = 0; idx < (stacktrace ? json_object_array_length(stacktrace) : 0); idx++) { - e = json_object_array_get_idx(stacktrace, idx); - fn = json_object_object_get(e, "function"); - file = json_object_object_get(e, "filename"); + for (idx = 0; idx < (stacktrace ? ucv_array_length(stacktrace) : 0); idx++) { + e = ucv_array_get(stacktrace, idx); + fn = ucv_object_get(e, "function", NULL); + file = ucv_object_get(e, "filename", NULL); if (idx == 0) { - path = (file && strcmp(json_object_get_string(file), "[stdin]")) - ? json_object_get_string(file) : NULL; + path = (file && strcmp(ucv_string_get(file), "[stdin]")) + ? ucv_string_get(file) : NULL; if (path && fn) - sprintf_append(msg, msglen, "In %s(), file %s, ", - json_object_get_string(fn), path); + ucv_stringbuf_printf(buf, "In %s(), file %s, ", ucv_string_get(fn), path); else if (fn) - sprintf_append(msg, msglen, "In %s(), ", - json_object_get_string(fn)); + ucv_stringbuf_printf(buf, "In %s(), ", ucv_string_get(fn)); else if (path) - sprintf_append(msg, msglen, "In %s, ", path); + ucv_stringbuf_printf(buf, "In %s, ", path); else - sprintf_append(msg, msglen, "In "); + ucv_stringbuf_append(buf, "In "); - sprintf_append(msg, msglen, "line %" PRId64 ", byte %" PRId64 ":\n", - json_object_get_int64(json_object_object_get(e, "line")), - json_object_get_int64(json_object_object_get(e, "byte"))); + ucv_stringbuf_printf(buf, "line %" PRId64 ", byte %" PRId64 ":\n", + ucv_int64_get(ucv_object_get(e, "line", NULL)), + ucv_int64_get(ucv_object_get(e, "byte", NULL))); } else { - line = json_object_object_get(e, "line"); - byte = json_object_object_get(e, "byte"); + line = ucv_object_get(e, "line", NULL); + byte = ucv_object_get(e, "byte", NULL); - sprintf_append(msg, msglen, " called from %s%s (%s", - fn ? "function " : "anonymous function", - fn ? json_object_get_string(fn) : "", - file ? json_object_get_string(file) : ""); + ucv_stringbuf_printf(buf, " called from %s%s (%s", + fn ? "function " : "anonymous function", + fn ? ucv_string_get(fn) : "", + file ? ucv_string_get(file) : ""); if (line && byte) - sprintf_append(msg, msglen, ":%" PRId64 ":%" PRId64 ")\n", - json_object_get_int64(line), - json_object_get_int64(byte)); + ucv_stringbuf_printf(buf, ":%" PRId64 ":%" PRId64 ")\n", + ucv_int64_get(line), + ucv_int64_get(byte)); else - sprintf_append(msg, msglen, "[C])\n"); + ucv_stringbuf_append(buf, "[C])\n"); } } - format_source_context(msg, msglen, src, off, false); + return format_source_context(buf, src, off, false); +} + +static char *uc_cast_string(uc_vm *vm, uc_value_t **v, bool *freeable) { + if (ucv_type(*v) == UC_STRING) { + *freeable = false; + + return _ucv_string_get(v); + } + + *freeable = true; + + return ucv_to_string(vm, *v); } static double -uc_cast_double(json_object *v) +uc_cast_double(uc_value_t *v) { - enum json_type t; + uc_type_t t; int64_t n; double d; t = uc_cast_number(v, &n, &d); errno = 0; - if (t == json_type_double) { + if (t == UC_DOUBLE) { if (isnan(d)) errno = EINVAL; else if (!isfinite(d)) @@ -282,16 +237,16 @@ uc_cast_double(json_object *v) } static int64_t -uc_cast_int64(json_object *v) +uc_cast_int64(uc_value_t *v) { - enum json_type t; + uc_type_t t; int64_t n; double d; t = uc_cast_number(v, &n, &d); errno = 0; - if (t == json_type_double) { + if (t == UC_DOUBLE) { if (isnan(d)) errno = EINVAL; else if (!isfinite(d)) @@ -305,73 +260,72 @@ uc_cast_int64(json_object *v) return n; } -static json_object * +static uc_value_t * uc_print_common(uc_vm *vm, size_t nargs, FILE *fh) { - json_object *item; + uc_value_t *item; size_t reslen = 0; size_t len = 0; size_t arridx; - const char *p; + char *p; for (arridx = 0; arridx < nargs; arridx++) { item = uc_get_arg(arridx); - if (json_object_is_type(item, json_type_string)) { - p = json_object_get_string(item); - len = json_object_get_string_len(item); + if (ucv_type(item) == UC_STRING) { + len = ucv_string_length(item); + reslen += fwrite(ucv_string_get(item), 1, len, fh); } - else { - p = item ? json_object_get_string(item) : NULL; - p = p ? p : ""; + else if (item != NULL) { + p = ucv_to_string(vm, item); len = strlen(p); + reslen += fwrite(p, 1, len, fh); + free(p); } - - reslen += fwrite(p, 1, len, fh); } - return xjs_new_int64(reslen); + return ucv_int64_new(reslen); } -static json_object * +static uc_value_t * uc_print(uc_vm *vm, size_t nargs) { return uc_print_common(vm, nargs, stdout); } -static json_object * +static uc_value_t * uc_length(uc_vm *vm, size_t nargs) { - json_object *arg = uc_get_arg(0); + uc_value_t *arg = uc_get_arg(0); - switch (json_object_get_type(arg)) { - case json_type_object: - return xjs_new_int64(json_object_object_length(arg)); + switch (ucv_type(arg)) { + case UC_OBJECT: + return ucv_int64_new(ucv_object_length(arg)); - case json_type_array: - return xjs_new_int64(json_object_array_length(arg)); + case UC_ARRAY: + return ucv_int64_new(ucv_array_length(arg)); - case json_type_string: - return xjs_new_int64(json_object_get_string_len(arg)); + case UC_STRING: + return ucv_int64_new(ucv_string_length(arg)); default: return NULL; } } -static json_object * +static uc_value_t * uc_index(uc_vm *vm, size_t nargs, bool right) { - json_object *stack = uc_get_arg(0); - json_object *needle = uc_get_arg(1); + uc_value_t *stack = uc_get_arg(0); + uc_value_t *needle = uc_get_arg(1); size_t arridx, len, ret = -1; const char *sstr, *nstr, *p; - switch (json_object_get_type(stack)) { - case json_type_array: - for (arridx = 0, len = json_object_array_length(stack); arridx < len; arridx++) { - if (uc_cmp(TK_EQ, json_object_array_get_idx(stack, arridx), needle)) { + switch (ucv_type(stack)) { + case UC_ARRAY: + for (arridx = 0, len = ucv_array_length(stack); arridx < len; arridx++) { + if (uc_cmp(TK_EQ, ucv_array_get(stack, arridx), needle)) { ret = arridx; if (!right) @@ -379,11 +333,11 @@ uc_index(uc_vm *vm, size_t nargs, bool right) } } - return xjs_new_int64(ret); + return ucv_int64_new(ret); - case json_type_string: - sstr = json_object_get_string(stack); - nstr = needle ? json_object_get_string(needle) : NULL; + case UC_STRING: + sstr = ucv_string_get(stack); + nstr = needle ? ucv_string_get(needle) : NULL; len = needle ? strlen(nstr) : 0; for (p = sstr; *p && len; p++) { @@ -395,126 +349,87 @@ uc_index(uc_vm *vm, size_t nargs, bool right) } } - return xjs_new_int64(ret); + return ucv_int64_new(ret); default: return NULL; } } -static json_object * +static uc_value_t * uc_lindex(uc_vm *vm, size_t nargs) { return uc_index(vm, nargs, false); } -static json_object * +static uc_value_t * uc_rindex(uc_vm *vm, size_t nargs) { return uc_index(vm, nargs, true); } -static json_object * +static uc_value_t * uc_push(uc_vm *vm, size_t nargs) { - json_object *arr = uc_get_arg(0); - json_object *item = NULL; + uc_value_t *arr = uc_get_arg(0); + uc_value_t *item = NULL; size_t arridx; - if (!json_object_is_type(arr, json_type_array)) + if (ucv_type(arr) != UC_ARRAY) return NULL; for (arridx = 1; arridx < nargs; arridx++) { item = uc_get_arg(arridx); - json_object_array_add(arr, uc_value_get(item)); + ucv_array_push(arr, ucv_get(item)); } - return uc_value_get(item); + return ucv_get(item); } -static json_object * +static uc_value_t * uc_pop(uc_vm *vm, size_t nargs) { - json_object *arr = uc_get_arg(0); - json_object *item = NULL; - size_t arrlen; + uc_value_t *arr = uc_get_arg(0); - if (!json_object_is_type(arr, json_type_array)) - return NULL; - - arrlen = json_object_array_length(arr); - - if (arrlen > 0) { - item = uc_value_get(json_object_array_get_idx(arr, arrlen - 1)); - json_object_array_del_idx(arr, arrlen - 1, 1); -#ifdef HAVE_ARRAY_SHRINK - json_object_array_shrink(arr, 0); -#endif - } - - return item; + return ucv_array_pop(arr); } -static json_object * +static uc_value_t * uc_shift(uc_vm *vm, size_t nargs) { - json_object *arr = uc_get_arg(0); - json_object *item = NULL; - size_t arridx, arrlen; - - if (!json_object_is_type(arr, json_type_array)) - return NULL; - - item = uc_value_get(json_object_array_get_idx(arr, 0)); - arrlen = json_object_array_length(arr); - - for (arridx = 0; arridx < arrlen - 1; arridx++) - json_object_array_put_idx(arr, arridx, - uc_value_get(json_object_array_get_idx(arr, arridx + 1))); + uc_value_t *arr = uc_get_arg(0); - json_object_array_del_idx(arr, arrlen - 1, 1); -#ifdef HAVE_ARRAY_SHRINK - json_object_array_shrink(arr, 0); -#endif - - return item; + return ucv_array_shift(arr); } -static json_object * +static uc_value_t * uc_unshift(uc_vm *vm, size_t nargs) { - json_object *arr = uc_get_arg(0); - json_object *item = NULL; - size_t arridx, arrlen, addlen; + uc_value_t *arr = uc_get_arg(0); + uc_value_t *item = NULL; + size_t i; - if (!json_object_is_type(arr, json_type_array)) + if (ucv_type(arr) != UC_ARRAY) return NULL; - arrlen = json_object_array_length(arr); - addlen = nargs - 1; - - for (arridx = arrlen; arridx > 0; arridx--) - json_object_array_put_idx(arr, arridx + addlen - 1, - uc_value_get(json_object_array_get_idx(arr, arridx - 1))); - - for (arridx = 0; arridx < addlen; arridx++) { - item = uc_get_arg(arridx + 1); - json_object_array_put_idx(arr, arridx, uc_value_get(item)); + for (i = 1; i < nargs; i++) { + item = uc_get_arg(i); + ucv_array_unshift(arr, ucv_get(item)); } - return uc_value_get(item); + return ucv_get(item); } -static json_object * +static uc_value_t * uc_chr(uc_vm *vm, size_t nargs) { - json_object *rv = NULL; + uc_value_t *rv = NULL; size_t idx; int64_t n; char *str; if (!nargs) - return xjs_new_string_len("", 0); + return ucv_string_new_length("", 0); str = xalloc(nargs); @@ -529,58 +444,68 @@ uc_chr(uc_vm *vm, size_t nargs) str[idx] = (char)n; } - rv = xjs_new_string_len(str, nargs); + rv = ucv_string_new_length(str, nargs); free(str); return rv; } -static json_object * +static uc_value_t * uc_delete(uc_vm *vm, size_t nargs) { - json_object *obj = uc_get_arg(0); - json_object *rv = NULL; + uc_value_t *obj = uc_get_arg(0); + uc_value_t *rv = NULL; const char *key; - size_t arridx; + size_t i; - if (!json_object_is_type(obj, json_type_object)) + if (ucv_type(obj) != UC_OBJECT) return NULL; - for (arridx = 1; arridx < nargs; arridx++) { - uc_value_put(rv); + for (i = 1; i < nargs; i++) { + ucv_put(rv); - key = json_object_get_string(uc_get_arg(arridx)); - rv = uc_value_get(json_object_object_get(obj, key ? key : "null")); + key = ucv_string_get(uc_get_arg(i)); + rv = ucv_get(ucv_object_get(obj, key ? key : "null", NULL)); - json_object_object_del(obj, key ? key : "null"); + ucv_object_delete(obj, key ? key : "null"); } return rv; } -static json_object * +static uc_value_t * uc_die(uc_vm *vm, size_t nargs) { - const char *msg = json_object_get_string(uc_get_arg(0)); + uc_value_t *msg = uc_get_arg(0); + bool freeable = false; + char *s; + + s = msg ? uc_cast_string(vm, &msg, &freeable) : "Died"; - uc_vm_raise_exception(vm, EXCEPTION_USER, msg ? msg : "Died"); + uc_vm_raise_exception(vm, EXCEPTION_USER, s); + + if (freeable) + free(s); return NULL; } -static json_object * +static uc_value_t * uc_exists(uc_vm *vm, size_t nargs) { - json_object *obj = uc_get_arg(0); - const char *key = json_object_get_string(uc_get_arg(1)); + uc_value_t *obj = uc_get_arg(0); + const char *key = ucv_string_get(uc_get_arg(1)); + bool found; - if (!json_object_is_type(obj, json_type_object)) + if (ucv_type(obj) != UC_OBJECT) return false; - return xjs_new_boolean(json_object_object_get_ex(obj, key ? key : "null", NULL)); + ucv_object_get(obj, key ? key : "null", &found); + + return ucv_boolean_new(found); } -__attribute__((noreturn)) static json_object * +__attribute__((noreturn)) static uc_value_t * uc_exit(uc_vm *vm, size_t nargs) { int64_t n = uc_cast_int64(uc_get_arg(0)); @@ -588,37 +513,37 @@ uc_exit(uc_vm *vm, size_t nargs) exit(n); } -static json_object * +static uc_value_t * uc_getenv(uc_vm *vm, size_t nargs) { - const char *key = json_object_get_string(uc_get_arg(0)); + const char *key = ucv_string_get(uc_get_arg(0)); char *val = key ? getenv(key) : NULL; - return val ? xjs_new_string(val) : NULL; + return val ? ucv_string_new(val) : NULL; } -static json_object * +static uc_value_t * uc_filter(uc_vm *vm, size_t nargs) { - json_object *obj = uc_get_arg(0); - json_object *func = uc_get_arg(1); - json_object *rv, *arr; + uc_value_t *obj = uc_get_arg(0); + uc_value_t *func = uc_get_arg(1); + uc_value_t *rv, *arr; size_t arridx, arrlen; - if (!json_object_is_type(obj, json_type_array)) + if (ucv_type(obj) != UC_ARRAY) return NULL; - arr = xjs_new_array(); + arr = ucv_array_new(vm); - for (arrlen = json_object_array_length(obj), arridx = 0; arridx < arrlen; arridx++) { + for (arrlen = ucv_array_length(obj), arridx = 0; arridx < arrlen; arridx++) { /* XXX: revisit leaks */ - uc_vm_stack_push(vm, uc_value_get(func)); - uc_vm_stack_push(vm, uc_value_get(json_object_array_get_idx(obj, arridx))); - uc_vm_stack_push(vm, xjs_new_int64(arridx)); - uc_vm_stack_push(vm, uc_value_get(obj)); + uc_vm_stack_push(vm, ucv_get(func)); + uc_vm_stack_push(vm, ucv_get(ucv_array_get(obj, arridx))); + uc_vm_stack_push(vm, ucv_int64_new(arridx)); + uc_vm_stack_push(vm, ucv_get(obj)); if (uc_vm_call(vm, false, 3)) { - uc_value_put(arr); + ucv_put(arr); return NULL; } @@ -626,281 +551,229 @@ uc_filter(uc_vm *vm, size_t nargs) rv = uc_vm_stack_pop(vm); if (uc_val_is_truish(rv)) - json_object_array_add(arr, uc_value_get(json_object_array_get_idx(obj, arridx))); + ucv_array_push(arr, ucv_get(ucv_array_get(obj, arridx))); - uc_value_put(rv); + ucv_put(rv); } return arr; } -static json_object * +static uc_value_t * uc_hex(uc_vm *vm, size_t nargs) { - const char *val = json_object_get_string(uc_get_arg(0)); + const char *val = ucv_string_get(uc_get_arg(0)); int64_t n; char *e; if (!val || !isxdigit(*val)) - return uc_double_new(NAN); + return ucv_double_new(NAN); n = strtoll(val, &e, 16); if (e == val || *e) - return uc_double_new(NAN); + return ucv_double_new(NAN); - return xjs_new_int64(n); + return ucv_int64_new(n); } -static json_object * +static uc_value_t * uc_int(uc_vm *vm, size_t nargs) { int64_t n = uc_cast_int64(uc_get_arg(0)); if (errno == EINVAL || errno == EOVERFLOW) - return uc_double_new(NAN); + return ucv_double_new(NAN); - return xjs_new_int64(n); + return ucv_int64_new(n); } -static json_object * +static uc_value_t * uc_join(uc_vm *vm, size_t nargs) { - const char *sep = json_object_get_string(uc_get_arg(0)); - json_object *arr = uc_get_arg(1); - json_object *rv = NULL; - size_t arrlen, arridx, len = 1; - const char *item; - char *res, *p; - int ret; + uc_value_t *sep = uc_get_arg(0); + uc_value_t *arr = uc_get_arg(1); + size_t arrlen, arridx; + uc_stringbuf_t *buf; - if (!json_object_is_type(arr, json_type_array)) + if (ucv_type(arr) != UC_ARRAY) return NULL; - for (arrlen = json_object_array_length(arr), arridx = 0; arridx < arrlen; arridx++) { - if (arridx > 0) - len += strlen(sep); - - item = json_object_get_string(json_object_array_get_idx(arr, arridx)); - len += item ? strlen(item) : 0; - } - - p = res = xalloc(len); - - for (arrlen = json_object_array_length(arr), arridx = 0; arridx < arrlen; arridx++) { - if (arridx > 0) { - ret = snprintf(p, len, "%s", sep); - - if (ret < 0 || ret >= len) - goto out; + buf = ucv_stringbuf_new(); - len -= ret; - p += ret; - } - - item = json_object_get_string(json_object_array_get_idx(arr, arridx)); - - if (item) { - ret = snprintf(p, len, "%s", item); - - if (ret < 0 || ret >= len) - goto out; + for (arrlen = ucv_array_length(arr), arridx = 0; arridx < arrlen; arridx++) { + if (arridx > 0) + ucv_to_stringbuf(vm, buf, sep, false); - len -= ret; - p += ret; - } + ucv_to_stringbuf(vm, buf, ucv_array_get(arr, arridx), false); } - rv = xjs_new_string(res); - -out: - free(res); - - return rv; + return ucv_stringbuf_finish(buf); } -static json_object * +static uc_value_t * uc_keys(uc_vm *vm, size_t nargs) { - json_object *obj = uc_get_arg(0); - json_object *arr = NULL; + uc_value_t *obj = uc_get_arg(0); + uc_value_t *arr = NULL; - if (!json_object_is_type(obj, json_type_object)) + if (ucv_type(obj) != UC_OBJECT) return NULL; - arr = xjs_new_array(); + arr = ucv_array_new(vm); - json_object_object_foreach(obj, key, val) - json_object_array_add(arr, xjs_new_string(key)); + ucv_object_foreach(obj, key, val) + ucv_array_push(arr, ucv_string_new(key)); return arr; } -static json_object * +static uc_value_t * uc_lc(uc_vm *vm, size_t nargs) { - const char *str = json_object_get_string(uc_get_arg(0)); - size_t len = str ? strlen(str) : 0; - json_object *rv = NULL; - char *res, *p; + char *str = ucv_to_string(vm, uc_get_arg(0)); + uc_value_t *rv = NULL; + char *p; if (!str) return NULL; - res = p = xalloc(len); + for (p = str; *p; p++) + if (*p >= 'A' && *p <= 'Z') + *p |= 32; - while (*str) - if (*str >= 'A' && *str <= 'Z') - *p++ = 32 + *str++; - else - *p++ = *str++; + rv = ucv_string_new(str); - rv = xjs_new_string_len(res, len); - free(res); + free(str); return rv; } -static json_object * +static uc_value_t * uc_map(uc_vm *vm, size_t nargs) { - json_object *obj = uc_get_arg(0); - json_object *func = uc_get_arg(1); - json_object *arr, *rv; + uc_value_t *obj = uc_get_arg(0); + uc_value_t *func = uc_get_arg(1); + uc_value_t *arr, *rv; size_t arridx, arrlen; - if (!json_object_is_type(obj, json_type_array)) + if (ucv_type(obj) != UC_ARRAY) return NULL; - arr = xjs_new_array(); + arr = ucv_array_new(vm); - for (arrlen = json_object_array_length(obj), arridx = 0; arridx < arrlen; arridx++) { + for (arrlen = ucv_array_length(obj), arridx = 0; arridx < arrlen; arridx++) { /* XXX: revisit leaks */ - uc_vm_stack_push(vm, uc_value_get(func)); - uc_vm_stack_push(vm, uc_value_get(json_object_array_get_idx(obj, arridx))); - uc_vm_stack_push(vm, xjs_new_int64(arridx)); - uc_vm_stack_push(vm, uc_value_get(obj)); + uc_vm_stack_push(vm, ucv_get(func)); + uc_vm_stack_push(vm, ucv_get(ucv_array_get(obj, arridx))); + uc_vm_stack_push(vm, ucv_int64_new(arridx)); + uc_vm_stack_push(vm, ucv_get(obj)); if (uc_vm_call(vm, false, 3)) { - uc_value_put(arr); + ucv_put(arr); return NULL; } rv = uc_vm_stack_pop(vm); - json_object_array_add(arr, rv); + ucv_array_push(arr, rv); } return arr; } -static json_object * +static uc_value_t * uc_ord(uc_vm *vm, size_t nargs) { - json_object *obj = uc_get_arg(0); - json_object *rv, *pos; + uc_value_t *obj = uc_get_arg(0); + uc_value_t *rv, *pos; const char *str; size_t i, len; int64_t n; - if (!json_object_is_type(obj, json_type_string)) + if (ucv_type(obj) != UC_STRING) return NULL; - str = json_object_get_string(obj); - len = json_object_get_string_len(obj); + str = ucv_string_get(obj); + len = ucv_string_length(obj); if (nargs == 1) - return str[0] ? xjs_new_int64((int64_t)str[0]) : NULL; + return str[0] ? ucv_int64_new((int64_t)str[0]) : NULL; - rv = xjs_new_array(); + rv = ucv_array_new(vm); for (i = 1; i < nargs; i++) { pos = uc_get_arg(i); - if (json_object_is_type(pos, json_type_int)) { - n = json_object_get_int64(pos); + if (ucv_type(pos) == UC_INTEGER) { + n = ucv_int64_get(pos); if (n < 0) n += len; - if (n >= 0 && n < len) { - json_object_array_add(rv, xjs_new_int64((int64_t)str[n])); + if (n >= 0 && (uint64_t)n < len) { + ucv_array_push(rv, ucv_int64_new((int64_t)str[n])); continue; } } - json_object_array_add(rv, NULL); + ucv_array_push(rv, NULL); } return rv; } -static json_object * +static uc_value_t * uc_type(uc_vm *vm, size_t nargs) { - json_object *v = uc_get_arg(0); - uc_objtype_t o = uc_object_type(v); - - switch (o) { - case UC_OBJ_CFUNCTION: - case UC_OBJ_FUNCTION: - case UC_OBJ_CLOSURE: - return xjs_new_string("function"); - - case UC_OBJ_RESSOURCE: - return xjs_new_string("ressource"); - - default: - switch (json_object_get_type(v)) { - case json_type_object: - return xjs_new_string("object"); - - case json_type_array: - return xjs_new_string("array"); + uc_value_t *v = uc_get_arg(0); + uc_type_t t = ucv_type(v); - case json_type_double: - return xjs_new_string("double"); + switch (t) { + case UC_CFUNCTION: + case UC_FUNCTION: + case UC_CLOSURE: + return ucv_string_new("function"); - case json_type_int: - return xjs_new_string("int"); + case UC_INTEGER: + return ucv_string_new("int"); - case json_type_boolean: - return xjs_new_string("bool"); + case UC_BOOLEAN: + return ucv_string_new("bool"); - case json_type_string: - return xjs_new_string("string"); + case UC_NULL: + return NULL; - default: - return NULL; - } + default: + return ucv_string_new(ucv_typename(v)); } } -static json_object * +static uc_value_t * uc_reverse(uc_vm *vm, size_t nargs) { - json_object *obj = uc_get_arg(0); - json_object *rv = NULL; + uc_value_t *obj = uc_get_arg(0); + uc_value_t *rv = NULL; size_t len, arridx; const char *str; char *dup, *p; - if (json_object_is_type(obj, json_type_array)) { - rv = xjs_new_array(); + if (ucv_type(obj) == UC_ARRAY) { + rv = ucv_array_new(vm); - for (arridx = json_object_array_length(obj); arridx > 0; arridx--) - json_object_array_add(rv, uc_value_get(json_object_array_get_idx(obj, arridx - 1))); + for (arridx = ucv_array_length(obj); arridx > 0; arridx--) + ucv_array_push(rv, ucv_get(ucv_array_get(obj, arridx - 1))); } - else if (json_object_is_type(obj, json_type_string)) { - len = json_object_get_string_len(obj); - str = json_object_get_string(obj); + else if (ucv_type(obj) == UC_STRING) { + len = ucv_string_length(obj); + str = ucv_string_get(obj); p = dup = xalloc(len + 1); while (len > 0) *p++ = str[--len]; - rv = xjs_new_string(dup); + rv = ucv_string_new(dup); free(dup); } @@ -912,15 +785,15 @@ uc_reverse(uc_vm *vm, size_t nargs) static struct { uc_vm *vm; bool ex; - json_object *fn; + uc_value_t *fn; } sort_ctx; static int sort_fn(const void *k1, const void *k2) { - json_object * const *v1 = k1; - json_object * const *v2 = k2; - json_object *rv; + uc_value_t * const *v1 = k1; + uc_value_t * const *v2 = k2; + uc_value_t *rv; int ret; if (!sort_ctx.fn) @@ -929,9 +802,9 @@ sort_fn(const void *k1, const void *k2) if (sort_ctx.ex) return 0; - uc_vm_stack_push(sort_ctx.vm, uc_value_get(sort_ctx.fn)); - uc_vm_stack_push(sort_ctx.vm, uc_value_get(*v1)); - uc_vm_stack_push(sort_ctx.vm, uc_value_get(*v2)); + uc_vm_stack_push(sort_ctx.vm, ucv_get(sort_ctx.fn)); + uc_vm_stack_push(sort_ctx.vm, ucv_get(*v1)); + uc_vm_stack_push(sort_ctx.vm, ucv_get(*v2)); if (uc_vm_call(sort_ctx.vm, false, 2)) { sort_ctx.ex = true; @@ -943,40 +816,40 @@ sort_fn(const void *k1, const void *k2) ret = !uc_val_is_truish(rv); - uc_value_put(rv); + ucv_put(rv); return ret; } -static json_object * +static uc_value_t * uc_sort(uc_vm *vm, size_t nargs) { - json_object *arr = uc_get_arg(0); - json_object *fn = uc_get_arg(1); + uc_value_t *arr = uc_get_arg(0); + uc_value_t *fn = uc_get_arg(1); - if (!json_object_is_type(arr, json_type_array)) + if (ucv_type(arr) != UC_ARRAY) return NULL; sort_ctx.vm = vm; sort_ctx.fn = fn; - json_object_array_sort(arr, sort_fn); + ucv_array_sort(arr, sort_fn); - return sort_ctx.ex ? NULL : uc_value_get(arr); + return sort_ctx.ex ? NULL : ucv_get(arr); } -static json_object * +static uc_value_t * uc_splice(uc_vm *vm, size_t nargs) { - json_object *arr = uc_get_arg(0); + uc_value_t *arr = uc_get_arg(0); int64_t ofs = uc_cast_int64(uc_get_arg(1)); int64_t remlen = uc_cast_int64(uc_get_arg(2)); size_t arrlen, addlen, idx; - if (!json_object_is_type(arr, json_type_array)) + if (ucv_type(arr) != UC_ARRAY) return NULL; - arrlen = json_object_array_length(arr); + arrlen = ucv_array_length(arr); addlen = nargs; if (addlen == 1) { @@ -991,7 +864,7 @@ uc_splice(uc_vm *vm, size_t nargs) if (ofs < 0) ofs = 0; } - else if (ofs > arrlen) { + else if ((uint64_t)ofs > arrlen) { ofs = arrlen; } @@ -1005,7 +878,7 @@ uc_splice(uc_vm *vm, size_t nargs) if (ofs < 0) ofs = 0; } - else if (ofs > arrlen) { + else if ((uint64_t)ofs > arrlen) { ofs = arrlen; } @@ -1015,71 +888,71 @@ uc_splice(uc_vm *vm, size_t nargs) if (remlen < 0) remlen = 0; } - else if (remlen > arrlen - ofs) { + else if ((uint64_t)remlen > arrlen - ofs) { remlen = arrlen - ofs; } addlen -= 3; } - if (addlen < remlen) { - json_object_array_del_idx(arr, ofs, remlen - addlen); + if (addlen < (uint64_t)remlen) { + ucv_array_delete(arr, ofs, remlen - addlen); } - else if (addlen > remlen) { - for (idx = arrlen; idx > ofs; idx--) - json_object_array_put_idx(arr, idx + addlen - remlen - 1, - uc_value_get(json_object_array_get_idx(arr, idx - 1))); + else if (addlen > (uint64_t)remlen) { + for (idx = arrlen; idx > (uint64_t)ofs; idx--) + ucv_array_set(arr, idx + addlen - remlen - 1, + ucv_get(ucv_array_get(arr, idx - 1))); } for (idx = 0; idx < addlen; idx++) - json_object_array_put_idx(arr, ofs + idx, - uc_value_get(uc_get_arg(3 + idx))); + ucv_array_set(arr, ofs + idx, + ucv_get(uc_get_arg(3 + idx))); - return uc_value_get(arr); + return ucv_get(arr); } -static json_object * +static uc_value_t * uc_split(uc_vm *vm, size_t nargs) { - json_object *str = uc_get_arg(0); - json_object *sep = uc_get_arg(1); - json_object *arr = NULL; + uc_value_t *str = uc_get_arg(0); + uc_value_t *sep = uc_get_arg(1); + uc_value_t *arr = NULL; const char *p, *sepstr, *splitstr; int eflags = 0, res; regmatch_t pmatch; - uc_regexp *re; + uc_regexp_t *re; size_t seplen; - if (!sep || !json_object_is_type(str, json_type_string)) + if (!sep || ucv_type(str) != UC_STRING) return NULL; - arr = xjs_new_array(); - splitstr = json_object_get_string(str); + arr = ucv_array_new(vm); + splitstr = ucv_string_get(str); - if (uc_object_is_type(sep, UC_OBJ_REGEXP)) { - re = uc_object_as_regexp(sep); + if (ucv_type(sep) == UC_REGEXP) { + re = (uc_regexp_t *)sep; while (true) { - res = regexec(&re->re, splitstr, 1, &pmatch, eflags); + res = regexec(&re->regexp, splitstr, 1, &pmatch, eflags); if (res == REG_NOMATCH) break; - json_object_array_add(arr, xjs_new_string_len(splitstr, pmatch.rm_so)); + ucv_array_push(arr, ucv_string_new_length(splitstr, pmatch.rm_so)); splitstr += pmatch.rm_eo; eflags |= REG_NOTBOL; } - json_object_array_add(arr, xjs_new_string(splitstr)); + ucv_array_push(arr, ucv_string_new(splitstr)); } - else if (json_object_is_type(sep, json_type_string)) { - sepstr = json_object_get_string(sep); + else if (ucv_type(sep) == UC_STRING) { + sepstr = ucv_string_get(sep); for (p = splitstr + (*sepstr ? 1 : 0), seplen = strlen(sepstr); *p; p++) { if (!strncmp(p, sepstr, seplen)) { if (*sepstr || p > splitstr) - json_object_array_add(arr, xjs_new_string_len(splitstr, p - splitstr)); + ucv_array_push(arr, ucv_string_new_length(splitstr, p - splitstr)); splitstr = p + seplen; p = splitstr - (*sepstr ? 1 : 0); @@ -1087,10 +960,10 @@ uc_split(uc_vm *vm, size_t nargs) } if (*splitstr) - json_object_array_add(arr, xjs_new_string_len(splitstr, p - splitstr)); + ucv_array_push(arr, ucv_string_new_length(splitstr, p - splitstr)); } else { - uc_value_put(arr); + ucv_put(arr); return NULL; } @@ -1098,20 +971,20 @@ uc_split(uc_vm *vm, size_t nargs) return arr; } -static json_object * +static uc_value_t * uc_substr(uc_vm *vm, size_t nargs) { - json_object *str = uc_get_arg(0); + uc_value_t *str = uc_get_arg(0); int64_t ofs = uc_cast_int64(uc_get_arg(1)); int64_t sublen = uc_cast_int64(uc_get_arg(2)); const char *p; size_t len; - if (!json_object_is_type(str, json_type_string)) + if (ucv_type(str) != UC_STRING) return NULL; - p = json_object_get_string(str); - len = json_object_get_string_len(str); + p = ucv_string_get(str); + len = ucv_string_length(str); switch (nargs) { case 1: @@ -1127,7 +1000,7 @@ uc_substr(uc_vm *vm, size_t nargs) if (ofs < 0) ofs = 0; } - else if (ofs > len) { + else if ((uint64_t)ofs > len) { ofs = len; } @@ -1142,7 +1015,7 @@ uc_substr(uc_vm *vm, size_t nargs) if (ofs < 0) ofs = 0; } - else if (ofs > len) { + else if ((uint64_t)ofs > len) { ofs = len; } @@ -1152,53 +1025,49 @@ uc_substr(uc_vm *vm, size_t nargs) if (sublen < 0) sublen = 0; } - else if (sublen > len - ofs) { + else if ((uint64_t)sublen > len - ofs) { sublen = len - ofs; } break; } - return xjs_new_string_len(p + ofs, sublen); + return ucv_string_new_length(p + ofs, sublen); } -static json_object * +static uc_value_t * uc_time(uc_vm *vm, size_t nargs) { time_t t = time(NULL); - return xjs_new_int64((int64_t)t); + return ucv_int64_new((int64_t)t); } -static json_object * +static uc_value_t * uc_uc(uc_vm *vm, size_t nargs) { - const char *str = json_object_get_string(uc_get_arg(0)); - size_t len = str ? strlen(str) : 0; - json_object *rv = NULL; - char *res, *p; + char *str = ucv_to_string(vm, uc_get_arg(0)); + uc_value_t *rv = NULL; + char *p; if (!str) return NULL; - res = p = xalloc(len); + for (p = str; *p; p++) + if (*p >= 'a' && *p <= 'z') + *p &= ~32; - while (*str) - if (*str >= 'a' && *str <= 'z') - *p++ = *str++ - 32; - else - *p++ = *str++; + rv = ucv_string_new(str); - rv = xjs_new_string_len(res, len); - free(res); + free(str); return rv; } -static json_object * +static uc_value_t * uc_uchr(uc_vm *vm, size_t nargs) { - json_object *rv = NULL; + uc_value_t *rv = NULL; size_t idx, ulen; char *p, *str; int64_t n; @@ -1231,48 +1100,49 @@ uc_uchr(uc_vm *vm, size_t nargs) break; } - rv = xjs_new_string_len(str, ulen); + rv = ucv_string_new_length(str, ulen); + free(str); return rv; } -static json_object * +static uc_value_t * uc_values(uc_vm *vm, size_t nargs) { - json_object *obj = uc_get_arg(0); - json_object *arr; + uc_value_t *obj = uc_get_arg(0); + uc_value_t *arr; - if (!json_object_is_type(obj, json_type_object)) + if (ucv_type(obj) != UC_OBJECT) return NULL; - arr = xjs_new_array(); + arr = ucv_array_new(vm); - json_object_object_foreach(obj, key, val) { + ucv_object_foreach(obj, key, val) { (void)key; - json_object_array_add(arr, uc_value_get(val)); + ucv_array_push(arr, ucv_get(val)); } return arr; } -static json_object * +static uc_value_t * uc_trim_common(uc_vm *vm, size_t nargs, bool start, bool end) { - json_object *str = uc_get_arg(0); - json_object *chr = uc_get_arg(1); + uc_value_t *str = uc_get_arg(0); + uc_value_t *chr = uc_get_arg(1); const char *p, *c; size_t len; - if (!json_object_is_type(str, json_type_string) || - (chr != NULL && !json_object_is_type(chr, json_type_string))) + if (ucv_type(str) != UC_STRING || + (chr != NULL && ucv_type(chr) != UC_STRING)) return NULL; - c = json_object_get_string(chr); + c = ucv_string_get(chr); c = c ? c : " \t\r\n"; - p = json_object_get_string(str); - len = json_object_get_string_len(str); + p = ucv_string_get(str); + len = ucv_string_length(str); if (start) { while (*p) { @@ -1293,47 +1163,45 @@ uc_trim_common(uc_vm *vm, size_t nargs, bool start, bool end) } } - return xjs_new_string_len(p, len); + return ucv_string_new_length(p, len); } -static json_object * +static uc_value_t * uc_trim(uc_vm *vm, size_t nargs) { return uc_trim_common(vm, nargs, true, true); } -static json_object * +static uc_value_t * uc_ltrim(uc_vm *vm, size_t nargs) { return uc_trim_common(vm, nargs, true, false); } -static json_object * +static uc_value_t * uc_rtrim(uc_vm *vm, size_t nargs) { return uc_trim_common(vm, nargs, false, true); } -static size_t -uc_printf_common(uc_vm *vm, size_t nargs, char **res) +static void +uc_printf_common(uc_vm *vm, size_t nargs, uc_stringbuf_t *buf) { - json_object *fmt = uc_get_arg(0); + uc_value_t *fmt = uc_get_arg(0); char *fp, sfmt[sizeof("%0- 123456789.123456789%")]; - union { const char *s; int64_t n; double d; } arg; + union { char *s; int64_t n; double d; } arg; const char *fstr, *last, *p; - size_t len = 0, argidx = 1; - enum json_type t; - - *res = NULL; + uc_type_t t = UC_NULL; + size_t argidx = 1; - if (json_object_is_type(fmt, json_type_string)) - fstr = json_object_get_string(fmt); + if (ucv_type(fmt) == UC_STRING) + fstr = ucv_string_get(fmt); else fstr = ""; for (last = p = fstr; *p; p++) { if (*p == '%') { - snprintf_append(res, &len, "%s", p - last, last); + ucv_stringbuf_addstr(buf, last, p - last); last = p++; @@ -1405,7 +1273,7 @@ uc_printf_common(uc_vm *vm, size_t nargs, char **res) case 'u': case 'x': case 'X': - t = json_type_int; + t = UC_INTEGER; if (argidx < nargs) arg.n = uc_cast_int64(uc_get_arg(argidx++)); @@ -1420,7 +1288,7 @@ uc_printf_common(uc_vm *vm, size_t nargs, char **res) case 'F': case 'g': case 'G': - t = json_type_double; + t = UC_DOUBLE; if (argidx < nargs) arg.d = uc_cast_double(uc_get_arg(argidx++)); @@ -1430,7 +1298,7 @@ uc_printf_common(uc_vm *vm, size_t nargs, char **res) break; case 'c': - t = json_type_int; + t = UC_INTEGER; if (argidx < nargs) arg.n = uc_cast_int64(uc_get_arg(argidx++)) & 0xff; @@ -1440,33 +1308,31 @@ uc_printf_common(uc_vm *vm, size_t nargs, char **res) break; case 's': - t = json_type_string; + t = UC_STRING; if (argidx < nargs) - arg.s = json_object_get_string(uc_get_arg(argidx++)); + arg.s = ucv_to_string(vm, uc_get_arg(argidx++)); else arg.s = NULL; - arg.s = arg.s ? arg.s : "(null)"; + arg.s = arg.s ? arg.s : xstrdup("(null)"); break; case 'J': - t = json_type_string; + t = UC_STRING; if (argidx < nargs) - arg.s = json_object_to_json_string_ext( - uc_get_arg(argidx++), - JSON_C_TO_STRING_SPACED|JSON_C_TO_STRING_NOSLASHESCAPE|JSON_C_TO_STRING_STRICT); + arg.s = ucv_to_jsonstring(vm, uc_get_arg(argidx++)); else arg.s = NULL; - arg.s = arg.s ? arg.s : "null"; + arg.s = arg.s ? arg.s : xstrdup("null"); break; case '%': - t = json_type_null; + t = UC_NULL; break; @@ -1477,66 +1343,70 @@ uc_printf_common(uc_vm *vm, size_t nargs, char **res) if (fp + 2 >= sfmt + sizeof(sfmt)) goto next; - *fp++ = (t == json_type_string) ? 's' : *p; + *fp++ = (t == UC_STRING) ? 's' : *p; *fp = 0; -#pragma GCC diagnostic ignored "-Wformat-security" - switch (t) { - case json_type_int: sprintf_append(res, &len, sfmt, arg.n); break; - case json_type_double: sprintf_append(res, &len, sfmt, arg.d); break; - case json_type_string: sprintf_append(res, &len, sfmt, arg.s); break; - default: sprintf_append(res, &len, sfmt); break; - } + case UC_INTEGER: + ucv_stringbuf_printf(buf, sfmt, arg.n); + break; -#pragma GCC diagnostic pop + case UC_DOUBLE: + ucv_stringbuf_printf(buf, sfmt, arg.d); + break; + + case UC_STRING: + ucv_stringbuf_printf(buf, sfmt, arg.s); + break; + + default: + ucv_stringbuf_addstr(buf, sfmt, strlen(sfmt)); + break; + } last = p + 1; next: + if (t == UC_STRING) + free(arg.s); + continue; } } - snprintf_append(res, &len, "%s", p - last, last); - - return len; + ucv_stringbuf_addstr(buf, last, p - last); } -static json_object * +static uc_value_t * uc_sprintf(uc_vm *vm, size_t nargs) { - json_object *rv; - char *str = NULL; - size_t len; - - len = uc_printf_common(vm, nargs, &str); - rv = xjs_new_string_len(str, len); + uc_stringbuf_t *buf = ucv_stringbuf_new(); - free(str); + uc_printf_common(vm, nargs, buf); - return rv; + return ucv_stringbuf_finish(buf); } -static json_object * +static uc_value_t * uc_printf(uc_vm *vm, size_t nargs) { - char *str = NULL; + uc_stringbuf_t *buf = xprintbuf_new(); size_t len; - len = uc_printf_common(vm, nargs, &str); - len = fwrite(str, 1, len, stdout); + uc_printf_common(vm, nargs, buf); - free(str); + len = fwrite(buf->buf, 1, printbuf_length(buf), stdout); - return xjs_new_int64(len); + printbuf_free(buf); + + return ucv_int64_new(len); } static bool -uc_require_so(uc_vm *vm, const char *path, json_object **res) +uc_require_so(uc_vm *vm, const char *path, uc_value_t **res) { - void (*init)(const uc_ops *, uc_prototype *); - uc_prototype *scope; + void (*init)(uc_value_t *); + uc_value_t *scope; struct stat st; void *dlh; @@ -1562,22 +1432,22 @@ uc_require_so(uc_vm *vm, const char *path, json_object **res) return true; } - scope = uc_prototype_new(NULL); + scope = ucv_object_new(vm); - init(&uc, scope); + init(scope); - *res = scope->header.jso; + *res = scope; return true; } static bool -uc_require_ucode(uc_vm *vm, const char *path, uc_prototype *scope, json_object **res) +uc_require_ucode(uc_vm *vm, const char *path, uc_value_t *scope, uc_value_t **res) { uc_exception_type_t extype; - uc_prototype *prev_scope; - uc_function *function; - uc_closure *closure; + uc_function_t *function; + uc_value_t *prev_scope; + uc_value_t *closure; uc_source *source; struct stat st; char *err; @@ -1606,9 +1476,9 @@ uc_require_ucode(uc_vm *vm, const char *path, uc_prototype *scope, json_object * return true; } - closure = uc_closure_new(function, false); + closure = ucv_closure_new(vm, function, false); - uc_vm_stack_push(vm, closure->header.jso); + uc_vm_stack_push(vm, closure); prev_scope = vm->globals; vm->globals = scope ? scope : prev_scope; @@ -1626,11 +1496,10 @@ uc_require_ucode(uc_vm *vm, const char *path, uc_prototype *scope, json_object * } static bool -uc_require_path(uc_vm *vm, const char *path_template, const char *name, json_object **res) +uc_require_path(uc_vm *vm, const char *path_template, const char *name, uc_value_t **res) { + uc_stringbuf_t *buf = xprintbuf_new(); const char *p, *q, *last; - char *path = NULL; - size_t plen = 0; bool rv = false; *res = NULL; @@ -1640,12 +1509,16 @@ uc_require_path(uc_vm *vm, const char *path_template, const char *name, json_obj if (!p) goto invalid; - snprintf_append(&path, &plen, "%s", p - path_template, path_template); + ucv_stringbuf_addstr(buf, path_template, p - path_template); for (q = last = name;; q++) { if (*q == '.' || *q == '\0') { - snprintf_append(&path, &plen, "%s", q - last, last); - sprintf_append(&path, &plen, "%s", *q ? "/" : ++p); + ucv_stringbuf_addstr(buf, last, q - last); + + if (*q) + ucv_stringbuf_append(buf, "/"); + else + ucv_stringbuf_addstr(buf, p + 1, strlen(p + 1)); if (*q == '\0') break; @@ -1657,45 +1530,45 @@ uc_require_path(uc_vm *vm, const char *path_template, const char *name, json_obj } } - if (!strcmp(p, ".so")) - rv = uc_require_so(vm, path, res); - else if (!strcmp(p, ".uc")) - rv = uc_require_ucode(vm, path, NULL, res); + if (!strcmp(p + 1, ".so")) + rv = uc_require_so(vm, buf->buf, res); + else if (!strcmp(p + 1, ".uc")) + rv = uc_require_ucode(vm, buf->buf, NULL, res); invalid: - free(path); + printbuf_free(buf); return rv; } -static json_object * +static uc_value_t * uc_require(uc_vm *vm, size_t nargs) { - json_object *val = uc_get_arg(0); - json_object *search, *se, *res; + uc_value_t *val = uc_get_arg(0); + uc_value_t *search, *se, *res; size_t arridx, arrlen; const char *name; - if (!json_object_is_type(val, json_type_string)) + if (ucv_type(val) != UC_STRING) return NULL; - name = json_object_get_string(val); - search = uc_prototype_lookup(vm->globals, "REQUIRE_SEARCH_PATH"); + name = ucv_string_get(val); + search = ucv_property_get(vm->globals, "REQUIRE_SEARCH_PATH"); - if (!json_object_is_type(search, json_type_array)) { + if (ucv_type(search) != UC_ARRAY) { uc_vm_raise_exception(vm, EXCEPTION_RUNTIME, "Global require search path not set"); return NULL; } - for (arridx = 0, arrlen = json_object_array_length(search); arridx < arrlen; arridx++) { - se = json_object_array_get_idx(search, arridx); + for (arridx = 0, arrlen = ucv_array_length(search); arridx < arrlen; arridx++) { + se = ucv_array_get(search, arridx); - if (!json_object_is_type(se, json_type_string)) + if (ucv_type(se) != UC_STRING) continue; - if (uc_require_path(vm, json_object_get_string(se), name, &res)) + if (uc_require_path(vm, ucv_string_get(se), name, &res)) return res; } @@ -1705,11 +1578,11 @@ uc_require(uc_vm *vm, size_t nargs) return NULL; } -static json_object * +static uc_value_t * uc_iptoarr(uc_vm *vm, size_t nargs) { - json_object *ip = uc_get_arg(0); - json_object *res; + uc_value_t *ip = uc_get_arg(0); + uc_value_t *res; union { uint8_t u8[4]; struct in_addr in; @@ -1717,24 +1590,24 @@ uc_iptoarr(uc_vm *vm, size_t nargs) } a; int i; - if (!json_object_is_type(ip, json_type_string)) + if (ucv_type(ip) != UC_STRING) return NULL; - if (inet_pton(AF_INET6, json_object_get_string(ip), &a)) { - res = xjs_new_array(); + if (inet_pton(AF_INET6, ucv_string_get(ip), &a)) { + res = ucv_array_new(vm); for (i = 0; i < 16; i++) - json_object_array_add(res, xjs_new_int64(a.in6.s6_addr[i])); + ucv_array_push(res, ucv_int64_new(a.in6.s6_addr[i])); return res; } - else if (inet_pton(AF_INET, json_object_get_string(ip), &a)) { - res = xjs_new_array(); + else if (inet_pton(AF_INET, ucv_string_get(ip), &a)) { + res = ucv_array_new(vm); - json_object_array_add(res, xjs_new_int64(a.u8[0])); - json_object_array_add(res, xjs_new_int64(a.u8[1])); - json_object_array_add(res, xjs_new_int64(a.u8[2])); - json_object_array_add(res, xjs_new_int64(a.u8[3])); + ucv_array_push(res, ucv_int64_new(a.u8[0])); + ucv_array_push(res, ucv_int64_new(a.u8[1])); + ucv_array_push(res, ucv_int64_new(a.u8[2])); + ucv_array_push(res, ucv_int64_new(a.u8[3])); return res; } @@ -1743,14 +1616,14 @@ uc_iptoarr(uc_vm *vm, size_t nargs) } static int -check_byte(json_object *v) +check_byte(uc_value_t *v) { int n; - if (!json_object_is_type(v, json_type_int)) + if (ucv_type(v) != UC_INTEGER) return -1; - n = json_object_get_int(v); + n = ucv_int64_get(v); if (n < 0 || n > 255) return -1; @@ -1758,10 +1631,10 @@ check_byte(json_object *v) return n; } -static json_object * +static uc_value_t * uc_arrtoip(uc_vm *vm, size_t nargs) { - json_object *arr = uc_get_arg(0); + uc_value_t *arr = uc_get_arg(0); union { uint8_t u8[4]; struct in6_addr in6; @@ -1769,13 +1642,13 @@ uc_arrtoip(uc_vm *vm, size_t nargs) char buf[INET6_ADDRSTRLEN]; int i, n; - if (!json_object_is_type(arr, json_type_array)) + if (ucv_type(arr) != UC_ARRAY) return NULL; - switch (json_object_array_length(arr)) { + switch (ucv_array_length(arr)) { case 4: for (i = 0; i < 4; i++) { - n = check_byte(json_object_array_get_idx(arr, i)); + n = check_byte(ucv_array_get(arr, i)); if (n < 0) return NULL; @@ -1785,11 +1658,11 @@ uc_arrtoip(uc_vm *vm, size_t nargs) inet_ntop(AF_INET, &a, buf, sizeof(buf)); - return xjs_new_string(buf); + return ucv_string_new(buf); case 16: for (i = 0; i < 16; i++) { - n = check_byte(json_object_array_get_idx(arr, i)); + n = check_byte(ucv_array_get(arr, i)); if (n < 0) return NULL; @@ -1799,49 +1672,51 @@ uc_arrtoip(uc_vm *vm, size_t nargs) inet_ntop(AF_INET6, &a, buf, sizeof(buf)); - return xjs_new_string(buf); + return ucv_string_new(buf); default: return NULL; } } -static json_object * +static uc_value_t * uc_match(uc_vm *vm, size_t nargs) { - json_object *subject = uc_get_arg(0); - json_object *pattern = uc_get_arg(1); - json_object *rv = NULL, *m; - int eflags = 0, res, i; + uc_value_t *subject = uc_get_arg(0); + uc_value_t *pattern = uc_get_arg(1); + uc_value_t *rv = NULL, *m; regmatch_t pmatch[10]; - uc_regexp *re; - const char *p; + int eflags = 0, res; + uc_regexp_t *re; + bool freeable; + char *p; + size_t i; - if (!uc_object_is_type(pattern, UC_OBJ_REGEXP) || !subject) + if (ucv_type(pattern) != UC_REGEXP || !subject) return NULL; - p = json_object_get_string(subject); - re = uc_object_as_regexp(pattern); + p = uc_cast_string(vm, &subject, &freeable); + re = (uc_regexp_t *)pattern; while (true) { - res = regexec(&re->re, p, ARRAY_SIZE(pmatch), pmatch, eflags); + res = regexec(&re->regexp, p, ARRAY_SIZE(pmatch), pmatch, eflags); if (res == REG_NOMATCH) break; - m = xjs_new_array(); + m = ucv_array_new(vm); for (i = 0; i < ARRAY_SIZE(pmatch) && pmatch[i].rm_so != -1; i++) { - json_object_array_add(m, - xjs_new_string_len(p + pmatch[i].rm_so, - pmatch[i].rm_eo - pmatch[i].rm_so)); + ucv_array_push(m, + ucv_string_new_length(p + pmatch[i].rm_so, + pmatch[i].rm_eo - pmatch[i].rm_so)); } if (re->global) { if (!rv) - rv = xjs_new_array(); + rv = ucv_array_new(vm); - json_object_array_add(rv, m); + ucv_array_push(rv, m); p += pmatch[0].rm_eo; eflags |= REG_NOTBOL; @@ -1852,24 +1727,27 @@ uc_match(uc_vm *vm, size_t nargs) } } + if (freeable) + free(p); + return rv; } -static json_object * -uc_replace_cb(uc_vm *vm, json_object *func, +static uc_value_t * +uc_replace_cb(uc_vm *vm, uc_value_t *func, const char *subject, regmatch_t *pmatch, size_t plen, - char **sp, size_t *sl) + uc_stringbuf_t *resbuf) { - json_object *rv; + uc_value_t *rv; size_t i; /* XXX: revisit leaks */ - uc_vm_stack_push(vm, uc_value_get(func)); + uc_vm_stack_push(vm, ucv_get(func)); for (i = 0; i < plen && pmatch[i].rm_so != -1; i++) { uc_vm_stack_push(vm, - xjs_new_string_len(subject + pmatch[i].rm_so, - pmatch[i].rm_eo - pmatch[i].rm_so)); + ucv_string_new_length(subject + pmatch[i].rm_so, + pmatch[i].rm_eo - pmatch[i].rm_so)); } if (uc_vm_call(vm, false, i)) @@ -1877,39 +1755,42 @@ uc_replace_cb(uc_vm *vm, json_object *func, rv = uc_vm_stack_pop(vm); - sprintf_append(sp, sl, "%s", rv ? json_object_get_string(rv) : "null"); + ucv_to_stringbuf(vm, resbuf, rv, false); - uc_value_put(rv); + ucv_put(rv); return NULL; } static void -uc_replace_str(uc_vm *vm, json_object *str, +uc_replace_str(uc_vm *vm, uc_value_t *str, const char *subject, regmatch_t *pmatch, size_t plen, - char **sp, size_t *sl) + uc_stringbuf_t *resbuf) { - const char *p, *r = str ? json_object_get_string(str) : "null"; bool esc = false; - int i; + char *p, *r; + uint8_t i; - for (p = r; *p; p++) { + for (p = r = ucv_to_string(vm, str); *p; p++) { if (esc) { switch (*p) { case '&': if (pmatch[0].rm_so != -1) - snprintf_append(sp, sl, "%s", pmatch[0].rm_eo - pmatch[0].rm_so, - subject + pmatch[0].rm_so); + ucv_stringbuf_addstr(resbuf, + subject + pmatch[0].rm_so, + pmatch[0].rm_eo - pmatch[0].rm_so); break; case '`': if (pmatch[0].rm_so != -1) - snprintf_append(sp, sl, "%s", pmatch[0].rm_so, subject); + ucv_stringbuf_addstr(resbuf, subject, pmatch[0].rm_so); break; case '\'': if (pmatch[0].rm_so != -1) - sprintf_append(sp, sl, "%s", subject + pmatch[0].rm_eo); + ucv_stringbuf_addstr(resbuf, + subject + pmatch[0].rm_eo, + strlen(subject + pmatch[0].rm_eo)); break; case '1': @@ -1922,19 +1803,24 @@ uc_replace_str(uc_vm *vm, json_object *str, case '8': case '9': i = *p - '0'; - if (i < plen && pmatch[i].rm_so != -1) - snprintf_append(sp, sl, "%s", pmatch[i].rm_eo - pmatch[i].rm_so, - subject + pmatch[i].rm_so); - else - sprintf_append(sp, sl, "$%c", *p); + if (i < plen && pmatch[i].rm_so != -1) { + ucv_stringbuf_addstr(resbuf, + subject + pmatch[i].rm_so, + pmatch[i].rm_eo - pmatch[i].rm_so); + } + else { + ucv_stringbuf_append(resbuf, "$"); + ucv_stringbuf_addstr(resbuf, p, 1); + } break; case '$': - sprintf_append(sp, sl, "$"); + ucv_stringbuf_append(resbuf, "$"); break; default: - sprintf_append(sp, sl, "$%c", *p); + ucv_stringbuf_append(resbuf, "$"); + ucv_stringbuf_addstr(resbuf, p, 1); } esc = false; @@ -1943,51 +1829,58 @@ uc_replace_str(uc_vm *vm, json_object *str, esc = true; } else { - sprintf_append(sp, sl, "%c", *p); + ucv_stringbuf_addstr(resbuf, p, 1); } } + + free(r); } -static json_object * +static uc_value_t * uc_replace(uc_vm *vm, size_t nargs) { - json_object *subject = uc_get_arg(0); - json_object *pattern = uc_get_arg(1); - json_object *replace = uc_get_arg(2); - json_object *rv = NULL; - const char *sb, *p, *l; + char *sb = NULL, *pt = NULL, *p, *l; + uc_value_t *subject = uc_get_arg(0); + uc_value_t *pattern = uc_get_arg(1); + uc_value_t *replace = uc_get_arg(2); + bool sb_freeable, pt_freeable; + uc_value_t *rv = NULL; + uc_stringbuf_t *resbuf; regmatch_t pmatch[10]; int eflags = 0, res; - size_t sl = 0, pl; - char *sp = NULL; - uc_regexp *re; + uc_regexp_t *re; + size_t pl; if (!pattern || !subject || !replace) return NULL; - if (uc_object_is_type(pattern, UC_OBJ_REGEXP)) { - p = json_object_get_string(subject); - re = uc_object_as_regexp(pattern); + sb = uc_cast_string(vm, &subject, &sb_freeable); + resbuf = ucv_stringbuf_new(); + + if (ucv_type(pattern) == UC_REGEXP) { + re = (uc_regexp_t *)pattern; + p = sb; while (true) { - res = regexec(&re->re, p, ARRAY_SIZE(pmatch), pmatch, eflags); + res = regexec(&re->regexp, p, ARRAY_SIZE(pmatch), pmatch, eflags); if (res == REG_NOMATCH) break; - snprintf_append(&sp, &sl, "%s", pmatch[0].rm_so, p); + ucv_stringbuf_addstr(resbuf, p, pmatch[0].rm_so); - if (uc_object_is_callable(replace)) { - rv = uc_replace_cb(vm, replace, p, pmatch, ARRAY_SIZE(pmatch), &sp, &sl); + if (ucv_is_callable(replace)) { + rv = uc_replace_cb(vm, replace, p, pmatch, ARRAY_SIZE(pmatch), resbuf); if (rv) { - free(sp); + if (sb_freeable) + free(sb); return rv; } } else { - uc_replace_str(vm, replace, p, pmatch, ARRAY_SIZE(pmatch), &sp, &sl); + uc_replace_str(vm, replace, p, pmatch, ARRAY_SIZE(pmatch), resbuf); } p += pmatch[0].rm_eo; @@ -1998,57 +1891,64 @@ uc_replace(uc_vm *vm, size_t nargs) break; } - sprintf_append(&sp, &sl, "%s", p); + ucv_stringbuf_addstr(resbuf, p, strlen(p)); } else { - sb = json_object_get_string(subject); - p = json_object_get_string(pattern); - pl = strlen(p); + pt = uc_cast_string(vm, &pattern, &pt_freeable); + pl = strlen(pt); - for (l = sb; *sb; sb++) { - if (!strncmp(sb, p, pl)) { - snprintf_append(&sp, &sl, "%s", sb - l, l); + for (l = p = sb; *p; p++) { + if (!strncmp(p, pt, pl)) { + ucv_stringbuf_addstr(resbuf, l, p - l); - pmatch[0].rm_so = sb - l; + pmatch[0].rm_so = p - l; pmatch[0].rm_eo = pmatch[0].rm_so + pl; - if (uc_object_is_callable(replace)) { - rv = uc_replace_cb(vm, replace, l, pmatch, 1, &sp, &sl); + if (ucv_is_callable(replace)) { + rv = uc_replace_cb(vm, replace, l, pmatch, 1, resbuf); if (rv) { - free(sp); + if (sb_freeable) + free(sb); + + if (pt_freeable) + free(pt); return rv; } } else { - uc_replace_str(vm, replace, l, pmatch, 1, &sp, &sl); + uc_replace_str(vm, replace, l, pmatch, 1, resbuf); } - l = sb + pl; - sb += pl - 1; + l = p + pl; + p += pl - 1; } } - sprintf_append(&sp, &sl, "%s", l); + ucv_stringbuf_addstr(resbuf, l, strlen(l)); + + if (pt_freeable) + free(pt); } - rv = xjs_new_string_len(sp, sl); - free(sp); + if (sb_freeable) + free(sb); - return rv; + return ucv_stringbuf_finish(resbuf); } -static json_object * +static uc_value_t * uc_json(uc_vm *vm, size_t nargs) { - json_object *rv, *src = uc_get_arg(0); + uc_value_t *rv, *src = uc_get_arg(0); struct json_tokener *tok = NULL; enum json_tokener_error err; + json_object *jso; const char *str; size_t len; - if (!json_object_is_type(src, json_type_string)) { + if (ucv_type(src) != UC_STRING) { uc_vm_raise_exception(vm, EXCEPTION_TYPE, "Passed value is not a string"); @@ -2056,24 +1956,24 @@ uc_json(uc_vm *vm, size_t nargs) } tok = xjs_new_tokener(); - str = json_object_get_string(src); - len = json_object_get_string_len(src); + str = ucv_string_get(src); + len = ucv_string_length(src); /* NB: the len + 1 here is intentional to pass the terminating \0 byte * to the json-c parser. This is required to work-around upstream * issue #681 <https://github.com/json-c/json-c/issues/681> */ - rv = json_tokener_parse_ex(tok, str, len + 1); + jso = json_tokener_parse_ex(tok, str, len + 1); err = json_tokener_get_error(tok); if (err == json_tokener_continue) { - uc_value_put(rv); + json_object_put(jso); uc_vm_raise_exception(vm, EXCEPTION_SYNTAX, "Unexpected end of string in JSON data"); return NULL; } else if (err != json_tokener_success) { - uc_value_put(rv); + json_object_put(jso); uc_vm_raise_exception(vm, EXCEPTION_SYNTAX, "Failed to parse JSON string: %s", json_tokener_error_desc(err)); @@ -2081,7 +1981,7 @@ uc_json(uc_vm *vm, size_t nargs) return NULL; } else if (json_tokener_get_parse_end(tok) < len) { - uc_value_put(rv); + json_object_put(jso); uc_vm_raise_exception(vm, EXCEPTION_SYNTAX, "Trailing garbage after JSON data"); @@ -2090,6 +1990,10 @@ uc_json(uc_vm *vm, size_t nargs) json_tokener_free(tok); + rv = ucv_from_json(vm, jso); + + json_object_put(jso); + return rv; } @@ -2126,26 +2030,24 @@ include_path(const char *curpath, const char *incpath) return dup; } -static json_object * +static uc_value_t * uc_include(uc_vm *vm, size_t nargs) { - json_object *path = uc_get_arg(0); - json_object *scope = uc_get_arg(1); - json_object *rv = NULL; - uc_closure *closure = NULL; - uc_prototype *sc; - bool put = false; + uc_value_t *path = uc_get_arg(0); + uc_value_t *scope = uc_get_arg(1); + uc_value_t *rv = NULL, *sc = NULL; + uc_closure_t *closure = NULL; size_t i; char *p; - if (!json_object_is_type(path, json_type_string)) { + if (ucv_type(path) != UC_STRING) { uc_vm_raise_exception(vm, EXCEPTION_TYPE, "Passed filename is not a string"); return NULL; } - if (scope && !json_object_is_type(scope, json_type_object)) { + if (scope && ucv_type(scope) != UC_OBJECT) { uc_vm_raise_exception(vm, EXCEPTION_TYPE, "Passed scope value is not an object"); @@ -2163,7 +2065,7 @@ uc_include(uc_vm *vm, size_t nargs) if (!closure) return NULL; - p = include_path(closure->function->source->filename, json_object_get_string(path)); + p = include_path(closure->function->source->filename, ucv_string_get(path)); if (!p) { uc_vm_raise_exception(vm, EXCEPTION_RUNTIME, @@ -2172,68 +2074,67 @@ uc_include(uc_vm *vm, size_t nargs) return NULL; } - if (uc_object_is_type(scope, UC_OBJ_PROTOTYPE)) { - sc = uc_object_as_prototype(scope); + if (ucv_prototype_get(scope)) { + sc = ucv_get(scope); } else if (scope) { - sc = uc_prototype_new(vm->globals); - put = true; + sc = ucv_object_new(vm); + + ucv_object_foreach(scope, key, val) + ucv_object_add(sc, key, ucv_get(val)); - json_object_object_foreach(scope, key, val) - json_object_object_add(sc->header.jso, key, uc_value_get(val)); + ucv_prototype_set(sc, ucv_get(vm->globals)); } else { - sc = vm->globals; + sc = ucv_get(vm->globals); } if (uc_require_ucode(vm, p, sc, &rv)) - uc_value_put(rv); + ucv_put(rv); + ucv_put(sc); free(p); - if (put) - uc_value_put(sc->header.jso); - return NULL; } -static json_object * +static uc_value_t * uc_warn(uc_vm *vm, size_t nargs) { return uc_print_common(vm, nargs, stderr); } -static json_object * +static uc_value_t * uc_system(uc_vm *vm, size_t nargs) { - json_object *cmdline = uc_get_arg(0); - json_object *timeout = uc_get_arg(1); - const char **arglist, *fn, *s; + uc_value_t *cmdline = uc_get_arg(0); + uc_value_t *timeout = uc_get_arg(1); + const char **arglist, *fn; sigset_t sigmask, sigomask; struct timespec ts; + size_t i, len; int64_t tms; - int rc, len; pid_t cld; - size_t i; + int rc; - if (timeout && (!json_object_is_type(timeout, json_type_int) || json_object_get_int64(timeout) < 0)) { + if (timeout && (ucv_type(timeout) != UC_INTEGER || ucv_int64_get(timeout) < 0)) { uc_vm_raise_exception(vm, EXCEPTION_TYPE, "Invalid timeout specified"); return NULL; } - switch (json_object_get_type(cmdline)) { - case json_type_string: + switch (ucv_type(cmdline)) { + case UC_STRING: arglist = xalloc(sizeof(*arglist) * 4); arglist[0] = "/bin/sh"; arglist[1] = "-c"; - arglist[2] = json_object_get_string(cmdline); + arglist[2] = ucv_string_get(cmdline); arglist[3] = NULL; break; - case json_type_array: - len = json_object_array_length(cmdline); + case UC_ARRAY: + len = ucv_array_length(cmdline); if (len == 0) { uc_vm_raise_exception(vm, EXCEPTION_TYPE, @@ -2244,10 +2145,8 @@ uc_system(uc_vm *vm, size_t nargs) arglist = xalloc(sizeof(*arglist) * (len + 1)); - for (i = 0; i < len; i++) { - s = json_object_get_string(json_object_array_get_idx(cmdline, i)); - arglist[i] = s ? s : "null"; - } + for (i = 0; i < len; i++) + arglist[i] = ucv_to_string(vm, ucv_array_get(cmdline, i)); arglist[i] = NULL; @@ -2260,7 +2159,7 @@ uc_system(uc_vm *vm, size_t nargs) return NULL; } - tms = timeout ? json_object_get_int64(timeout) : 0; + tms = timeout ? ucv_int64_get(timeout) : 0; if (tms > 0) { sigemptyset(&sigmask); @@ -2315,14 +2214,17 @@ uc_system(uc_vm *vm, size_t nargs) if (tms > 0) sigprocmask(SIG_SETMASK, &sigomask, NULL); + for (i = 0; arglist[i]; i++) + free((char *)arglist[i]); + free(arglist); if (WIFEXITED(rc)) - return xjs_new_int64(WEXITSTATUS(rc)); + return ucv_int64_new(WEXITSTATUS(rc)); else if (WIFSIGNALED(rc)) - return xjs_new_int64(-WTERMSIG(rc)); + return ucv_int64_new(-WTERMSIG(rc)); else if (WIFSTOPPED(rc)) - return xjs_new_int64(-WSTOPSIG(rc)); + return ucv_int64_new(-WSTOPSIG(rc)); return NULL; } @@ -2331,6 +2233,9 @@ fail: if (tms > 0) sigprocmask(SIG_SETMASK, &sigomask, NULL); + for (i = 0; arglist[i]; i++) + free((char *)arglist[i]); + free(arglist); uc_vm_raise_exception(vm, EXCEPTION_RUNTIME, @@ -2339,95 +2244,61 @@ fail: return NULL; } -static json_object * +static uc_value_t * uc_trace(uc_vm *vm, size_t nargs) { - json_object *level = uc_get_arg(0); + uc_value_t *level = uc_get_arg(0); uint8_t prev_level; - if (!json_object_is_type(level, json_type_int)) { + if (ucv_type(level) != UC_INTEGER) { uc_vm_raise_exception(vm, EXCEPTION_TYPE, "Invalid level specified"); return NULL; } prev_level = vm->trace; - vm->trace = json_object_get_int64(level); + vm->trace = ucv_int64_get(level); - return xjs_new_int64(prev_level); + return ucv_int64_new(prev_level); } -static json_object * +static uc_value_t * uc_proto(uc_vm *vm, size_t nargs) { - json_object *val = uc_get_arg(0); - json_object *proto = NULL; - uc_prototype *p, *ref; - - if (nargs < 2) { - switch (uc_object_type(val)) { - case UC_OBJ_PROTOTYPE: - p = uc_object_as_prototype(val)->parent; + uc_value_t *val = uc_get_arg(0); + uc_value_t *proto = NULL; - return p ? uc_value_get(p->header.jso) : NULL; - - case UC_OBJ_RESSOURCE: - p = uc_ressource_prototype(val); - - return p ? uc_value_get(p->header.jso) : NULL; - - default: - return NULL; - } - } + if (nargs < 2) + return ucv_get(ucv_prototype_get(val)); proto = uc_get_arg(1); - switch (uc_object_type(proto)) { - case UC_OBJ_PROTOTYPE: - p = uc_object_as_prototype(proto); - break; - - case UC_OBJ_RESSOURCE: - p = uc_ressource_prototype(proto); - break; - - default: - switch (json_object_get_type(proto)) { - case json_type_object: - p = uc_protoref_new(proto, NULL); - break; - - default: - uc_vm_raise_exception(vm, EXCEPTION_TYPE, "Passed value is neither a prototype, ressource or object"); - - return NULL; - } - } + if (!ucv_prototype_set(val, proto)) + uc_vm_raise_exception(vm, EXCEPTION_TYPE, "Passed value is neither a prototype, ressource or object"); - ref = uc_protoref_new(val, p); + ucv_get(proto); - return ref ? uc_value_get(ref->header.jso) : NULL; + return ucv_get(val); } -static json_object * +static uc_value_t * uc_sleep(uc_vm *vm, size_t nargs) { - json_object *duration = uc_get_arg(0); + uc_value_t *duration = uc_get_arg(0); struct timeval tv; int64_t ms; ms = uc_cast_int64(duration); if (errno != 0 || ms <= 0) - return xjs_new_boolean(false); + return ucv_boolean_new(false); tv.tv_sec = ms / 1000; tv.tv_usec = (ms % 1000) * 1000; select(0, NULL, NULL, NULL, &tv); - return xjs_new_boolean(true); + return ucv_boolean_new(true); } static const uc_cfunction_list functions[] = { @@ -2484,7 +2355,7 @@ static const uc_cfunction_list functions[] = { void -uc_lib_init(uc_prototype *scope) +uc_lib_init(uc_value_t *scope) { uc_add_proto_functions(scope, functions); } @@ -19,185 +19,106 @@ #include "vm.h" #include "lexer.h" -#include "object.h" typedef struct { const char *name; - uc_cfn_ptr func; + uc_cfn_ptr_t func; } uc_cfunction_list; -typedef struct { - /* value operations */ - struct { - uc_prototype *(*proto)(uc_prototype *); - uc_cfunction *(*cfunc)(const char *, uc_cfn_ptr); - json_object *(*dbl)(double); - uc_regexp *(*regexp)(const char *, bool, bool, bool, char **); - uc_ressource *(*ressource)(json_object *, uc_ressource_type *, void *); - enum json_type (*tonumber)(json_object *, int64_t *, double *); - } value; - - /* ressource operations */ - struct { - uc_ressource_type *(*define)(const char *, uc_prototype *, void (*)(void *)); - uc_ressource *(*create)(json_object *, uc_ressource_type *, void *); - void **(*data)(json_object *, const char *); - uc_prototype *(*proto)(json_object *); - } ressource; - - /* VM operations */ - struct { - uc_exception_type_t (*call)(uc_vm *, bool, size_t); - json_object *(*peek)(uc_vm *, size_t); - json_object *(*pop)(uc_vm *); - void (*push)(uc_vm *, json_object *); - void (*raise)(uc_vm *, uc_exception_type_t, const char *, ...); - } vm; -} uc_ops; - -extern const uc_ops uc; - -void uc_lib_init(uc_prototype *scope); - -void format_source_context(char **msg, size_t *msglen, uc_source *src, size_t off, bool compact); -void format_error_context(char **msg, size_t *msglen, uc_source *src, json_object *stacktrace, size_t off); +void uc_lib_init(uc_value_t *scope); + +bool format_source_context(uc_stringbuf_t *buf, uc_source *src, size_t off, bool compact); +bool format_error_context(uc_stringbuf_t *buf, uc_source *src, uc_value_t *stacktrace, size_t off); /* vm helper */ static inline void * -_uc_get_self(const uc_ops *ops, uc_vm *vm, const char *expected_type) +_uc_get_self(uc_vm *vm, const char *expected_type) { - return ops->ressource.data(vm->callframes.entries[vm->callframes.count - 1].ctx, expected_type); + return ucv_ressource_dataptr(vm->callframes.entries[vm->callframes.count - 1].ctx, expected_type); } -#define uc_get_self(...) _uc_get_self(ops, vm, __VA_ARGS__) +#define uc_get_self(...) _uc_get_self(vm, __VA_ARGS__) -static inline json_object * -_uc_get_arg(const uc_ops *ops, uc_vm *vm, size_t nargs, size_t n) +static inline uc_value_t * +_uc_get_arg(uc_vm *vm, size_t nargs, size_t n) { if (n >= nargs) return NULL; - return ops->vm.peek(vm, nargs - n - 1); + return uc_vm_stack_peek(vm, nargs - n - 1); } -#define uc_get_arg(...) _uc_get_arg(ops, vm, nargs, __VA_ARGS__) +#define uc_get_arg(...) _uc_get_arg(vm, nargs, __VA_ARGS__) -#define uc_call(nargs) ops->vm.call(vm, false, nargs) -#define uc_push_val(val) ops->vm.push(vm, val) -#define uc_pop_val() ops->vm.pop(vm) +#define uc_call(nargs) uc_vm_call(vm, false, nargs) +#define uc_push_val(val) uc_vm_stack_push(vm, val) +#define uc_pop_val() uc_vm_stack_pop(vm) /* value helper */ -static inline json_object * -_uc_alloc_proto(const uc_ops *ops, uc_prototype *parent) -{ - return ops->value.proto(parent)->header.jso; -} - -static inline json_object * -_uc_alloc_cfunc(const uc_ops *ops, const char *name, uc_cfn_ptr fptr) -{ - return ops->value.cfunc(name, fptr)->header.jso; -} - -static inline json_object * -_uc_alloc_double(const uc_ops *ops, double dbl) -{ - return ops->value.dbl(dbl); -} - -static inline json_object * -_uc_alloc_regexp(const uc_ops *ops, const char *pattern, bool global, bool icase, bool newline, char **errp) +static inline uc_value_t * +uc_alloc_ressource(uc_ressource_type_t *type, void *data) { - uc_regexp *re = ops->value.regexp(pattern, global, icase, newline, errp); - - return re ? re->header.jso : NULL; -} - -static inline json_object * -_uc_alloc_ressource(const uc_ops *ops, uc_ressource_type *type, void *data) -{ - uc_ressource *res = ops->value.ressource(xjs_new_object(), type, data); - - return res ? res->header.jso : NULL; + return ucv_ressource_new(type, data); } -#define uc_alloc_proto(...) _uc_alloc_proto(ops, __VA_ARGS__) -#define uc_alloc_cfunc(...) _uc_alloc_cfunc(ops, __VA_ARGS__) -#define uc_alloc_double(...) _uc_alloc_double(ops, __VA_ARGS__) -#define uc_alloc_regexp(...) _uc_alloc_regexp(ops, __VA_ARGS__) -#define uc_alloc_ressource(...) _uc_alloc_ressource(ops, __VA_ARGS__) - -static inline json_type -_uc_to_number(const uc_ops *ops, json_object *v, int64_t *n, double *d) +static inline uc_type_t +uc_to_number(uc_value_t *v, int64_t *n, double *d) { - return ops->value.tonumber(v, n, d); + return uc_cast_number(v, n, d); } static inline double -_uc_to_double(const uc_ops *ops, json_object *v) +uc_to_double(uc_value_t *v) { int64_t n; double d; - return (ops->value.tonumber(v, &n, &d) == json_type_double) ? d : (double)n; + return (uc_cast_number(v, &n, &d) == UC_DOUBLE) ? d : (double)n; } static inline int64_t -_uc_to_int64(const uc_ops *ops, json_object *v) +uc_to_int64(uc_value_t *v) { int64_t n; double d; - return (ops->value.tonumber(v, &n, &d) == json_type_double) ? (int64_t)d : n; + return (uc_cast_number(v, &n, &d) == UC_DOUBLE) ? (int64_t)d : n; } -#define uc_to_number(...) _uc_to_number(ops, __VA_ARGS__) -#define uc_to_double(...) _uc_to_double(ops, __VA_ARGS__) -#define uc_to_int64(...) _uc_to_int64(ops, __VA_ARGS__) - /* ressource type helper */ -static inline uc_ressource_type * -_uc_declare_type(const uc_ops *ops, const char *name, const uc_cfunction_list *list, size_t len, void (*freefn)(void *)) +static inline uc_ressource_type_t * +_uc_declare_type(const char *name, const uc_cfunction_list *list, size_t len, void (*freefn)(void *)) { - uc_prototype *proto = ops->value.proto(NULL); + uc_value_t *proto = ucv_object_new(NULL); while (len-- > 0) - json_object_object_add(proto->header.jso, list[len].name, - _uc_alloc_cfunc(ops, list[len].name, list[len].func)); + ucv_object_add(proto, list[len].name, + ucv_cfunction_new(list[len].name, list[len].func)); - return ops->ressource.define(name, proto, freefn); + return ucv_ressource_type_add(name, proto, freefn); } #define uc_declare_type(name, functions, freefn) \ - _uc_declare_type(ops, name, functions, ARRAY_SIZE(functions), freefn) + _uc_declare_type(name, functions, ARRAY_SIZE(functions), freefn) /* prototype helper */ -static inline bool -uc_add_proto_val(uc_prototype *proto, const char *key, json_object *value) -{ - if (!proto) - return false; - - return json_object_object_add(proto->header.jso, key, value); -} - static inline void -_uc_add_proto_functions(const uc_ops *ops, uc_prototype *proto, const uc_cfunction_list *list, size_t len) +_uc_add_proto_functions(uc_value_t *proto, const uc_cfunction_list *list, size_t len) { while (len-- > 0) - json_object_object_add(proto->header.jso, list[len].name, - _uc_alloc_cfunc(ops, list[len].name, list[len].func)); + ucv_object_add(proto, list[len].name, + ucv_cfunction_new(list[len].name, list[len].func)); } #define uc_add_proto_functions(proto, functions) \ - _uc_add_proto_functions(ops, proto, functions, ARRAY_SIZE(functions)) + _uc_add_proto_functions(proto, functions, ARRAY_SIZE(functions)) #endif /* __LIB_H_ */ @@ -28,29 +28,29 @@ #define err_return(err) do { last_error = err; return NULL; } while(0) //static const uc_ops *ops; -static uc_ressource_type *file_type, *proc_type, *dir_type; +static uc_ressource_type_t *file_type, *proc_type, *dir_type; static int last_error = 0; -static json_object * +static uc_value_t * uc_fs_error(uc_vm *vm, size_t nargs) { - json_object *errmsg; + uc_value_t *errmsg; if (last_error == 0) return NULL; - errmsg = json_object_new_string(strerror(last_error)); + errmsg = ucv_string_new(strerror(last_error)); last_error = 0; return errmsg; } -static json_object * +static uc_value_t * uc_fs_read_common(uc_vm *vm, size_t nargs, const char *type) { - json_object *limit = uc_get_arg(0); - json_object *rv = NULL; + uc_value_t *limit = uc_get_arg(0); + uc_value_t *rv = NULL; char buf[128], *p = NULL, *tmp; size_t rlen, len = 0; const char *lstr; @@ -61,8 +61,8 @@ uc_fs_read_common(uc_vm *vm, size_t nargs, const char *type) if (!fp || !*fp) err_return(EBADF); - if (json_object_is_type(limit, json_type_string)) { - lstr = json_object_get_string(limit); + if (ucv_type(limit) == UC_STRING) { + lstr = ucv_string_get(limit); if (!strcmp(lstr, "line")) { while (true) { @@ -110,8 +110,8 @@ uc_fs_read_common(uc_vm *vm, size_t nargs, const char *type) return NULL; } } - else if (json_object_is_type(limit, json_type_int)) { - lsize = json_object_get_int64(limit); + else if (ucv_type(limit) == UC_INTEGER) { + lsize = ucv_int64_get(limit); if (lsize <= 0) return NULL; @@ -132,43 +132,43 @@ uc_fs_read_common(uc_vm *vm, size_t nargs, const char *type) err_return(EINVAL); } - rv = json_object_new_string_len(p, len); + rv = ucv_string_new_length(p, len); free(p); return rv; } -static json_object * +static uc_value_t * uc_fs_write_common(uc_vm *vm, size_t nargs, const char *type) { - json_object *data = uc_get_arg(0); + uc_value_t *data = uc_get_arg(0); size_t len, wsize; - const char *str; + char *str; FILE **fp = uc_get_self(type); if (!fp || !*fp) err_return(EBADF); - if (json_object_is_type(data, json_type_string)) { - str = json_object_get_string(data); - len = json_object_get_string_len(data); + if (ucv_type(data) == UC_STRING) { + len = ucv_string_length(data); + wsize = fwrite(ucv_string_get(data), 1, len, *fp); } else { - str = json_object_to_json_string(data); + str = ucv_to_jsonstring(vm, data); len = str ? strlen(str) : 0; + wsize = fwrite(str, 1, len, *fp); + free(str); } - wsize = fwrite(str, 1, len, *fp); - if (wsize < len && ferror(*fp)) err_return(errno); - return json_object_new_int64(wsize); + return ucv_int64_new(wsize); } -static json_object * +static uc_value_t * uc_fs_pclose(uc_vm *vm, size_t nargs) { FILE **fp = uc_get_self("fs.proc"); @@ -184,38 +184,38 @@ uc_fs_pclose(uc_vm *vm, size_t nargs) err_return(errno); if (WIFEXITED(rc)) - return xjs_new_int64(WEXITSTATUS(rc)); + return ucv_int64_new(WEXITSTATUS(rc)); if (WIFSIGNALED(rc)) - return xjs_new_int64(-WTERMSIG(rc)); + return ucv_int64_new(-WTERMSIG(rc)); - return xjs_new_int64(0); + return ucv_int64_new(0); } -static json_object * +static uc_value_t * uc_fs_pread(uc_vm *vm, size_t nargs) { return uc_fs_read_common(vm, nargs, "fs.proc"); } -static json_object * +static uc_value_t * uc_fs_pwrite(uc_vm *vm, size_t nargs) { return uc_fs_write_common(vm, nargs, "fs.proc"); } -static json_object * +static uc_value_t * uc_fs_popen(uc_vm *vm, size_t nargs) { - json_object *comm = uc_get_arg(0); - json_object *mode = uc_get_arg(1); + uc_value_t *comm = uc_get_arg(0); + uc_value_t *mode = uc_get_arg(1); FILE *fp; - if (!json_object_is_type(comm, json_type_string)) + if (ucv_type(comm) != UC_STRING) err_return(EINVAL); - fp = popen(json_object_get_string(comm), - json_object_is_type(mode, json_type_string) ? json_object_get_string(mode) : "r"); + fp = popen(ucv_string_get(comm), + ucv_type(mode) == UC_STRING ? ucv_string_get(mode) : "r"); if (!fp) err_return(errno); @@ -224,7 +224,7 @@ uc_fs_popen(uc_vm *vm, size_t nargs) } -static json_object * +static uc_value_t * uc_fs_close(uc_vm *vm, size_t nargs) { FILE **fp = uc_get_self("fs.file"); @@ -235,26 +235,26 @@ uc_fs_close(uc_vm *vm, size_t nargs) fclose(*fp); *fp = NULL; - return json_object_new_boolean(true); + return ucv_boolean_new(true); } -static json_object * +static uc_value_t * uc_fs_read(uc_vm *vm, size_t nargs) { return uc_fs_read_common(vm, nargs, "fs.file"); } -static json_object * +static uc_value_t * uc_fs_write(uc_vm *vm, size_t nargs) { return uc_fs_write_common(vm, nargs, "fs.file"); } -static json_object * +static uc_value_t * uc_fs_seek(uc_vm *vm, size_t nargs) { - json_object *ofs = uc_get_arg(0); - json_object *how = uc_get_arg(1); + uc_value_t *ofs = uc_get_arg(0); + uc_value_t *how = uc_get_arg(1); int whence, res; long offset; @@ -265,27 +265,27 @@ uc_fs_seek(uc_vm *vm, size_t nargs) if (!ofs) offset = 0; - else if (!json_object_is_type(ofs, json_type_int)) + else if (ucv_type(ofs) != UC_INTEGER) err_return(EINVAL); else - offset = (long)json_object_get_int64(ofs); + offset = (long)ucv_int64_get(ofs); if (!how) whence = 0; - else if (!json_object_is_type(how, json_type_int)) + else if (ucv_type(how) != UC_INTEGER) err_return(EINVAL); else - whence = (int)json_object_get_int64(how); + whence = (int)ucv_int64_get(how); res = fseek(*fp, offset, whence); if (res < 0) err_return(errno); - return json_object_new_boolean(true); + return ucv_boolean_new(true); } -static json_object * +static uc_value_t * uc_fs_tell(uc_vm *vm, size_t nargs) { long offset; @@ -300,21 +300,21 @@ uc_fs_tell(uc_vm *vm, size_t nargs) if (offset < 0) err_return(errno); - return json_object_new_int64(offset); + return ucv_int64_new(offset); } -static json_object * +static uc_value_t * uc_fs_open(uc_vm *vm, size_t nargs) { - json_object *path = uc_get_arg(0); - json_object *mode = uc_get_arg(1); + uc_value_t *path = uc_get_arg(0); + uc_value_t *mode = uc_get_arg(1); FILE *fp; - if (!json_object_is_type(path, json_type_string)) + if (ucv_type(path) != UC_STRING) err_return(EINVAL); - fp = fopen(json_object_get_string(path), - json_object_is_type(mode, json_type_string) ? json_object_get_string(mode) : "r"); + fp = fopen(ucv_string_get(path), + ucv_type(mode) == UC_STRING ? ucv_string_get(mode) : "r"); if (!fp) err_return(errno); @@ -323,7 +323,7 @@ uc_fs_open(uc_vm *vm, size_t nargs) } -static json_object * +static uc_value_t * uc_fs_readdir(uc_vm *vm, size_t nargs) { DIR **dp = uc_get_self("fs.dir"); @@ -338,10 +338,10 @@ uc_fs_readdir(uc_vm *vm, size_t nargs) if (!e) err_return(errno); - return json_object_new_string(e->d_name); + return ucv_string_new(e->d_name); } -static json_object * +static uc_value_t * uc_fs_telldir(uc_vm *vm, size_t nargs) { DIR **dp = uc_get_self("fs.dir"); @@ -355,30 +355,30 @@ uc_fs_telldir(uc_vm *vm, size_t nargs) if (position == -1) err_return(errno); - return json_object_new_int64((int64_t)position); + return ucv_int64_new((int64_t)position); } -static json_object * +static uc_value_t * uc_fs_seekdir(uc_vm *vm, size_t nargs) { - json_object *ofs = uc_get_arg(0); + uc_value_t *ofs = uc_get_arg(0); DIR **dp = uc_get_self("fs.dir"); long position; - if (!json_object_is_type(ofs, json_type_int)) + if (ucv_type(ofs) != UC_INTEGER) err_return(EINVAL); if (!dp || !*dp) err_return(EBADF); - position = (long)json_object_get_int64(ofs); + position = (long)ucv_int64_get(ofs); seekdir(*dp, position); - return json_object_new_boolean(true); + return ucv_boolean_new(true); } -static json_object * +static uc_value_t * uc_fs_closedir(uc_vm *vm, size_t nargs) { DIR **dp = uc_get_self("fs.dir"); @@ -389,19 +389,19 @@ uc_fs_closedir(uc_vm *vm, size_t nargs) closedir(*dp); *dp = NULL; - return json_object_new_boolean(true); + return ucv_boolean_new(true); } -static json_object * +static uc_value_t * uc_fs_opendir(uc_vm *vm, size_t nargs) { - json_object *path = uc_get_arg(0); + uc_value_t *path = uc_get_arg(0); DIR *dp; - if (!json_object_is_type(path, json_type_string)) + if (ucv_type(path) != UC_STRING) err_return(EINVAL); - dp = opendir(json_object_get_string(path)); + dp = opendir(ucv_string_get(path)); if (!dp) err_return(errno); @@ -409,15 +409,15 @@ uc_fs_opendir(uc_vm *vm, size_t nargs) return uc_alloc_ressource(dir_type, dp); } -static json_object * +static uc_value_t * uc_fs_readlink(uc_vm *vm, size_t nargs) { - json_object *path = uc_get_arg(0); - json_object *res; + uc_value_t *path = uc_get_arg(0); + uc_value_t *res; ssize_t buflen = 0, rv; char *buf = NULL, *tmp; - if (!json_object_is_type(path, json_type_string)) + if (ucv_type(path) != UC_STRING) err_return(EINVAL); do { @@ -430,7 +430,7 @@ uc_fs_readlink(uc_vm *vm, size_t nargs) } buf = tmp; - rv = readlink(json_object_get_string(path), buf, buflen); + rv = readlink(ucv_string_get(path), buf, buflen); if (rv == -1) { free(buf); @@ -442,173 +442,173 @@ uc_fs_readlink(uc_vm *vm, size_t nargs) } while (true); - res = json_object_new_string_len(buf, rv); + res = ucv_string_new_length(buf, rv); free(buf); return res; } -static json_object * +static uc_value_t * uc_fs_stat_common(uc_vm *vm, size_t nargs, bool use_lstat) { - json_object *path = uc_get_arg(0); - json_object *res, *o; + uc_value_t *path = uc_get_arg(0); + uc_value_t *res, *o; struct stat st; int rv; - if (!json_object_is_type(path, json_type_string)) + if (ucv_type(path) != UC_STRING) err_return(EINVAL); - rv = (use_lstat ? lstat : stat)(json_object_get_string(path), &st); + rv = (use_lstat ? lstat : stat)(ucv_string_get(path), &st); if (rv == -1) err_return(errno); - res = json_object_new_object(); + res = ucv_object_new(vm); if (!res) err_return(ENOMEM); - o = json_object_new_object(); + o = ucv_object_new(vm); if (o) { - json_object_object_add(o, "major", json_object_new_int64(major(st.st_dev))); - json_object_object_add(o, "minor", json_object_new_int64(minor(st.st_dev))); + ucv_object_add(o, "major", ucv_int64_new(major(st.st_dev))); + ucv_object_add(o, "minor", ucv_int64_new(minor(st.st_dev))); - json_object_object_add(res, "dev", o); + ucv_object_add(res, "dev", o); } - o = json_object_new_object(); + o = ucv_object_new(vm); if (o) { - json_object_object_add(o, "setuid", json_object_new_boolean(st.st_mode & S_ISUID)); - json_object_object_add(o, "setgid", json_object_new_boolean(st.st_mode & S_ISGID)); - json_object_object_add(o, "sticky", json_object_new_boolean(st.st_mode & S_ISVTX)); + ucv_object_add(o, "setuid", ucv_boolean_new(st.st_mode & S_ISUID)); + ucv_object_add(o, "setgid", ucv_boolean_new(st.st_mode & S_ISGID)); + ucv_object_add(o, "sticky", ucv_boolean_new(st.st_mode & S_ISVTX)); - json_object_object_add(o, "user_read", json_object_new_boolean(st.st_mode & S_IRUSR)); - json_object_object_add(o, "user_write", json_object_new_boolean(st.st_mode & S_IWUSR)); - json_object_object_add(o, "user_exec", json_object_new_boolean(st.st_mode & S_IXUSR)); + ucv_object_add(o, "user_read", ucv_boolean_new(st.st_mode & S_IRUSR)); + ucv_object_add(o, "user_write", ucv_boolean_new(st.st_mode & S_IWUSR)); + ucv_object_add(o, "user_exec", ucv_boolean_new(st.st_mode & S_IXUSR)); - json_object_object_add(o, "group_read", json_object_new_boolean(st.st_mode & S_IRGRP)); - json_object_object_add(o, "group_write", json_object_new_boolean(st.st_mode & S_IWGRP)); - json_object_object_add(o, "group_exec", json_object_new_boolean(st.st_mode & S_IXGRP)); + ucv_object_add(o, "group_read", ucv_boolean_new(st.st_mode & S_IRGRP)); + ucv_object_add(o, "group_write", ucv_boolean_new(st.st_mode & S_IWGRP)); + ucv_object_add(o, "group_exec", ucv_boolean_new(st.st_mode & S_IXGRP)); - json_object_object_add(o, "other_read", json_object_new_boolean(st.st_mode & S_IROTH)); - json_object_object_add(o, "other_write", json_object_new_boolean(st.st_mode & S_IWOTH)); - json_object_object_add(o, "other_exec", json_object_new_boolean(st.st_mode & S_IXOTH)); + ucv_object_add(o, "other_read", ucv_boolean_new(st.st_mode & S_IROTH)); + ucv_object_add(o, "other_write", ucv_boolean_new(st.st_mode & S_IWOTH)); + ucv_object_add(o, "other_exec", ucv_boolean_new(st.st_mode & S_IXOTH)); - json_object_object_add(res, "perm", o); + ucv_object_add(res, "perm", o); } - json_object_object_add(res, "inode", json_object_new_int64((int64_t)st.st_ino)); - json_object_object_add(res, "mode", json_object_new_int64((int64_t)st.st_mode & ~S_IFMT)); - json_object_object_add(res, "nlink", json_object_new_int64((int64_t)st.st_nlink)); - json_object_object_add(res, "uid", json_object_new_int64((int64_t)st.st_uid)); - json_object_object_add(res, "gid", json_object_new_int64((int64_t)st.st_gid)); - json_object_object_add(res, "size", json_object_new_int64((int64_t)st.st_size)); - json_object_object_add(res, "blksize", json_object_new_int64((int64_t)st.st_blksize)); - json_object_object_add(res, "blocks", json_object_new_int64((int64_t)st.st_blocks)); - json_object_object_add(res, "atime", json_object_new_int64((int64_t)st.st_atime)); - json_object_object_add(res, "mtime", json_object_new_int64((int64_t)st.st_mtime)); - json_object_object_add(res, "ctime", json_object_new_int64((int64_t)st.st_ctime)); + ucv_object_add(res, "inode", ucv_int64_new((int64_t)st.st_ino)); + ucv_object_add(res, "mode", ucv_int64_new((int64_t)st.st_mode & ~S_IFMT)); + ucv_object_add(res, "nlink", ucv_int64_new((int64_t)st.st_nlink)); + ucv_object_add(res, "uid", ucv_int64_new((int64_t)st.st_uid)); + ucv_object_add(res, "gid", ucv_int64_new((int64_t)st.st_gid)); + ucv_object_add(res, "size", ucv_int64_new((int64_t)st.st_size)); + ucv_object_add(res, "blksize", ucv_int64_new((int64_t)st.st_blksize)); + ucv_object_add(res, "blocks", ucv_int64_new((int64_t)st.st_blocks)); + ucv_object_add(res, "atime", ucv_int64_new((int64_t)st.st_atime)); + ucv_object_add(res, "mtime", ucv_int64_new((int64_t)st.st_mtime)); + ucv_object_add(res, "ctime", ucv_int64_new((int64_t)st.st_ctime)); if (S_ISREG(st.st_mode)) - json_object_object_add(res, "type", json_object_new_string("file")); + ucv_object_add(res, "type", ucv_string_new("file")); else if (S_ISDIR(st.st_mode)) - json_object_object_add(res, "type", json_object_new_string("directory")); + ucv_object_add(res, "type", ucv_string_new("directory")); else if (S_ISCHR(st.st_mode)) - json_object_object_add(res, "type", json_object_new_string("char")); + ucv_object_add(res, "type", ucv_string_new("char")); else if (S_ISBLK(st.st_mode)) - json_object_object_add(res, "type", json_object_new_string("block")); + ucv_object_add(res, "type", ucv_string_new("block")); else if (S_ISFIFO(st.st_mode)) - json_object_object_add(res, "type", json_object_new_string("fifo")); + ucv_object_add(res, "type", ucv_string_new("fifo")); else if (S_ISLNK(st.st_mode)) - json_object_object_add(res, "type", json_object_new_string("link")); + ucv_object_add(res, "type", ucv_string_new("link")); else if (S_ISSOCK(st.st_mode)) - json_object_object_add(res, "type", json_object_new_string("socket")); + ucv_object_add(res, "type", ucv_string_new("socket")); else - json_object_object_add(res, "type", json_object_new_string("unknown")); + ucv_object_add(res, "type", ucv_string_new("unknown")); return res; } -static json_object * +static uc_value_t * uc_fs_stat(uc_vm *vm, size_t nargs) { return uc_fs_stat_common(vm, nargs, false); } -static json_object * +static uc_value_t * uc_fs_lstat(uc_vm *vm, size_t nargs) { return uc_fs_stat_common(vm, nargs, true); } -static json_object * +static uc_value_t * uc_fs_mkdir(uc_vm *vm, size_t nargs) { - json_object *path = uc_get_arg(0); - json_object *mode = uc_get_arg(1); + uc_value_t *path = uc_get_arg(0); + uc_value_t *mode = uc_get_arg(1); - if (!json_object_is_type(path, json_type_string) || - (mode && !json_object_is_type(mode, json_type_int))) + if (ucv_type(path) != UC_STRING || + (mode && ucv_type(mode) != UC_INTEGER)) err_return(EINVAL); - if (mkdir(json_object_get_string(path), (mode_t)(mode ? json_object_get_int64(mode) : 0777)) == -1) + if (mkdir(ucv_string_get(path), (mode_t)(mode ? ucv_int64_get(mode) : 0777)) == -1) err_return(errno); - return json_object_new_boolean(true); + return ucv_boolean_new(true); } -static json_object * +static uc_value_t * uc_fs_rmdir(uc_vm *vm, size_t nargs) { - json_object *path = uc_get_arg(0); + uc_value_t *path = uc_get_arg(0); - if (!json_object_is_type(path, json_type_string)) + if (ucv_type(path) != UC_STRING) err_return(EINVAL); - if (rmdir(json_object_get_string(path)) == -1) + if (rmdir(ucv_string_get(path)) == -1) err_return(errno); - return json_object_new_boolean(true); + return ucv_boolean_new(true); } -static json_object * +static uc_value_t * uc_fs_symlink(uc_vm *vm, size_t nargs) { - json_object *dest = uc_get_arg(0); - json_object *path = uc_get_arg(1); + uc_value_t *dest = uc_get_arg(0); + uc_value_t *path = uc_get_arg(1); - if (!json_object_is_type(dest, json_type_string) || - !json_object_is_type(path, json_type_string)) + if (ucv_type(dest) != UC_STRING || + ucv_type(path) != UC_STRING) err_return(EINVAL); - if (symlink(json_object_get_string(dest), json_object_get_string(path)) == -1) + if (symlink(ucv_string_get(dest), ucv_string_get(path)) == -1) err_return(errno); - return json_object_new_boolean(true); + return ucv_boolean_new(true); } -static json_object * +static uc_value_t * uc_fs_unlink(uc_vm *vm, size_t nargs) { - json_object *path = uc_get_arg(0); + uc_value_t *path = uc_get_arg(0); - if (!json_object_is_type(path, json_type_string)) + if (ucv_type(path) != UC_STRING) err_return(EINVAL); - if (unlink(json_object_get_string(path)) == -1) + if (unlink(ucv_string_get(path)) == -1) err_return(errno); - return json_object_new_boolean(true); + return ucv_boolean_new(true); } -static json_object * +static uc_value_t * uc_fs_getcwd(uc_vm *vm, size_t nargs) { - json_object *res; + uc_value_t *res; char *buf = NULL, *tmp; size_t buflen = 0; @@ -634,25 +634,25 @@ uc_fs_getcwd(uc_vm *vm, size_t nargs) } while (true); - res = json_object_new_string(buf); + res = ucv_string_new(buf); free(buf); return res; } -static json_object * +static uc_value_t * uc_fs_chdir(uc_vm *vm, size_t nargs) { - json_object *path = uc_get_arg(0); + uc_value_t *path = uc_get_arg(0); - if (!json_object_is_type(path, json_type_string)) + if (ucv_type(path) != UC_STRING) err_return(EINVAL); - if (chdir(json_object_get_string(path)) == -1) + if (chdir(ucv_string_get(path)) == -1) err_return(errno); - return json_object_new_boolean(true); + return ucv_boolean_new(true); } static const uc_cfunction_list proc_fns[] = { @@ -720,7 +720,7 @@ static void close_dir(void *ud) closedir(dp); } -void uc_module_init(uc_prototype *scope) +void uc_module_init(uc_value_t *scope) { uc_add_proto_functions(scope, global_fns); @@ -728,7 +728,7 @@ void uc_module_init(uc_prototype *scope) file_type = uc_declare_type("fs.file", file_fns, close_file); dir_type = uc_declare_type("fs.dir", dir_fns, close_dir); - uc_add_proto_val(scope, "stdin", uc_alloc_ressource(file_type, stdin)); - uc_add_proto_val(scope, "stdout", uc_alloc_ressource(file_type, stdout)); - uc_add_proto_val(scope, "stderr", uc_alloc_ressource(file_type, stderr)); + ucv_object_add(scope, "stdin", uc_alloc_ressource(file_type, stdin)); + ucv_object_add(scope, "stdout", uc_alloc_ressource(file_type, stdout)); + ucv_object_add(scope, "stderr", uc_alloc_ressource(file_type, stderr)); } @@ -21,105 +21,105 @@ static bool srand_called = false; -static json_object * +static uc_value_t * uc_abs(uc_vm *vm, size_t nargs) { - json_object *v = uc_get_arg(0); - enum json_type t; + uc_value_t *v = uc_get_arg(0); + uc_type_t t; int64_t n; double d; - if (json_object_is_type(v, json_type_null)) - return uc_alloc_double(NAN); + if (ucv_type(v) == UC_NULL) + return ucv_double_new(NAN); t = uc_to_number(v, &n, &d); - if (t == json_type_double) - return (isnan(d) || d < 0) ? uc_alloc_double(-d) : json_object_get(v); + if (t == UC_DOUBLE) + return (isnan(d) || d < 0) ? ucv_double_new(-d) : ucv_get(v); - return (n < 0) ? json_object_new_int64(-n) : json_object_get(v); + return (n < 0) ? ucv_int64_new(-n) : ucv_get(v); } -static json_object * +static uc_value_t * uc_atan2(uc_vm *vm, size_t nargs) { double d1 = uc_to_double(uc_get_arg(0)); double d2 = uc_to_double(uc_get_arg(1)); if (isnan(d1) || isnan(d2)) - return uc_alloc_double(NAN); + return ucv_double_new(NAN); - return uc_alloc_double(atan2(d1, d2)); + return ucv_double_new(atan2(d1, d2)); } -static json_object * +static uc_value_t * uc_cos(uc_vm *vm, size_t nargs) { double d = uc_to_double(uc_get_arg(0)); if (isnan(d)) - return uc_alloc_double(NAN); + return ucv_double_new(NAN); - return uc_alloc_double(cos(d)); + return ucv_double_new(cos(d)); } -static json_object * +static uc_value_t * uc_exp(uc_vm *vm, size_t nargs) { double d = uc_to_double(uc_get_arg(0)); if (isnan(d)) - return uc_alloc_double(NAN); + return ucv_double_new(NAN); - return uc_alloc_double(exp(d)); + return ucv_double_new(exp(d)); } -static json_object * +static uc_value_t * uc_log(uc_vm *vm, size_t nargs) { double d = uc_to_double(uc_get_arg(0)); if (isnan(d)) - return uc_alloc_double(NAN); + return ucv_double_new(NAN); - return uc_alloc_double(log(d)); + return ucv_double_new(log(d)); } -static json_object * +static uc_value_t * uc_sin(uc_vm *vm, size_t nargs) { double d = uc_to_double(uc_get_arg(0)); if (isnan(d)) - return uc_alloc_double(NAN); + return ucv_double_new(NAN); - return uc_alloc_double(sin(d)); + return ucv_double_new(sin(d)); } -static json_object * +static uc_value_t * uc_sqrt(uc_vm *vm, size_t nargs) { double d = uc_to_double(uc_get_arg(0)); if (isnan(d)) - return uc_alloc_double(NAN); + return ucv_double_new(NAN); - return uc_alloc_double(sqrt(d)); + return ucv_double_new(sqrt(d)); } -static json_object * +static uc_value_t * uc_pow(uc_vm *vm, size_t nargs) { double x = uc_to_double(uc_get_arg(0)); double y = uc_to_double(uc_get_arg(1)); if (isnan(x) || isnan(y)) - return uc_alloc_double(NAN); + return ucv_double_new(NAN); - return uc_alloc_double(pow(x, y)); + return ucv_double_new(pow(x, y)); } -static json_object * +static uc_value_t * uc_rand(uc_vm *vm, size_t nargs) { struct timeval tv; @@ -131,10 +131,10 @@ uc_rand(uc_vm *vm, size_t nargs) srand_called = true; } - return json_object_new_int64(rand()); + return ucv_int64_new(rand()); } -static json_object * +static uc_value_t * uc_srand(uc_vm *vm, size_t nargs) { int64_t n = uc_to_int64(uc_get_arg(0)); @@ -158,7 +158,7 @@ static const uc_cfunction_list math_fns[] = { { "srand", uc_srand }, }; -void uc_module_init(uc_prototype *scope) +void uc_module_init(uc_value_t *scope) { uc_add_proto_functions(scope, math_fns); } @@ -24,7 +24,7 @@ #define err_return(err) do { last_error = err; return NULL; } while(0) static enum ubus_msg_status last_error = 0; -static uc_ressource_type *conn_type; +static uc_ressource_type_t *conn_type; typedef struct { int timeout; @@ -32,28 +32,28 @@ typedef struct { struct ubus_context *ctx; } ubus_connection; -static json_object * +static uc_value_t * uc_ubus_error(uc_vm *vm, size_t nargs) { - json_object *errmsg; + uc_value_t *errmsg; if (last_error == 0) return NULL; - errmsg = json_object_new_string(ubus_strerror(last_error)); + errmsg = ucv_string_new(ubus_strerror(last_error)); last_error = 0; return errmsg; } -static json_object * -uc_blob_to_json(struct blob_attr *attr, bool table, const char **name); +static uc_value_t * +uc_blob_to_json(uc_vm *vm, struct blob_attr *attr, bool table, const char **name); -static json_object * -uc_blob_array_to_json(struct blob_attr *attr, size_t len, bool table) +static uc_value_t * +uc_blob_array_to_json(uc_vm *vm, struct blob_attr *attr, size_t len, bool table) { - json_object *o = table ? json_object_new_object() : json_object_new_array(); - json_object *v; + uc_value_t *o = table ? ucv_object_new(vm) : ucv_array_new(vm); + uc_value_t *v; struct blob_attr *pos; size_t rem = len; const char *name; @@ -63,21 +63,21 @@ uc_blob_array_to_json(struct blob_attr *attr, size_t len, bool table) __blob_for_each_attr(pos, attr, rem) { name = NULL; - v = uc_blob_to_json(pos, table, &name); + v = uc_blob_to_json(vm, pos, table, &name); if (table && name) - json_object_object_add(o, name, v); + ucv_object_add(o, name, v); else if (!table) - json_object_array_add(o, v); + ucv_array_push(o, v); else - json_object_put(v); + ucv_put(v); } return o; } -static json_object * -uc_blob_to_json(struct blob_attr *attr, bool table, const char **name) +static uc_value_t * +uc_blob_to_json(uc_vm *vm, struct blob_attr *attr, bool table, const char **name) { void *data; int len; @@ -93,16 +93,16 @@ uc_blob_to_json(struct blob_attr *attr, bool table, const char **name) switch (blob_id(attr)) { case BLOBMSG_TYPE_BOOL: - return json_object_new_boolean(*(uint8_t *)data); + return ucv_boolean_new(*(uint8_t *)data); case BLOBMSG_TYPE_INT16: - return json_object_new_int64((int64_t)be16_to_cpu(*(uint16_t *)data)); + return ucv_int64_new((int64_t)be16_to_cpu(*(uint16_t *)data)); case BLOBMSG_TYPE_INT32: - return json_object_new_int64((int64_t)be32_to_cpu(*(uint32_t *)data)); + return ucv_int64_new((int64_t)be32_to_cpu(*(uint32_t *)data)); case BLOBMSG_TYPE_INT64: - return json_object_new_uint64(be64_to_cpu(*(uint64_t *)data)); + return ucv_uint64_new(be64_to_cpu(*(uint64_t *)data)); case BLOBMSG_TYPE_DOUBLE: ; @@ -113,16 +113,16 @@ uc_blob_to_json(struct blob_attr *attr, bool table, const char **name) v.u64 = be64_to_cpu(*(uint64_t *)data); - return json_object_new_double(v.d); + return ucv_double_new(v.d); case BLOBMSG_TYPE_STRING: - return json_object_new_string(data); + return ucv_string_new(data); case BLOBMSG_TYPE_ARRAY: - return uc_blob_array_to_json(data, len, false); + return uc_blob_array_to_json(vm, data, len, false); case BLOBMSG_TYPE_TABLE: - return uc_blob_array_to_json(data, len, true); + return uc_blob_array_to_json(vm, data, len, true); default: return NULL; @@ -130,16 +130,16 @@ uc_blob_to_json(struct blob_attr *attr, bool table, const char **name) } -static json_object * +static uc_value_t * uc_ubus_connect(uc_vm *vm, size_t nargs) { - json_object *socket = uc_get_arg(0); - json_object *timeout = uc_get_arg(1); - json_object *co; + uc_value_t *socket = uc_get_arg(0); + uc_value_t *timeout = uc_get_arg(1); + uc_value_t *co; ubus_connection *c; - if ((socket && !json_object_is_type(socket, json_type_string)) || - (timeout && !json_object_is_type(timeout, json_type_int))) + if ((socket && ucv_type(socket) != UC_STRING) || + (timeout && ucv_type(timeout) != UC_INTEGER)) err_return(UBUS_STATUS_INVALID_ARGUMENT); c = calloc(1, sizeof(*c)); @@ -147,8 +147,8 @@ uc_ubus_connect(uc_vm *vm, size_t nargs) if (!c) err_return(UBUS_STATUS_UNKNOWN_ERROR); - c->ctx = ubus_connect(socket ? json_object_get_string(socket) : NULL); - c->timeout = timeout ? json_object_get_int(timeout) : 30; + c->ctx = ubus_connect(socket ? ucv_string_get(socket) : NULL); + c->timeout = timeout ? ucv_int64_get(timeout) : 30; if (!c->ctx) { free(c); @@ -158,7 +158,7 @@ uc_ubus_connect(uc_vm *vm, size_t nargs) if (c->timeout < 0) c->timeout = 30; - co = json_object_new_object(); + co = ucv_object_new(vm); if (!co) { ubus_free(c->ctx); @@ -174,16 +174,16 @@ uc_ubus_connect(uc_vm *vm, size_t nargs) static void uc_ubus_signatures_cb(struct ubus_context *c, struct ubus_object_data *o, void *p) { - json_object *arr = p; - json_object *sig; + uc_value_t *arr = p; + uc_value_t *sig; if (!o->signature) return; - sig = uc_blob_array_to_json(blob_data(o->signature), blob_len(o->signature), true); + sig = uc_blob_array_to_json(NULL, blob_data(o->signature), blob_len(o->signature), true); if (sig) - json_object_array_add(arr, sig); + ucv_array_push(arr, sig); } static void @@ -198,27 +198,27 @@ uc_ubus_objects_cb(struct ubus_context *c, struct ubus_object_data *o, void *p) json_object_array_add(arr, obj); } -static json_object * +static uc_value_t * uc_ubus_list(uc_vm *vm, size_t nargs) { ubus_connection **c = uc_get_self("ubus.connection"); - json_object *objname = uc_get_arg(0); - json_object *res = NULL; + uc_value_t *objname = uc_get_arg(0); + uc_value_t *res = NULL; enum ubus_msg_status rv; if (!c || !*c || !(*c)->ctx) err_return(UBUS_STATUS_CONNECTION_FAILED); - if (objname && !json_object_is_type(objname, json_type_string)) + if (objname && ucv_type(objname) != UC_STRING) err_return(UBUS_STATUS_INVALID_ARGUMENT); - res = json_object_new_array(); + res = ucv_array_new(vm); if (!res) err_return(UBUS_STATUS_UNKNOWN_ERROR); rv = ubus_lookup((*c)->ctx, - objname ? json_object_get_string(objname) : NULL, + objname ? ucv_string_get(objname) : NULL, objname ? uc_ubus_signatures_cb : uc_ubus_objects_cb, res); @@ -231,41 +231,48 @@ uc_ubus_list(uc_vm *vm, size_t nargs) static void uc_ubus_call_cb(struct ubus_request *req, int type, struct blob_attr *msg) { - json_object **res = (json_object **)req->priv; + uc_value_t **res = (uc_value_t **)req->priv; - *res = msg ? uc_blob_array_to_json(blob_data(msg), blob_len(msg), true) : NULL; + *res = msg ? uc_blob_array_to_json(NULL, blob_data(msg), blob_len(msg), true) : NULL; } -static json_object * +static uc_value_t * uc_ubus_call(uc_vm *vm, size_t nargs) { ubus_connection **c = uc_get_self("ubus.connection"); - json_object *objname = uc_get_arg(0); - json_object *funname = uc_get_arg(1); - json_object *funargs = uc_get_arg(2); - json_object *res = NULL; + uc_value_t *objname = uc_get_arg(0); + uc_value_t *funname = uc_get_arg(1); + uc_value_t *funargs = uc_get_arg(2); + uc_value_t *res = NULL; + json_object *o; enum ubus_msg_status rv; uint32_t id; if (!c || !*c || !(*c)->ctx) err_return(UBUS_STATUS_CONNECTION_FAILED); - if (!json_object_is_type(objname, json_type_string) || - !json_object_is_type(funname, json_type_string) || - (funargs && !json_object_is_type(funargs, json_type_object))) + if (ucv_type(objname) != UC_STRING || + ucv_type(funname) != UC_STRING || + (funargs && ucv_type(funargs) != UC_OBJECT)) err_return(UBUS_STATUS_INVALID_ARGUMENT); blob_buf_init(&(*c)->buf, 0); - if (funargs && !blobmsg_add_object(&(*c)->buf, funargs)) - err_return(UBUS_STATUS_UNKNOWN_ERROR); + if (funargs) { + o = ucv_to_json(funargs); + rv = blobmsg_add_object(&(*c)->buf, o); + json_object_put(o); + + if (!rv) + err_return(UBUS_STATUS_UNKNOWN_ERROR); + } - rv = ubus_lookup_id((*c)->ctx, json_object_get_string(objname), &id); + rv = ubus_lookup_id((*c)->ctx, ucv_string_get(objname), &id); if (rv != UBUS_STATUS_OK) err_return(rv); - rv = ubus_invoke((*c)->ctx, id, json_object_get_string(funname), (*c)->buf.head, + rv = ubus_invoke((*c)->ctx, id, ucv_string_get(funname), (*c)->buf.head, uc_ubus_call_cb, &res, (*c)->timeout * 1000); if (rv != UBUS_STATUS_OK) @@ -274,7 +281,7 @@ uc_ubus_call(uc_vm *vm, size_t nargs) return res; } -static json_object * +static uc_value_t * uc_ubus_disconnect(uc_vm *vm, size_t nargs) { ubus_connection **c = uc_get_self("ubus.connection"); @@ -285,7 +292,7 @@ uc_ubus_disconnect(uc_vm *vm, size_t nargs) ubus_free((*c)->ctx); (*c)->ctx = NULL; - return json_object_new_boolean(true); + return ucv_boolean_new(true); } @@ -313,7 +320,7 @@ static void close_connection(void *ud) { free(conn); } -void uc_module_init(uc_prototype *scope) +void uc_module_init(uc_value_t *scope) { uc_add_proto_functions(scope, global_fns); @@ -22,7 +22,7 @@ #define err_return(err) do { last_error = err; return NULL; } while(0) static int last_error = 0; -static uc_ressource_type *cursor_type; +static uc_ressource_type_t *cursor_type; enum pkg_cmd { CMD_SAVE, @@ -30,11 +30,11 @@ enum pkg_cmd { CMD_REVERT }; -static json_object * +static uc_value_t * uc_uci_error(uc_vm *vm, size_t nargs) { char buf[sizeof("Unknown error: -9223372036854775808")]; - json_object *errmsg; + uc_value_t *errmsg; const char *errstr[] = { [UCI_ERR_MEM] = "Out of memory", @@ -49,12 +49,12 @@ uc_uci_error(uc_vm *vm, size_t nargs) if (last_error == 0) return NULL; - if (last_error >= 0 && last_error < ARRAY_SIZE(errstr)) { - errmsg = json_object_new_string(errstr[last_error]); + if (last_error >= 0 && (unsigned)last_error < ARRAY_SIZE(errstr)) { + errmsg = ucv_string_new(errstr[last_error]); } else { snprintf(buf, sizeof(buf), "Unknown error: %d", last_error); - errmsg = json_object_new_string(buf); + errmsg = ucv_string_new(buf); } last_error = 0; @@ -63,16 +63,16 @@ uc_uci_error(uc_vm *vm, size_t nargs) } -static json_object * +static uc_value_t * uc_uci_cursor(uc_vm *vm, size_t nargs) { - json_object *cdir = uc_get_arg(0); - json_object *sdir = uc_get_arg(1); + uc_value_t *cdir = uc_get_arg(0); + uc_value_t *sdir = uc_get_arg(1); struct uci_context *c; int rv; - if ((cdir && !json_object_is_type(cdir, json_type_string)) || - (sdir && !json_object_is_type(sdir, json_type_string))) + if ((cdir && ucv_type(cdir) != UC_STRING) || + (sdir && ucv_type(sdir) != UC_STRING)) err_return(UCI_ERR_INVAL); c = uci_alloc_context(); @@ -81,14 +81,14 @@ uc_uci_cursor(uc_vm *vm, size_t nargs) err_return(UCI_ERR_MEM); if (cdir) { - rv = uci_set_confdir(c, json_object_get_string(cdir)); + rv = uci_set_confdir(c, ucv_string_get(cdir)); if (rv) err_return(rv); } if (sdir) { - rv = uci_set_savedir(c, json_object_get_string(sdir)); + rv = uci_set_savedir(c, ucv_string_get(sdir)); if (rv) err_return(rv); @@ -98,54 +98,57 @@ uc_uci_cursor(uc_vm *vm, size_t nargs) } -static json_object * +static uc_value_t * uc_uci_load(uc_vm *vm, size_t nargs) { struct uci_context **c = uc_get_self("uci.cursor"); - json_object *conf = uc_get_arg(0); + uc_value_t *conf = uc_get_arg(0); struct uci_element *e; + char *s; if (!c || !*c) err_return(UCI_ERR_INVAL); - if (!json_object_is_type(conf, json_type_string)) + if (ucv_type(conf) != UC_STRING) err_return(UCI_ERR_INVAL); + s = ucv_string_get(conf); + uci_foreach_element(&(*c)->root, e) { - if (!strcmp(e->name, json_object_get_string(conf))) { + if (!strcmp(e->name, s)) { uci_unload(*c, uci_to_package(e)); break; } } - if (uci_load(*c, json_object_get_string(conf), NULL)) + if (uci_load(*c, s, NULL)) err_return((*c)->err); - return json_object_new_boolean(true); + return ucv_boolean_new(true); } -static json_object * +static uc_value_t * uc_uci_unload(uc_vm *vm, size_t nargs) { struct uci_context **c = uc_get_self("uci.cursor"); - json_object *conf = uc_get_arg(0); + uc_value_t *conf = uc_get_arg(0); struct uci_element *e; if (!c || !*c) err_return(UCI_ERR_INVAL); - if (!json_object_is_type(conf, json_type_string)) + if (ucv_type(conf) != UC_STRING) err_return(UCI_ERR_INVAL); uci_foreach_element(&(*c)->root, e) { - if (!strcmp(e->name, json_object_get_string(conf))) { + if (!strcmp(e->name, ucv_string_get(conf))) { uci_unload(*c, uci_to_package(e)); - return json_object_new_boolean(true); + return ucv_boolean_new(true); } } - return json_object_new_boolean(false); + return ucv_boolean_new(false); } static int @@ -177,22 +180,22 @@ lookup_ptr(struct uci_context *ctx, struct uci_ptr *ptr, bool extended) return uci_lookup_ptr(ctx, ptr, NULL, extended); } -static json_object * -option_to_json(struct uci_option *o) +static uc_value_t * +option_to_uval(uc_vm *vm, struct uci_option *o) { - json_object *arr; struct uci_element *e; + uc_value_t *arr; switch (o->type) { case UCI_TYPE_STRING: - return json_object_new_string(o->v.string); + return ucv_string_new(o->v.string); case UCI_TYPE_LIST: - arr = json_object_new_array(); + arr = ucv_array_new(vm); if (arr) uci_foreach_element(&o->v.list, e) - json_object_array_add(arr, json_object_new_string(e->name)); + ucv_array_push(arr, ucv_string_new(e->name)); return arr; @@ -201,36 +204,36 @@ option_to_json(struct uci_option *o) } } -static json_object * -section_to_json(struct uci_section *s, int index) +static uc_value_t * +section_to_uval(uc_vm *vm, struct uci_section *s, int index) { - json_object *so = json_object_new_object(); + uc_value_t *so = ucv_object_new(vm); struct uci_element *e; struct uci_option *o; if (!so) return NULL; - json_object_object_add(so, ".anonymous", json_object_new_boolean(s->anonymous)); - json_object_object_add(so, ".type", json_object_new_string(s->type)); - json_object_object_add(so, ".name", json_object_new_string(s->e.name)); + ucv_object_add(so, ".anonymous", ucv_boolean_new(s->anonymous)); + ucv_object_add(so, ".type", ucv_string_new(s->type)); + ucv_object_add(so, ".name", ucv_string_new(s->e.name)); if (index >= 0) - json_object_object_add(so, ".index", json_object_new_int64(index)); + ucv_object_add(so, ".index", ucv_int64_new(index)); uci_foreach_element(&s->options, e) { o = uci_to_option(e); - json_object_object_add(so, o->e.name, option_to_json(o)); + ucv_object_add(so, o->e.name, option_to_uval(vm, o)); } return so; } -static json_object * -package_to_json(struct uci_package *p) +static uc_value_t * +package_to_uval(uc_vm *vm, struct uci_package *p) { - json_object *po = json_object_new_object(); - json_object *so; + uc_value_t *po = ucv_object_new(vm); + uc_value_t *so; struct uci_element *e; int i = 0; @@ -238,37 +241,37 @@ package_to_json(struct uci_package *p) return NULL; uci_foreach_element(&p->sections, e) { - so = section_to_json(uci_to_section(e), i++); - json_object_object_add(po, e->name, so); + so = section_to_uval(vm, uci_to_section(e), i++); + ucv_object_add(po, e->name, so); } return po; } -static json_object * +static uc_value_t * uc_uci_get_any(uc_vm *vm, size_t nargs, bool all) { struct uci_context **c = uc_get_self("uci.cursor"); - json_object *conf = uc_get_arg(0); - json_object *sect = uc_get_arg(1); - json_object *opt = uc_get_arg(2); + 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 = {}; int rv; if (!c || !*c) err_return(UCI_ERR_INVAL); - if (!json_object_is_type(conf, json_type_string) || - (sect && !json_object_is_type(sect, json_type_string)) || - (opt && !json_object_is_type(opt, json_type_string))) + if ((ucv_type(conf) != UC_STRING) || + (sect && ucv_type(sect) != UC_STRING) || + (opt && ucv_type(opt) != UC_STRING)) err_return(UCI_ERR_INVAL); if ((!sect && !all) || (opt && all)) err_return(UCI_ERR_INVAL); - ptr.package = json_object_get_string(conf); - ptr.section = sect ? json_object_get_string(sect) : NULL; - ptr.option = opt ? json_object_get_string(opt) : NULL; + ptr.package = ucv_string_get(conf); + ptr.section = sect ? ucv_string_get(sect) : NULL; + ptr.option = opt ? ucv_string_get(opt) : NULL; rv = lookup_ptr(*c, &ptr, true); @@ -283,60 +286,60 @@ uc_uci_get_any(uc_vm *vm, size_t nargs, bool all) if (!ptr.s) err_return(UCI_ERR_NOTFOUND); - return section_to_json(ptr.s, -1); + return section_to_uval(vm, ptr.s, -1); } if (!ptr.p) err_return(UCI_ERR_NOTFOUND); - return package_to_json(ptr.p); + return package_to_uval(vm, ptr.p); } if (ptr.option) { if (!ptr.o) err_return(UCI_ERR_NOTFOUND); - return option_to_json(ptr.o); + return option_to_uval(vm, ptr.o); } if (!ptr.s) err_return(UCI_ERR_NOTFOUND); - return json_object_new_string(ptr.s->type); + return ucv_string_new(ptr.s->type); } -static json_object * +static uc_value_t * uc_uci_get(uc_vm *vm, size_t nargs) { return uc_uci_get_any(vm, nargs, false); } -static json_object * +static uc_value_t * uc_uci_get_all(uc_vm *vm, size_t nargs) { return uc_uci_get_any(vm, nargs, true); } -static json_object * +static uc_value_t * uc_uci_get_first(uc_vm *vm, size_t nargs) { struct uci_context **c = uc_get_self("uci.cursor"); - json_object *conf = uc_get_arg(0); - json_object *type = uc_get_arg(1); - json_object *opt = uc_get_arg(2); + uc_value_t *conf = uc_get_arg(0); + uc_value_t *type = uc_get_arg(1); + uc_value_t *opt = uc_get_arg(2); struct uci_package *p = NULL; struct uci_section *sc; struct uci_element *e; struct uci_ptr ptr = {}; int rv; - if (!json_object_is_type(conf, json_type_string) || - !json_object_is_type(type, json_type_string) || - (opt && !json_object_is_type(opt, json_type_string))) + if (ucv_type(conf) != UC_STRING || + ucv_type(type) != UC_STRING || + (opt && ucv_type(opt) != UC_STRING)) err_return(UCI_ERR_INVAL); uci_foreach_element(&(*c)->root, e) { - if (strcmp(e->name, json_object_get_string(conf))) + if (strcmp(e->name, ucv_string_get(conf))) continue; p = uci_to_package(e); @@ -349,15 +352,15 @@ uc_uci_get_first(uc_vm *vm, size_t nargs) uci_foreach_element(&p->sections, e) { sc = uci_to_section(e); - if (strcmp(sc->type, json_object_get_string(type))) + if (strcmp(sc->type, ucv_string_get(type))) continue; if (!opt) - return json_object_new_string(sc->e.name); + return ucv_string_new(sc->e.name); - ptr.package = json_object_get_string(conf); + ptr.package = ucv_string_get(conf); ptr.section = sc->e.name; - ptr.option = json_object_get_string(opt); + ptr.option = ucv_string_get(opt); ptr.p = p; ptr.s = sc; @@ -369,29 +372,29 @@ uc_uci_get_first(uc_vm *vm, size_t nargs) if (!(ptr.flags & UCI_LOOKUP_COMPLETE)) err_return(UCI_ERR_NOTFOUND); - return option_to_json(ptr.o); + return option_to_uval(vm, ptr.o); } err_return(UCI_ERR_NOTFOUND); } -static json_object * +static uc_value_t * uc_uci_add(uc_vm *vm, size_t nargs) { struct uci_context **c = uc_get_self("uci.cursor"); - json_object *conf = uc_get_arg(0); - json_object *type = uc_get_arg(1); + uc_value_t *conf = uc_get_arg(0); + uc_value_t *type = uc_get_arg(1); struct uci_element *e = NULL; struct uci_package *p = NULL; struct uci_section *sc = NULL; int rv; - if (!json_object_is_type(conf, json_type_string) || - !json_object_is_type(type, json_type_string)) + if (ucv_type(conf) != UC_STRING || + ucv_type(type) != UC_STRING) err_return(UCI_ERR_INVAL); uci_foreach_element(&(*c)->root, e) { - if (!strcmp(e->name, json_object_get_string(conf))) { + if (!strcmp(e->name, ucv_string_get(conf))) { p = uci_to_package(e); break; } @@ -400,73 +403,75 @@ uc_uci_add(uc_vm *vm, size_t nargs) if (!p) err_return(UCI_ERR_NOTFOUND); - rv = uci_add_section(*c, p, json_object_get_string(type), &sc); + rv = uci_add_section(*c, p, ucv_string_get(type), &sc); if (rv != UCI_OK) err_return(rv); else if (!sc) err_return(UCI_ERR_NOTFOUND); - return json_object_new_string(sc->e.name); + return ucv_string_new(sc->e.name); } static bool -json_to_value(json_object *val, const char **p, bool *is_list) +uval_to_uci(uc_vm *vm, uc_value_t *val, const char **p, bool *is_list) { - json_object *item; + uc_value_t *item; *p = NULL; if (is_list) *is_list = false; - switch (json_object_get_type(val)) { - case json_type_object: - return false; - - case json_type_array: - if (json_object_array_length(val) == 0) + switch (ucv_type(val)) { + case UC_ARRAY: + if (ucv_array_length(val) == 0) return false; - item = json_object_array_get_idx(val, 0); + item = ucv_array_get(val, 0); /* don't recurse */ - if (json_object_is_type(item, json_type_array)) + if (ucv_type(item) == UC_ARRAY) return false; if (is_list) *is_list = true; - return json_to_value(item, p, NULL); + return uval_to_uci(vm, item, p, NULL); - case json_type_boolean: - *p = json_object_get_boolean(val) ? "1" : "0"; + case UC_BOOLEAN: + *p = xstrdup(ucv_boolean_get(val) ? "1" : "0"); return true; - case json_type_null: + case UC_DOUBLE: + case UC_INTEGER: + case UC_STRING: + *p = ucv_to_string(vm, val); + /* fall through */ + + case UC_NULL: return true; default: - *p = json_object_get_string(val); - - return true; + return false; } } -static json_object * +static uc_value_t * uc_uci_set(uc_vm *vm, size_t nargs) { struct uci_context **c = uc_get_self("uci.cursor"); - json_object *conf = uc_get_arg(0); - json_object *sect = uc_get_arg(1); - json_object *opt = NULL, *val = NULL; + 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 = {}; bool is_list = false; - int rv, i; + size_t i; + int rv; - if (!json_object_is_type(conf, json_type_string) || - !json_object_is_type(sect, json_type_string)) + if (ucv_type(conf) != UC_STRING || + ucv_type(sect) != UC_STRING) err_return(UCI_ERR_INVAL); switch (nargs) { @@ -475,7 +480,7 @@ uc_uci_set(uc_vm *vm, size_t nargs) opt = uc_get_arg(2); val = uc_get_arg(3); - if (!json_object_is_type(opt, json_type_string)) + if (ucv_type(opt) != UC_STRING) err_return(UCI_ERR_INVAL); break; @@ -484,7 +489,7 @@ uc_uci_set(uc_vm *vm, size_t nargs) case 3: val = uc_get_arg(2); - if (!json_object_is_type(val, json_type_string)) + if (ucv_type(val) != UC_STRING) err_return(UCI_ERR_INVAL); break; @@ -493,9 +498,9 @@ uc_uci_set(uc_vm *vm, size_t nargs) err_return(UCI_ERR_INVAL); } - ptr.package = json_object_get_string(conf); - ptr.section = json_object_get_string(sect); - ptr.option = opt ? json_object_get_string(opt) : NULL; + ptr.package = ucv_string_get(conf); + ptr.section = ucv_string_get(sect); + ptr.option = opt ? ucv_string_get(opt) : NULL; rv = lookup_ptr(*c, &ptr, true); @@ -505,18 +510,19 @@ uc_uci_set(uc_vm *vm, size_t nargs) if (!ptr.s && ptr.option) err_return(UCI_ERR_NOTFOUND); - if (!json_to_value(val, &ptr.value, &is_list)) + if (!uval_to_uci(vm, val, &ptr.value, &is_list)) err_return(UCI_ERR_INVAL); if (is_list) { /* if we got a one-element array, delete existing option (if any) * and iterate array at offset 0 */ - if (json_object_array_length(val) == 1) { + if (ucv_array_length(val) == 1) { i = 0; - if (ptr.o) { - ptr.value = NULL; + free((char *)ptr.value); + ptr.value = NULL; + if (ptr.o) { rv = uci_delete(*c, &ptr); if (rv != UCI_OK) @@ -529,16 +535,18 @@ uc_uci_set(uc_vm *vm, size_t nargs) i = 1; rv = uci_set(*c, &ptr); + free((char *)ptr.value); if (rv != UCI_OK) err_return(rv); } - for (; i < json_object_array_length(val); i++) { - if (!json_to_value(json_object_array_get_idx(val, i), &ptr.value, NULL)) + for (; i < ucv_array_length(val); i++) { + if (!uval_to_uci(vm, ucv_array_get(val, i), &ptr.value, NULL)) continue; rv = uci_add_list(*c, &ptr); + free((char *)ptr.value); if (rv != UCI_OK) err_return(rv); @@ -546,32 +554,33 @@ uc_uci_set(uc_vm *vm, size_t nargs) } else { rv = uci_set(*c, &ptr); + free((char *)ptr.value); if (rv != UCI_OK) err_return(rv); } - return json_object_new_boolean(true); + return ucv_boolean_new(true); } -static json_object * +static uc_value_t * uc_uci_delete(uc_vm *vm, size_t nargs) { struct uci_context **c = uc_get_self("uci.cursor"); - json_object *conf = uc_get_arg(0); - json_object *sect = uc_get_arg(1); - json_object *opt = uc_get_arg(2); + 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 = {}; int rv; - if (!json_object_is_type(conf, json_type_string) || - !json_object_is_type(sect, json_type_string) || - (opt && !json_object_is_type(opt, json_type_string))) + if (ucv_type(conf) != UC_STRING || + ucv_type(sect) != UC_STRING || + (opt && ucv_type(opt) != UC_STRING)) err_return(UCI_ERR_INVAL); - ptr.package = json_object_get_string(conf); - ptr.section = json_object_get_string(sect); - ptr.option = opt ? json_object_get_string(opt) : NULL; + ptr.package = ucv_string_get(conf); + ptr.section = ucv_string_get(sect); + ptr.option = opt ? ucv_string_get(opt) : NULL; rv = lookup_ptr(*c, &ptr, true); @@ -586,21 +595,21 @@ uc_uci_delete(uc_vm *vm, size_t nargs) if (rv != UCI_OK) err_return(rv); - return json_object_new_boolean(true); + return ucv_boolean_new(true); } -static json_object * +static uc_value_t * uc_uci_rename(uc_vm *vm, size_t nargs) { struct uci_context **c = uc_get_self("uci.cursor"); - json_object *conf = uc_get_arg(0); - json_object *sect = uc_get_arg(1); - json_object *opt = NULL, *val = NULL; + 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 = {}; int rv; - if (!json_object_is_type(conf, json_type_string) || - !json_object_is_type(sect, json_type_string)) + if (ucv_type(conf) != UC_STRING || + ucv_type(sect) != UC_STRING) err_return(UCI_ERR_INVAL); switch (nargs) { @@ -609,8 +618,8 @@ uc_uci_rename(uc_vm *vm, size_t nargs) opt = uc_get_arg(2); val = uc_get_arg(3); - if (!json_object_is_type(opt, json_type_string) || - !json_object_is_type(val, json_type_string)) + if (ucv_type(opt) != UC_STRING || + ucv_type(val) != UC_STRING) err_return(UCI_ERR_INVAL); break; @@ -619,7 +628,7 @@ uc_uci_rename(uc_vm *vm, size_t nargs) case 3: val = uc_get_arg(2); - if (!json_object_is_type(val, json_type_string)) + if (ucv_type(val) != UC_STRING) err_return(UCI_ERR_INVAL); break; @@ -628,10 +637,10 @@ uc_uci_rename(uc_vm *vm, size_t nargs) err_return(UCI_ERR_INVAL); } - ptr.package = json_object_get_string(conf); - ptr.section = json_object_get_string(sect); - ptr.option = opt ? json_object_get_string(opt) : NULL; - ptr.value = json_object_get_string(val); + ptr.package = ucv_string_get(conf); + ptr.section = ucv_string_get(sect); + ptr.option = opt ? ucv_string_get(opt) : NULL; + ptr.value = ucv_string_get(val); rv = lookup_ptr(*c, &ptr, true); @@ -646,32 +655,32 @@ uc_uci_rename(uc_vm *vm, size_t nargs) if (rv != UCI_OK) err_return(rv); - return json_object_new_boolean(true); + return ucv_boolean_new(true); } -static json_object * +static uc_value_t * uc_uci_reorder(uc_vm *vm, size_t nargs) { struct uci_context **c = uc_get_self("uci.cursor"); - json_object *conf = uc_get_arg(0); - json_object *sect = uc_get_arg(1); - json_object *val = uc_get_arg(2); + 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 = {}; int64_t n; int rv; - if (!json_object_is_type(conf, json_type_string) || - !json_object_is_type(sect, json_type_string) || - !json_object_is_type(val, json_type_int)) + if (ucv_type(conf) != UC_STRING || + ucv_type(sect) != UC_STRING || + ucv_type(val) != UC_INTEGER) err_return(UCI_ERR_INVAL); - n = json_object_get_int64(val); + n = ucv_int64_get(val); if (n < 0) err_return(UCI_ERR_INVAL); - ptr.package = json_object_get_string(conf); - ptr.section = json_object_get_string(sect); + ptr.package = ucv_string_get(conf); + ptr.section = ucv_string_get(sect); rv = lookup_ptr(*c, &ptr, true); @@ -686,14 +695,14 @@ uc_uci_reorder(uc_vm *vm, size_t nargs) if (rv != UCI_OK) err_return(rv); - return json_object_new_boolean(true); + return ucv_boolean_new(true); } -static json_object * +static uc_value_t * uc_uci_pkg_command(uc_vm *vm, size_t nargs, enum pkg_cmd cmd) { struct uci_context **c = uc_get_self("uci.cursor"); - json_object *conf = uc_get_arg(0); + uc_value_t *conf = uc_get_arg(0); struct uci_element *e, *tmp; struct uci_package *p; struct uci_ptr ptr = {}; @@ -702,13 +711,13 @@ uc_uci_pkg_command(uc_vm *vm, size_t nargs, enum pkg_cmd cmd) if (cmd != CMD_REVERT && conf) err_return(UCI_ERR_INVAL); - if (conf && !json_object_is_type(conf, json_type_string)) + if (conf && ucv_type(conf) != UC_STRING) err_return(UCI_ERR_INVAL); uci_foreach_element_safe(&(*c)->root, tmp, e) { p = uci_to_package(e); - if (conf && strcmp(e->name, json_object_get_string(conf))) + if (conf && strcmp(e->name, ucv_string_get(conf))) continue; switch (cmd) { @@ -736,29 +745,29 @@ uc_uci_pkg_command(uc_vm *vm, size_t nargs, enum pkg_cmd cmd) if (res != UCI_OK) err_return(res); - return json_object_new_boolean(true); + return ucv_boolean_new(true); } -static json_object * +static uc_value_t * uc_uci_save(uc_vm *vm, size_t nargs) { return uc_uci_pkg_command(vm, nargs, CMD_SAVE); } -static json_object * +static uc_value_t * uc_uci_commit(uc_vm *vm, size_t nargs) { return uc_uci_pkg_command(vm, nargs, CMD_COMMIT); } -static json_object * +static uc_value_t * uc_uci_revert(uc_vm *vm, size_t nargs) { return uc_uci_pkg_command(vm, nargs, CMD_REVERT); } -static json_object * -change_to_json(struct uci_delta *d) +static uc_value_t * +change_to_uval(uc_vm *vm, struct uci_delta *d) { const char *types[] = { [UCI_CMD_REORDER] = "order", @@ -770,36 +779,36 @@ change_to_json(struct uci_delta *d) [UCI_CMD_CHANGE] = "set", }; - json_object *a; + uc_value_t *a; if (!d->section) return NULL; - a = json_object_new_array(); + a = ucv_array_new(vm); if (!a) return NULL; - json_object_array_add(a, json_object_new_string(types[d->cmd])); - json_object_array_add(a, json_object_new_string(d->section)); + ucv_array_push(a, ucv_string_new(types[d->cmd])); + ucv_array_push(a, ucv_string_new(d->section)); if (d->e.name) - json_object_array_add(a, json_object_new_string(d->e.name)); + ucv_array_push(a, ucv_string_new(d->e.name)); if (d->value) { if (d->cmd == UCI_CMD_REORDER) - json_object_array_add(a, json_object_new_int64(strtoul(d->value, NULL, 10))); + ucv_array_push(a, ucv_int64_new(strtoul(d->value, NULL, 10))); else - json_object_array_add(a, json_object_new_string(d->value)); + ucv_array_push(a, ucv_string_new(d->value)); } return a; } -static json_object * -changes_to_json(struct uci_context *ctx, const char *package) +static uc_value_t * +changes_to_uval(uc_vm *vm, struct uci_context *ctx, const char *package) { - json_object *a = NULL, *c; + uc_value_t *a = NULL, *c; struct uci_package *p = NULL; struct uci_element *e; bool unload = false; @@ -820,23 +829,23 @@ changes_to_json(struct uci_context *ctx, const char *package) return NULL; if (!uci_list_empty(&p->delta) || !uci_list_empty(&p->saved_delta)) { - a = json_object_new_array(); + a = ucv_array_new(vm); if (!a) err_return(UCI_ERR_MEM); uci_foreach_element(&p->saved_delta, e) { - c = change_to_json(uci_to_delta(e)); + c = change_to_uval(vm, uci_to_delta(e)); if (c) - json_object_array_add(a, c); + ucv_array_push(a, c); } uci_foreach_element(&p->delta, e) { - c = change_to_json(uci_to_delta(e)); + c = change_to_uval(vm, uci_to_delta(e)); if (c) - json_object_array_add(a, c); + ucv_array_push(a, c); } } @@ -846,16 +855,16 @@ changes_to_json(struct uci_context *ctx, const char *package) return a; } -static json_object * +static uc_value_t * uc_uci_changes(uc_vm *vm, size_t nargs) { struct uci_context **c = uc_get_self("uci.cursor"); - json_object *conf = uc_get_arg(0); - json_object *res, *chg; + uc_value_t *conf = uc_get_arg(0); + uc_value_t *res, *chg; char **configs; int rv, i; - if (conf && !json_object_is_type(conf, json_type_string)) + if (conf && ucv_type(conf) != UC_STRING) err_return(UCI_ERR_INVAL); rv = uci_list_configs(*c, &configs); @@ -863,21 +872,16 @@ uc_uci_changes(uc_vm *vm, size_t nargs) if (rv != UCI_OK) err_return(rv); - res = json_object_new_object(); - - if (!res) { - free(configs); - err_return(UCI_ERR_MEM); - } + res = ucv_object_new(vm); for (i = 0; configs[i]; i++) { - if (conf && strcmp(configs[i], json_object_get_string(conf))) + if (conf && strcmp(configs[i], ucv_string_get(conf))) continue; - chg = changes_to_json(*c, configs[i]); + chg = changes_to_uval(vm, *c, configs[i]); if (chg) - json_object_object_add(res, configs[i], chg); + ucv_object_add(res, configs[i], chg); } free(configs); @@ -885,14 +889,14 @@ uc_uci_changes(uc_vm *vm, size_t nargs) return res; } -static json_object * +static uc_value_t * uc_uci_foreach(uc_vm *vm, size_t nargs) { struct uci_context **c = uc_get_self("uci.cursor"); - json_object *conf = uc_get_arg(0); - json_object *type = uc_get_arg(1); - json_object *func = uc_get_arg(2); - json_object *rv = NULL; + uc_value_t *conf = uc_get_arg(0); + uc_value_t *type = uc_get_arg(1); + uc_value_t *func = uc_get_arg(2); + uc_value_t *rv = NULL; struct uci_package *p = NULL; struct uci_element *e, *tmp; struct uci_section *sc; @@ -901,12 +905,12 @@ uc_uci_foreach(uc_vm *vm, size_t nargs) bool ret = false; int i = 0; - if (!json_object_is_type(conf, json_type_string) || - (type && !json_object_is_type(type, json_type_string))) + if (ucv_type(conf) != UC_STRING || + (type && ucv_type(type) != UC_STRING)) err_return(UCI_ERR_INVAL); uci_foreach_element(&(*c)->root, e) { - if (strcmp(e->name, json_object_get_string(conf))) + if (strcmp(e->name, ucv_string_get(conf))) continue; p = uci_to_package(e); @@ -920,11 +924,11 @@ uc_uci_foreach(uc_vm *vm, size_t nargs) sc = uci_to_section(e); i++; - if (type && strcmp(sc->type, json_object_get_string(type))) + if (type && strcmp(sc->type, ucv_string_get(type))) continue; - uc_push_val(uc_value_get(func)); - uc_push_val(section_to_json(sc, i - 1)); + uc_push_val(ucv_get(func)); + uc_push_val(section_to_uval(vm, sc, i - 1)); ex = uc_call(1); @@ -934,9 +938,9 @@ uc_uci_foreach(uc_vm *vm, size_t nargs) ret = true; rv = uc_pop_val(); - stop = (json_object_is_type(rv, json_type_boolean) && !json_object_get_boolean(rv)); + stop = (ucv_type(rv) == UC_BOOLEAN && !ucv_boolean_get(rv)); - json_object_put(rv); + ucv_put(rv); if (stop) break; @@ -944,14 +948,14 @@ uc_uci_foreach(uc_vm *vm, size_t nargs) /* XXX: rethrow */ - return json_object_new_boolean(ret); + return ucv_boolean_new(ret); } -static json_object * +static uc_value_t * uc_uci_configs(uc_vm *vm, size_t nargs) { struct uci_context **c = uc_get_self("uci.cursor"); - json_object *a; + uc_value_t *a; char **configs; int i, rv; @@ -960,15 +964,10 @@ uc_uci_configs(uc_vm *vm, size_t nargs) if (rv != UCI_OK) err_return(rv); - a = json_object_new_array(); - - if (!a) { - free(configs); - err_return(UCI_ERR_MEM); - } + a = ucv_array_new(vm); for (i = 0; configs[i]; i++) - json_object_array_add(a, json_object_new_string(configs[i])); + ucv_array_push(a, ucv_string_new(configs[i])); free(configs); @@ -1006,7 +1005,7 @@ static void close_uci(void *ud) { uci_free_context((struct uci_context *)ud); } -void uc_module_init(uc_prototype *scope) +void uc_module_init(uc_value_t *scope) { uc_add_proto_functions(scope, global_fns); @@ -55,14 +55,14 @@ print_usage(const char *app) } static void -globals_init(uc_prototype *scope) +globals_init(uc_vm *vm, uc_value_t *scope) { - json_object *arr = xjs_new_array(); + uc_value_t *arr = ucv_array_new(vm); const char *p, *last; for (p = last = LIB_SEARCH_PATH;; p++) { if (*p == ':' || *p == '\0') { - json_object_array_add(arr, xjs_new_string_len(last, p - last)); + ucv_array_push(arr, ucv_string_new_length(last, p - last)); if (!*p) break; @@ -71,11 +71,11 @@ globals_init(uc_prototype *scope) } } - json_object_object_add(scope->header.jso, "REQUIRE_SEARCH_PATH", arr); + ucv_object_add(scope, "REQUIRE_SEARCH_PATH", arr); } static void -register_variable(uc_prototype *scope, const char *key, json_object *val) +register_variable(uc_value_t *scope, const char *key, uc_value_t *val) { char *name = strdup(key); char *p; @@ -87,17 +87,17 @@ register_variable(uc_prototype *scope, const char *key, json_object *val) if (!isalnum(*p) && *p != '_') *p = '_'; - json_object_object_add(scope->header.jso, name, val); + ucv_object_add(scope, name, val); free(name); } static int parse(uc_parse_config *config, uc_source *src, - bool skip_shebang, json_object *env, json_object *modules) + bool skip_shebang, uc_value_t *env, uc_value_t *modules) { - uc_prototype *globals = uc_prototype_new(NULL), *rootscope = NULL; - uc_function *entry; + uc_value_t *globals = NULL; + uc_function_t *entry; uc_vm vm = {}; char c, c2, *err; int rc = 0; @@ -131,25 +131,24 @@ parse(uc_parse_config *config, uc_source *src, goto out; } + globals = ucv_object_new(&vm); + /* load global variables */ - globals_init(globals); + globals_init(&vm, globals); /* load env variables */ if (env) { - json_object_object_foreach(env, key, val) - register_variable(globals, key, uc_value_get(val)); + ucv_object_foreach(env, key, val) + register_variable(globals, key, ucv_get(val)); } /* load std functions into global scope */ uc_lib_init(globals); /* create instance of global scope, set "global" property on it */ - rootscope = uc_protoref_new(xjs_new_object(), globals); - - json_object_object_add(rootscope->header.jso, "global", - uc_value_get(globals->header.jso)); + ucv_object_add(globals, "global", ucv_get(globals)); - rc = uc_vm_execute(&vm, entry, rootscope, modules); + rc = uc_vm_execute(&vm, entry, globals, modules); if (rc) { rc = 1; @@ -158,10 +157,6 @@ parse(uc_parse_config *config, uc_source *src, out: uc_vm_free(&vm); - uc_value_put(globals->header.jso); - - if (rootscope) - uc_value_put(rootscope->header.jso); return rc; } @@ -193,12 +188,13 @@ read_stdin(char **ptr) return uc_source_new_buffer("[stdin]", *ptr, tlen); } -static json_object * +static uc_value_t * parse_envfile(FILE *fp) { - json_object *rv = NULL; enum json_tokener_error err = json_tokener_continue; struct json_tokener *tok; + json_object *jso = NULL; + uc_value_t *rv; char buf[128]; size_t rlen; @@ -210,27 +206,32 @@ parse_envfile(FILE *fp) if (rlen == 0) break; - rv = json_tokener_parse_ex(tok, buf, rlen); + jso = json_tokener_parse_ex(tok, buf, rlen); err = json_tokener_get_error(tok); if (err != json_tokener_continue) break; } - if (err != json_tokener_success || !json_object_is_type(rv, json_type_object)) { - json_object_put(rv); - rv = NULL; + if (err != json_tokener_success || !json_object_is_type(jso, json_type_object)) { + json_object_put(jso); + + return NULL; } json_tokener_free(tok); + rv = ucv_from_json(NULL, jso); + + json_object_put(jso); + return rv; } int main(int argc, char **argv) { - json_object *env = NULL, *modules = NULL, *o, *p; + uc_value_t *env = NULL, *modules = NULL, *o, *p; uc_source *source = NULL, *envfile = NULL; char *stdin = NULL, *c; bool shebang = false; @@ -335,27 +336,27 @@ main(int argc, char **argv) goto out; } - env = env ? env : xjs_new_object(); + env = env ? env : ucv_object_new(NULL); if (c > optarg && optarg[0]) { - p = xjs_new_object(); - json_object_object_add(env, optarg, p); + p = ucv_object_new(NULL); + ucv_object_add(env, optarg, p); } else { p = env; } - json_object_object_foreach(o, key, val) - json_object_object_add(p, key, json_object_get(val)); + ucv_object_foreach(o, key, val) + ucv_object_add(p, key, ucv_get(val)); - json_object_put(o); + ucv_put(o); break; case 'm': - modules = modules ? modules : xjs_new_array(); + modules = modules ? modules : ucv_array_new(NULL); - json_object_array_add(modules, xjs_new_string(optarg)); + ucv_array_push(modules, ucv_string_new(optarg)); break; } @@ -382,8 +383,8 @@ main(int argc, char **argv) rv = parse(&config, source, shebang, env, modules); out: - json_object_put(modules); - json_object_put(env); + ucv_put(modules); + ucv_put(env); uc_source_put(source); @@ -18,7 +18,6 @@ #define __MODULE_H_ #include "lib.h" -#include "object.h" #include "vm.h" #define register_functions(scope, functions) \ @@ -34,23 +33,19 @@ }) #define declare_type(name, proto, freefn) \ - ops->ressource.define(name, proto, freefn) + ucv_ressource_type_add(name, proto, freefn) #define alloc_ressource(data, type) \ - ops->ressource.create(xjs_new_object(), type, data) + ucv_ressource_new(ucv_object_new(NULL), type, data) #define register_ressource(scope, key, res) \ json_object_object_add((scope)->header.jso, key, (res)->header.jso) -static const uc_ops *ops; +void uc_module_init(uc_value_t *scope) __attribute__((weak)); -void uc_module_init(uc_prototype *scope) __attribute__((weak)); - -void uc_module_entry(const uc_ops *_ops, uc_prototype *scope); -void uc_module_entry(const uc_ops *_ops, uc_prototype *scope) +void uc_module_entry(uc_value_t *scope); +void uc_module_entry(uc_value_t *scope) { - ops = _ops; - if (uc_module_init) uc_module_init(scope); } diff --git a/object.c b/object.c deleted file mode 100644 index 7748744..0000000 --- a/object.c +++ /dev/null @@ -1,493 +0,0 @@ -/* - * Copyright (C) 2020-2021 Jo-Philipp Wich <jo@mein.io> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <string.h> -#include <assert.h> - -#include "object.h" - -static void * -uc_object_new(uc_objtype_t type, size_t size, json_object_to_json_string_fn *tostring, json_object_delete_fn *gc) -{ - uc_objhdr *hdr = xalloc(size); - - hdr->type = type; - hdr->jso = xjs_new_object(); - - json_object_set_serializer(hdr->jso, tostring, hdr, gc); - - return hdr; -} - -static int -uc_upvalref_tostring(json_object *jso, struct printbuf *pb, int level, int flags) -{ - return sprintbuf(pb, "<upvalref %p>", jso); -} - -static void -uc_upvalref_gc(json_object *jso, void *userdata) -{ - uc_upvalref *up = userdata; - - uc_value_put(up->value); - free(up); -} - -uc_upvalref * -uc_upvalref_new(size_t slot) -{ - uc_upvalref *up; - - up = uc_object_new(UC_OBJ_UPVAL, sizeof(*up), uc_upvalref_tostring, uc_upvalref_gc); - up->slot = slot; - - return up; -} - -static int -uc_function_tostring(json_object *jso, struct printbuf *pb, int level, int flags) -{ - return sprintbuf(pb, "<function %p>", jso); -} - -static void -uc_function_gc(json_object *jso, void *userdata) -{ - uc_function *fn = userdata; - - uc_chunk_free(&fn->chunk); - uc_source_put(fn->source); - - free(fn); -} - -uc_function * -uc_function_new(const char *name, size_t srcpos, uc_source *source) -{ - size_t namelen = 0; - uc_function *fn; - - if (name) - namelen = strlen(name) + 1; - - fn = uc_object_new(UC_OBJ_FUNCTION, ALIGN(sizeof(*fn)) + namelen, uc_function_tostring, uc_function_gc); - fn->name = name ? strcpy((char *)fn + ALIGN(sizeof(*fn)), name) : NULL; - fn->nargs = 0; - fn->nupvals = 0; - fn->srcpos = srcpos; - fn->source = uc_source_get(source); - fn->vararg = false; - - uc_chunk_init(&fn->chunk); - - return fn; -} - -size_t -uc_function_get_srcpos(uc_function *fn, size_t off) -{ - size_t pos = uc_chunk_debug_get_srcpos(&fn->chunk, off); - - return pos ? fn->srcpos + pos : 0; -} - -static int -uc_closure_tostring(json_object *jso, struct printbuf *pb, int level, int flags) -{ - bool strict = (level > 0) || (flags & JSON_C_TO_STRING_STRICT); - uc_closure *closure = json_object_get_userdata(jso); - uc_function *function = closure->function; - json_object *argname; - size_t i; - - sprintbuf(pb, "%s%s", - strict ? "\"" : "", - closure->is_arrow ? "" : "function"); - - if (function->name) - sprintbuf(pb, " %s", function->name); - - sprintbuf(pb, "("); - - for (i = 1; i <= function->nargs; i++) { - argname = uc_chunk_debug_get_variable(&function->chunk, i - 1, i, false); - - if (i > 1) - sprintbuf(pb, ", "); - - if (i == function->nargs && function->vararg) - sprintbuf(pb, "..."); - - if (argname) - sprintbuf(pb, "%s", json_object_get_string(argname)); - else - sprintbuf(pb, "[arg%zu]", i); - - uc_value_put(argname); - } - - return sprintbuf(pb, ")%s { ... }%s", - closure->is_arrow ? " =>" : "", - strict ? "\"" : ""); -} - -static void -uc_closure_gc(json_object *jso, void *userdata) -{ - uc_closure *closure = userdata; - uc_function *function = closure->function; - size_t i; - - for (i = 0; i < function->nupvals; i++) - uc_value_put(closure->upvals[i]->header.jso); - - uc_value_put(function->header.jso); - - free(closure); -} - -uc_closure * -uc_closure_new(uc_function *function, bool arrow_fn) -{ - uc_closure *closure; - - closure = uc_object_new(UC_OBJ_CLOSURE, - ALIGN(sizeof(*closure)) + (sizeof(uc_upvalref *) * function->nupvals), - uc_closure_tostring, uc_closure_gc); - - closure->function = function; - closure->is_arrow = arrow_fn; - closure->upvals = function->nupvals ? ((void *)closure + ALIGN(sizeof(*closure))) : NULL; - - return closure; -} - -static int -uc_cfunction_tostring(json_object *jso, struct printbuf *pb, int level, int flags) -{ - bool strict = (level > 0) || (flags & JSON_C_TO_STRING_STRICT); - uc_cfunction *cfn = json_object_get_userdata(jso); - - return sprintbuf(pb, "%sfunction%s%s(...) { [native code] }%s", - strict ? "\"" : "", - cfn->name ? " " : "", - cfn->name ? cfn->name : "", - strict ? "\"" : ""); -} - -static void -uc_cfunction_gc(json_object *jso, void *userdata) -{ - free(userdata); -} - -uc_cfunction * -uc_cfunction_new(const char *name, uc_cfn_ptr fptr) -{ - size_t namelen = 0; - uc_cfunction *cfn; - - if (name) - namelen = strlen(name) + 1; - - cfn = uc_object_new(UC_OBJ_CFUNCTION, ALIGN(sizeof(*cfn)) + namelen, uc_cfunction_tostring, uc_cfunction_gc); - cfn->name = name ? strcpy((char *)cfn + ALIGN(sizeof(*cfn)), name) : NULL; - cfn->cfn = fptr; - - return cfn; -} - -static int -uc_regexp_tostring(json_object *jso, struct printbuf *pb, int level, int flags) -{ - bool strict = (level > 0) || (flags & JSON_C_TO_STRING_STRICT); - uc_regexp *re = json_object_get_userdata(jso); - json_object *s; - const char *p; - size_t len; - - sprintbuf(pb, "%s/", strict ? "\"" : ""); - - s = xjs_new_string(re->pattern); - - if (strict) - for (p = json_object_to_json_string(s) + 1, len = strlen(p) - 1; len > 0; len--, p++) - sprintbuf(pb, "%c", *p); - else - sprintbuf(pb, "%s", json_object_get_string(s)); - - uc_value_put(s); - - return sprintbuf(pb, "/%s%s%s%s", - re->global ? "g" : "", - re->icase ? "i" : "", - re->newline ? "s" : "", - strict ? "\"" : ""); -} - -static void -uc_regexp_gc(json_object *jso, void *userdata) -{ - uc_regexp *re = userdata; - - regfree(&re->re); - free(re); -} - -uc_regexp * -uc_regexp_new(const char *pattern, bool icase, bool newline, bool global, char **err) -{ - int cflags = REG_EXTENDED, res; - uc_regexp *re; - size_t len; - - re = uc_object_new(UC_OBJ_REGEXP, ALIGN(sizeof(*re)) + strlen(pattern) + 1, uc_regexp_tostring, uc_regexp_gc); - re->icase = icase; - re->global = global; - re->newline = newline; - re->pattern = strcpy((char *)re + ALIGN(sizeof(*re)), pattern); - - if (icase) - cflags |= REG_ICASE; - - if (newline) - cflags |= REG_NEWLINE; - - res = regcomp(&re->re, pattern, cflags); - - if (res != 0) { - if (err) { - len = regerror(res, &re->re, NULL, 0); - *err = xalloc(len); - - regerror(res, &re->re, *err, len); - } - - uc_value_put(re->header.jso); - - return NULL; - } - - json_object_object_add(re->header.jso, "source", xjs_new_string(pattern)); - json_object_object_add(re->header.jso, "i", xjs_new_boolean(icase)); - json_object_object_add(re->header.jso, "g", xjs_new_boolean(global)); - json_object_object_add(re->header.jso, "s", xjs_new_boolean(newline)); - - return re; -} - -static void -uc_prototype_gc(json_object *jso, void *userdata) -{ - uc_prototype *proto = userdata; - - if (proto->parent) - uc_value_put(proto->parent->header.jso); - - free(proto); -} - -uc_prototype * -uc_prototype_new(uc_prototype *parent) -{ - uc_prototype *proto; - - proto = uc_object_new(UC_OBJ_PROTOTYPE, sizeof(*proto), NULL, uc_prototype_gc); - - if (parent) { - proto->parent = parent; - uc_value_get(parent->header.jso); - } - - return proto; -} - -json_object * -uc_prototype_lookup(uc_prototype *proto, const char *key) -{ - json_object *val; - - for (; proto; proto = proto->parent) - if (json_object_object_get_ex(proto->header.jso, key, &val)) - return val; - - return NULL; -} - -uc_prototype * -uc_protoref_new(json_object *value, uc_prototype *proto) -{ - uc_prototype *ref; - - if (!json_object_is_type(value, json_type_object) && - !json_object_is_type(value, json_type_array)) - return NULL; - - ref = xalloc(sizeof(*ref)); - ref->header.type = UC_OBJ_PROTOTYPE; - ref->header.jso = value; - - if (proto) { - ref->parent = proto; - uc_value_get(proto->header.jso); - } - - json_object_set_serializer(ref->header.jso, NULL, ref, uc_prototype_gc); - - return ref; -} - - -static uc_ressource_types res_types; - -uc_ressource_type * -uc_ressource_type_add(const char *name, uc_prototype *proto, void (*freefn)(void *)) -{ - uc_ressource_type *existing; - - existing = uc_ressource_type_lookup(name); - - if (existing) { - uc_value_put(proto->header.jso); - - return existing; - } - - uc_vector_grow(&res_types); - - res_types.entries[res_types.count].name = name; - res_types.entries[res_types.count].proto = proto; - res_types.entries[res_types.count].free = freefn; - - return &res_types.entries[res_types.count++]; -} - -static uc_ressource_type * -uc_ressource_type_get(size_t type) -{ - return (type < res_types.count) ? &res_types.entries[type] : NULL; -} - -uc_ressource_type * -uc_ressource_type_lookup(const char *name) -{ - size_t i; - - for (i = 0; i < res_types.count; i++) - if (!strcmp(res_types.entries[i].name, name)) - return &res_types.entries[i]; - - return NULL; -} - -static int -uc_ressource_tostring(json_object *jso, struct printbuf *pb, int level, int flags) -{ - bool strict = (level > 0) || (flags & JSON_C_TO_STRING_STRICT); - uc_ressource *res = json_object_get_userdata(jso); - uc_ressource_type *type = uc_ressource_type_get(res->type); - - return sprintbuf(pb, "%s<%s %p>%s", - strict ? "\"" : "", - type ? type->name : "ressource", - res->data, - strict ? "\"" : ""); -} - -static void -uc_ressource_gc(json_object *jso, void *userdata) -{ - uc_ressource *res = userdata; - uc_ressource_type *type = uc_ressource_type_get(res->type); - - if (type && type->free) - type->free(res->data); - - free(res); -} - -uc_ressource * -uc_ressource_new(json_object *jso, uc_ressource_type *type, void *data) -{ - uc_ressource *res; - - if (!jso) - return NULL; - - res = xalloc(sizeof(*res)); - res->header.type = UC_OBJ_RESSOURCE; - res->header.jso = jso; - - res->type = type - res_types.entries; - res->data = data; - - json_object_set_serializer(res->header.jso, uc_ressource_tostring, res, uc_ressource_gc); - - return res; -} - -void ** -uc_ressource_dataptr(json_object *jso, const char *name) -{ - uc_ressource_type *type; - uc_ressource *res; - - if (!uc_object_is_type(jso, UC_OBJ_RESSOURCE)) - return NULL; - - res = uc_object_as_ressource(jso); - - if (name) { - type = uc_ressource_type_lookup(name); - - if (!type || type != uc_ressource_type_get(res->type)) - return NULL; - } - - return &res->data; -} - -uc_prototype * -uc_ressource_prototype(json_object *jso) -{ - uc_ressource_type *type; - uc_ressource *res; - - if (!uc_object_is_type(jso, UC_OBJ_RESSOURCE)) - return NULL; - - res = uc_object_as_ressource(jso); - type = uc_ressource_type_get(res->type); - - return type ? type->proto : NULL; -} - - -#ifdef __GNUC__ - -__attribute__((destructor)) -static void uc_ressource_types_free(void) -{ - size_t i; - - for (i = 0; i < res_types.count; i++) - uc_value_put(res_types.entries[i].proto->header.jso); - - uc_vector_clear(&res_types); -} - -#endif diff --git a/object.h b/object.h deleted file mode 100644 index 74cc835..0000000 --- a/object.h +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright (C) 2020-2021 Jo-Philipp Wich <jo@mein.io> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef __OBJECT_H_ -#define __OBJECT_H_ - -#include <stddef.h> -#include <stdint.h> -#include <stdbool.h> -#include <regex.h> - -#ifdef JSONC - #include <json.h> -#else - #include <json-c/json.h> -#endif - -#include "source.h" -#include "chunk.h" -#include "util.h" - -typedef enum { - UC_OBJ_INVAL, - UC_OBJ_UPVAL, - UC_OBJ_FUNCTION, - UC_OBJ_CLOSURE, - UC_OBJ_CFUNCTION, - UC_OBJ_REGEXP, - UC_OBJ_PROTOTYPE, - UC_OBJ_RESSOURCE -} uc_objtype_t; - -typedef struct { - uc_objtype_t type; - json_object *jso; -} uc_objhdr; - -typedef struct uc_upvalref { - uc_objhdr header; - size_t slot; - bool closed; - json_object *value; - struct uc_upvalref *next; -} uc_upvalref; - -typedef struct { - uc_objhdr header; - char *name; - bool arrow, vararg; - size_t nargs; - size_t nupvals; - size_t srcpos; - uc_chunk chunk; - uc_source *source; -} uc_function; - -typedef struct { - uc_objhdr header; - uc_function *function; - uc_upvalref **upvals; - bool is_arrow; -} uc_closure; - -struct uc_vm; -typedef json_object *(*uc_cfn_ptr)(struct uc_vm *, size_t); - -typedef struct { - uc_objhdr header; - char *name; - uc_cfn_ptr cfn; -} uc_cfunction; - -typedef struct { - uc_objhdr header; - regex_t re; - char *pattern; - bool icase, newline, global; -} uc_regexp; - -struct uc_prototype { - uc_objhdr header; - struct uc_prototype *parent; -}; - -typedef struct uc_prototype uc_prototype; - -typedef struct { - uc_objhdr header; - size_t type; - void *data; -} uc_ressource; - -typedef struct { - const char *name; - uc_prototype *proto; - void (*free)(void *); -} uc_ressource_type; - -uc_declare_vector(uc_ressource_types, uc_ressource_type); - -uc_upvalref *uc_upvalref_new(size_t slot); -uc_function *uc_function_new(const char *name, size_t line, uc_source *source); -uc_closure *uc_closure_new(uc_function *function, bool arrow_fn); -uc_cfunction *uc_cfunction_new(const char *name, uc_cfn_ptr cfn); -uc_regexp *uc_regexp_new(const char *pattern, bool icase, bool newline, bool global, char **err); -uc_prototype *uc_prototype_new(uc_prototype *parent); -uc_prototype *uc_protoref_new(json_object *value, uc_prototype *proto); -json_object *uc_prototype_lookup(uc_prototype *proto, const char *key); - -uc_ressource_type *uc_ressource_type_add(const char *name, uc_prototype *proto, void (*freefn)(void *)); -uc_ressource_type *uc_ressource_type_lookup(const char *name); - -uc_ressource *uc_ressource_new(json_object *jso, uc_ressource_type *type, void *data); -uc_prototype *uc_ressource_prototype(json_object *jso); -void **uc_ressource_dataptr(json_object *jso, const char *name); - -size_t uc_function_get_srcpos(uc_function *function, size_t off); - -static inline uc_objtype_t -uc_object_type(json_object *jso) -{ - uc_objhdr *hdr = json_object_get_userdata(jso); - - return hdr ? hdr->type : UC_OBJ_INVAL; -} - -static inline bool -uc_object_is_type(json_object *jso, uc_objtype_t type) -{ - return uc_object_type(jso) == type; -} - -static inline uc_upvalref * -uc_object_as_upvalref(json_object *jso) -{ - return json_object_get_userdata(jso); -} - -static inline uc_function * -uc_object_as_function(json_object *jso) -{ - return json_object_get_userdata(jso); -} - -static inline uc_closure * -uc_object_as_closure(json_object *jso) -{ - return json_object_get_userdata(jso); -} - -static inline uc_cfunction * -uc_object_as_cfunction(json_object *jso) -{ - return json_object_get_userdata(jso); -} - -static inline uc_regexp * -uc_object_as_regexp(json_object *jso) -{ - return json_object_get_userdata(jso); -} - -static inline uc_prototype * -uc_object_as_prototype(json_object *jso) -{ - return json_object_get_userdata(jso); -} - -static inline uc_ressource * -uc_object_as_ressource(json_object *jso) -{ - return json_object_get_userdata(jso); -} - -static inline bool -uc_object_is_callable(json_object *jso) -{ - switch (uc_object_type(jso)) { - case UC_OBJ_CLOSURE: - case UC_OBJ_CFUNCTION: - return true; - - default: - return false; - } -} - -#endif /* __OBJECT_H_ */ diff --git a/tests/custom/00_syntax/21_regex_literals b/tests/custom/00_syntax/21_regex_literals index 3af53bb..6d85e97 100644 --- a/tests/custom/00_syntax/21_regex_literals +++ b/tests/custom/00_syntax/21_regex_literals @@ -23,7 +23,7 @@ regular expression engine. Testing regular expression type. -- Expect stdout -- -object +regexp -- End -- -- Testcase -- @@ -0,0 +1,1755 @@ +/* + * Copyright (C) 2021 Jo-Philipp Wich <jo@mein.io> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <stdarg.h> +#include <stdlib.h> +#include <assert.h> +#include <endian.h> +#include <errno.h> +#include <math.h> + +#include "types.h" +#include "util.h" +#include "vm.h" + +uc_type_t +ucv_type(uc_value_t *uv) +{ + uc_type_t type = ((uintptr_t)uv & 3); + + if (type == UC_NULL && uv != NULL) + type = uv->type; + + return type; +} + +const char * +ucv_typename(uc_value_t *uv) +{ + switch (ucv_type(uv)) { + case UC_NULL: return "null"; + case UC_INTEGER: return "integer"; + case UC_BOOLEAN: return "boolean"; + case UC_STRING: return "string"; + case UC_DOUBLE: return "double"; + case UC_ARRAY: return "array"; + case UC_OBJECT: return "object"; + case UC_REGEXP: return "regexp"; + case UC_FUNCTION: return "function"; + case UC_CFUNCTION: return "cfunction"; + case UC_CLOSURE: return "closure"; + case UC_UPVALUE: return "upvalue"; + case UC_RESSOURCE: return "ressource"; + } + + return "unknown"; +} + +static uc_ressource_type_t * +ucv_ressource_type_get(size_t type); + +static void +ucv_unref(uc_weakref_t *ref) +{ + ref->prev->next = ref->next; + ref->next->prev = ref->prev; +} + +static void +ucv_ref(uc_weakref_t *head, uc_weakref_t *item) +{ + item->next = head->next; + item->prev = head; + head->next->prev = item; + head->next = item; +} + +#if 0 +static uc_weakref_t * +ucv_get_weakref(uc_value_t *uv) +{ + switch (ucv_type(uv)) { + case UC_ARRAY: + return &((uc_array_t *)uv)->ref; + + case UC_OBJECT: + return &((uc_object_t *)uv)->ref; + + case UC_CLOSURE: + return &((uc_closure_t *)uv)->ref; + + default: + return NULL; + } +} +#endif + +static void +ucv_put_value(uc_value_t *uv, bool retain) +{ + if (uv == NULL || (uintptr_t)uv & 3) + return; + + assert(uv->refcount > 0); + + if (uv->refcount > 0) + uv->refcount--; + + if (uv->refcount == 0) + ucv_free(uv, retain); +} + +static void +ucv_gc_mark(uc_value_t *uv); + +static void +ucv_gc_mark(uc_value_t *uv) +{ + uc_function_t *function; + uc_closure_t *closure; + uc_upvalref_t *upval; + uc_object_t *object; + uc_array_t *array; + struct lh_entry *entry; + size_t i; + + switch (ucv_type(uv)) { + case UC_ARRAY: + array = (uc_array_t *)uv; + + ucv_gc_mark(array->proto); + + for (i = 0; i < array->count; i++) + ucv_gc_mark(array->entries[i]); + + if (array->ref.next) + ucv_set_mark(uv); + + break; + + case UC_OBJECT: + object = (uc_object_t *)uv; + + ucv_gc_mark(object->proto); + + lh_foreach(object->table, entry) + ucv_gc_mark((uc_value_t *)lh_entry_v(entry)); + + if (object->ref.next) + ucv_set_mark(uv); + + break; + + case UC_CLOSURE: + closure = (uc_closure_t *)uv; + function = closure->function; + + for (i = 0; i < function->nupvals; i++) + ucv_gc_mark((uc_value_t *)closure->upvals[i]); + + ucv_gc_mark((uc_value_t *)function); + + if (closure->ref.next) + ucv_set_mark(uv); + + break; + + case UC_UPVALUE: + upval = (uc_upvalref_t *)uv; + ucv_gc_mark(upval->value); + break; + + default: + break; + } +} + +void +ucv_free(uc_value_t *uv, bool retain) +{ + uc_ressource_type_t *restype; + uc_ressource_t *ressource; + uc_function_t *function; + uc_closure_t *closure; + uc_upvalref_t *upval; + uc_regexp_t *regexp; + uc_object_t *object; + uc_array_t *array; + uc_weakref_t *ref; + size_t i; + + if (uv == NULL || (uintptr_t)uv & 3) + return; + + if (uv->mark) + return; + + uv->mark = true; + + ref = NULL; + + switch (uv->type) { + case UC_ARRAY: + array = (uc_array_t *)uv; + ref = &array->ref; + ucv_put_value(array->proto, retain); + + for (i = 0; i < array->count; i++) + ucv_put_value(array->entries[i], retain); + + uc_vector_clear(array); + break; + + case UC_OBJECT: + object = (uc_object_t *)uv; + ref = &object->ref; + ucv_put_value(object->proto, retain); + lh_table_free(object->table); + break; + + case UC_REGEXP: + regexp = (uc_regexp_t *)uv; + regfree(®exp->regexp); + break; + + case UC_FUNCTION: + function = (uc_function_t *)uv; + uc_chunk_free(&function->chunk); + uc_source_put(function->source); + break; + + case UC_CLOSURE: + closure = (uc_closure_t *)uv; + function = closure->function; + ref = &closure->ref; + + for (i = 0; i < function->nupvals; i++) + ucv_put_value((uc_value_t *)closure->upvals[i], retain); + + ucv_put_value((uc_value_t *)function, retain); + break; + + case UC_RESSOURCE: + ressource = (uc_ressource_t *)uv; + restype = ucv_ressource_type_get(ressource->type); + + if (restype && restype->free) + restype->free(ressource->data); + + break; + + case UC_UPVALUE: + upval = (uc_upvalref_t *)uv; + ucv_put_value(upval->value, retain); + break; + } + + if (!ref || !retain) { + if (ref && ref->prev && ref->next) + ucv_unref(ref); + + free(uv); + } + else { + uv->type = UC_NULL; + } +} + +void +ucv_put(uc_value_t *uv) +{ + ucv_put_value(uv, false); +} + +uc_value_t * +ucv_get(uc_value_t *uv) +{ + if (uv == NULL || (uintptr_t)uv & 3) + return uv; + + assert(uv->refcount < 0x03ffffff); + + uv->refcount++; + + return uv; +} + +uc_value_t * +ucv_boolean_new(bool val) +{ + uintptr_t pv = UC_BOOLEAN | (val << 2); + + return (uc_value_t *)pv; +} + +bool +ucv_boolean_get(uc_value_t *uv) +{ + uintptr_t pv = (uintptr_t)uv; + + if ((pv & 3) == UC_BOOLEAN) + return (pv >> 2) & 1; + + return false; +} + + +uc_value_t * +ucv_string_new(const char *str) +{ + return ucv_string_new_length(str, strlen(str)); +} + +uc_value_t * +ucv_string_new_length(const char *str, size_t length) +{ + uc_string_t *ustr; + uintptr_t pv; + size_t i; + char *s; + + if ((length + 1) < sizeof(void *)) { + pv = UC_STRING | (length << 2); + +#if __BYTE_ORDER == __LITTLE_ENDIAN + s = (char *)&pv + 1; +#else + s = (char *)&pv; +#endif + + for (i = 0; i < length; i++) + s[i] = str[i]; + + return (uc_value_t *)pv; + } + + ustr = xalloc(sizeof(*ustr) + length + 1); + ustr->header.type = UC_STRING; + ustr->header.refcount = 1; + ustr->length = length; + memcpy(ustr->str, str, length); + + return &ustr->header; +} + +uc_stringbuf_t * +ucv_stringbuf_new(void) +{ + uc_stringbuf_t *sb = xprintbuf_new(); + uc_string_t ustr = { + .header = { + .type = UC_STRING, + .refcount = 1 + } + }; + + printbuf_memappend_fast(sb, (char *)&ustr, sizeof(ustr)); + + return sb; +} + +uc_value_t * +ucv_stringbuf_finish(uc_stringbuf_t *sb) +{ + uc_string_t *ustr = (uc_string_t *)sb->buf; + + ustr->length = printbuf_length(sb) - offsetof(uc_string_t, str); + + free(sb); + + return &ustr->header; +} + +char * +_ucv_string_get(uc_value_t **uv) +{ + uc_string_t *str; + + switch ((uintptr_t)*uv & 3) { + case UC_STRING: +#if __BYTE_ORDER == __LITTLE_ENDIAN + return (char *)uv + 1; +#else + return (char *)uv; +#endif + + case UC_NULL: + if (*uv != NULL && (*uv)->type == UC_STRING) { + str = (uc_string_t *)*uv; + + return str->str; + } + } + + return NULL; +} + +size_t +ucv_string_length(uc_value_t *uv) +{ + uc_string_t *str = (uc_string_t *)uv; + uintptr_t pv = (uintptr_t)uv; + + if ((pv & 3) == UC_STRING) + return (pv & 0xff) >> 2; + else if (uv != NULL && uv->type == UC_STRING) + return str->length; + + return 0; +} + + +uc_value_t * +ucv_int64_new(int64_t n) +{ + uint64_t uval = (n < 0) ? ((n > INT64_MIN) ? (~n + 1) : INT64_MAX) : n; + uint64_t max = (1ULL << ((sizeof(void *) * 8) - 3)) - 1; + uc_integer_t *integer; + uintptr_t pv; + + if (uval <= max) { + pv = UC_INTEGER | ((n < 0) << 2) | (uval << 3); + + return (uc_value_t *)pv; + } + + integer = xalloc(sizeof(*integer)); + integer->header.type = UC_INTEGER; + integer->header.refcount = 1; + integer->header.u64 = 0; + integer->i.s64 = n; + + return &integer->header; +} + +uc_value_t * +ucv_uint64_new(uint64_t n) +{ + uint64_t max = (1ULL << ((sizeof(void *) * 8) - 3)) - 1; + uc_integer_t *integer; + uintptr_t pv; + + if (n <= max) { + pv = UC_INTEGER | (n << 3); + + return (uc_value_t *)pv; + } + + integer = xalloc(sizeof(*integer)); + integer->header.type = UC_INTEGER; + integer->header.refcount = 1; + integer->header.u64 = 1; + integer->i.u64 = n; + + return &integer->header; +} + +uint64_t +ucv_uint64_get(uc_value_t *uv) +{ + uintptr_t pv = (uintptr_t)uv; + uc_integer_t *integer; + + errno = 0; + + if ((pv & 3) == UC_INTEGER) { + if (((pv >> 2) & 1) == 0) + return (uint64_t)(pv >> 3); + + errno = ERANGE; + + return 0; + } + else if (uv != NULL && uv->type == UC_INTEGER) { + integer = (uc_integer_t *)uv; + + if (integer->header.u64) + return integer->i.u64; + + if (integer->i.s64 >= 0) + return (uint64_t)integer->i.s64; + + errno = ERANGE; + + return 0; + } + + errno = EINVAL; + + return 0; +} + +int64_t +ucv_int64_get(uc_value_t *uv) +{ + uintptr_t pv = (uintptr_t)uv; + uc_integer_t *integer; + + errno = 0; + + if ((pv & 3) == UC_INTEGER) { + if (((pv >> 2) & 1) == 0) + return (int64_t)(pv >> 3); + + return -(int64_t)(pv >> 3); + } + else if (uv != NULL && uv->type == UC_INTEGER) { + integer = (uc_integer_t *)uv; + + if (integer->header.u64 && integer->i.u64 <= INT64_MAX) + return (int64_t)integer->i.u64; + + if (!integer->header.u64) + return integer->i.s64; + + errno = ERANGE; + + return 0; + } + + errno = EINVAL; + + return 0; +} + + +uc_value_t * +ucv_double_new(double d) +{ + uc_double_t *dbl; + + dbl = xalloc(sizeof(*dbl)); + dbl->header.type = UC_DOUBLE; + dbl->header.refcount = 1; + dbl->dbl = d; + + return &dbl->header; +} + +double +ucv_double_get(uc_value_t *uv) +{ + uc_double_t *dbl; + + errno = 0; + + if (ucv_type(uv) != UC_DOUBLE) { + errno = EINVAL; + + return NAN; + } + + dbl = (uc_double_t *)uv; + + return dbl->dbl; +} + + +uc_value_t * +ucv_array_new(uc_vm *vm) +{ + return ucv_array_new_length(vm, 0); +} + +uc_value_t * +ucv_array_new_length(uc_vm *vm, size_t length) +{ + uc_array_t *array; + + /* XXX */ + length = 0; + + array = xalloc(sizeof(*array) + length * sizeof(array->entries[0])); + array->header.type = UC_ARRAY; + array->header.refcount = 1; + + if (length > 0) + array->count = length; + + uc_vector_grow(array); + + if (vm) + ucv_ref(&vm->values, &array->ref); + + return &array->header; +} + +uc_value_t * +ucv_array_pop(uc_value_t *uv) +{ + uc_array_t *array = (uc_array_t *)uv; + uc_value_t *item; + + if (ucv_type(uv) != UC_ARRAY || array->count == 0) + return NULL; + + item = ucv_get(array->entries[array->count - 1]); + + ucv_array_delete(uv, array->count - 1, 1); + + return item; +} + +uc_value_t * +ucv_array_push(uc_value_t *uv, uc_value_t *item) +{ + uc_array_t *array = (uc_array_t *)uv; + + if (ucv_type(uv) != UC_ARRAY) + return NULL; + + ucv_array_set(uv, array->count, item); + + return item; +} + +uc_value_t * +ucv_array_shift(uc_value_t *uv) +{ + uc_array_t *array = (uc_array_t *)uv; + uc_value_t *item; + + if (ucv_type(uv) != UC_ARRAY || array->count == 0) + return NULL; + + item = ucv_get(array->entries[0]); + + ucv_array_delete(uv, 0, 1); + + return item; +} + +uc_value_t * +ucv_array_unshift(uc_value_t *uv, uc_value_t *item) +{ + uc_array_t *array = (uc_array_t *)uv; + size_t i; + + if (ucv_type(uv) != UC_ARRAY || array->count == 0) + return NULL; + + array->count++; + uc_vector_grow(array); + + for (i = array->count; i > 1; i--) + array->entries[i - 1] = array->entries[i - 2]; + + array->entries[0] = item; + + return item; +} + +void +ucv_array_sort(uc_value_t *uv, int (*cmp)(const void *, const void *)) +{ + uc_array_t *array = (uc_array_t *)uv; + + if (ucv_type(uv) != UC_ARRAY || array->count <= 1) + return; + + qsort(array->entries, array->count, sizeof(array->entries[0]), cmp); +} + +bool +ucv_array_delete(uc_value_t *uv, size_t offset, size_t count) +{ + uc_array_t *array = (uc_array_t *)uv; + size_t i; + + if (ucv_type(uv) != UC_ARRAY || array->count == 0) + return false; + + if (offset >= array->count) + return false; + + if ((offset + count) < offset) + return false; + + if ((offset + count) > array->count) + count = array->count - offset; + + for (i = 0; i < count; i++) + ucv_put(array->entries[offset + i]); + + memmove(&array->entries[offset], + &array->entries[offset + count], + (array->count - (offset + count)) * sizeof(array->entries[0])); + + array->count -= count; + + uc_vector_grow(array); + + return true; +} + +bool +ucv_array_set(uc_value_t *uv, size_t index, uc_value_t *item) +{ + uc_array_t *array = (uc_array_t *)uv; + + if (ucv_type(uv) != UC_ARRAY) + return false; + + if (index >= array->count) { + array->count = index + 1; + uc_vector_grow(array); + } + else { + ucv_put(array->entries[index]); + } + + array->entries[index] = item; + + return true; +} + +uc_value_t * +ucv_array_get(uc_value_t *uv, size_t index) +{ + uc_array_t *array = (uc_array_t *)uv; + + if (ucv_type(uv) != UC_ARRAY) + return NULL; + + if (index >= array->count) + return NULL; + + return array->entries[index]; +} +size_t +ucv_array_length(uc_value_t *uv) +{ + uc_array_t *array = (uc_array_t *)uv; + + if (ucv_type(uv) != UC_ARRAY) + return 0; + + return array->count; +} + + +static void +ucv_free_object_entry(struct lh_entry *entry) +{ + free(lh_entry_k(entry)); + ucv_put(lh_entry_v(entry)); +} + +uc_value_t * +ucv_object_new(uc_vm *vm) +{ + struct lh_table *table; + uc_object_t *object; + + table = lh_kchar_table_new(16, ucv_free_object_entry); + + if (!table) { + fprintf(stderr, "Out of memory\n"); + abort(); + } + + object = xalloc(sizeof(*object)); + object->header.type = UC_OBJECT; + object->header.refcount = 1; + object->table = table; + + if (vm) + ucv_ref(&vm->values, &object->ref); + + return &object->header; +} + +bool +ucv_object_add(uc_value_t *uv, const char *key, uc_value_t *val) +{ + uc_object_t *object = (uc_object_t *)uv; + struct lh_entry *existing_entry; + uc_value_t *existing_value; + unsigned long hash; + + if (ucv_type(uv) != UC_OBJECT) + return false; + + hash = lh_get_hash(object->table, (const void *)key); + existing_entry = lh_table_lookup_entry_w_hash(object->table, (const void *)key, hash); + + if (existing_entry == NULL) { + return (lh_table_insert_w_hash(object->table, xstrdup(key), val, hash, 0) == 0); + } + + existing_value = (uc_value_t *)lh_entry_v(existing_entry); + + if (existing_value) + ucv_put(existing_value); + + existing_entry->v = val; + + return true; +} + +bool +ucv_object_delete(uc_value_t *uv, const char *key) +{ + uc_object_t *object = (uc_object_t *)uv; + + if (ucv_type(uv) != UC_OBJECT) + return false; + + return (lh_table_delete(object->table, key) == 0); +} + +uc_value_t * +ucv_object_get(uc_value_t *uv, const char *key, bool *found) +{ + uc_object_t *object = (uc_object_t *)uv; + uc_value_t *val = NULL; + bool rv; + + if (found != NULL) + *found = false; + + if (ucv_type(uv) != UC_OBJECT) + return NULL; + + rv = lh_table_lookup_ex(object->table, (const void *)key, (void **)&val); + + if (found != NULL) + *found = rv; + + return val; +} + +size_t +ucv_object_length(uc_value_t *uv) +{ + uc_object_t *object = (uc_object_t *)uv; + + if (ucv_type(uv) != UC_OBJECT) + return 0; + + return lh_table_length(object->table); +} + + +uc_value_t * +ucv_function_new(const char *name, size_t srcpos, uc_source *source) +{ + size_t namelen = 0; + uc_function_t *fn; + + if (name) + namelen = strlen(name); + + fn = xalloc(sizeof(*fn) + namelen + 1); + fn->header.type = UC_FUNCTION; + fn->header.refcount = 1; + + if (name) + strcpy(fn->name, name); + + fn->nargs = 0; + fn->nupvals = 0; + fn->srcpos = srcpos; + fn->source = uc_source_get(source); + fn->vararg = false; + + uc_chunk_init(&fn->chunk); + + return &fn->header; +} + +size_t +ucv_function_srcpos(uc_value_t *uv, size_t off) +{ + uc_function_t *fn = (uc_function_t *)uv; + size_t pos; + + if (ucv_type(uv) != UC_FUNCTION) + return 0; + + pos = uc_chunk_debug_get_srcpos(&fn->chunk, off); + + return pos ? fn->srcpos + pos : 0; +} + + +uc_value_t * +ucv_cfunction_new(const char *name, uc_cfn_ptr_t fptr) +{ + uc_cfunction_t *cfn; + size_t namelen = 0; + + if (name) + namelen = strlen(name); + + cfn = xalloc(sizeof(*cfn) + namelen + 1); + cfn->header.type = UC_CFUNCTION; + cfn->header.refcount = 1; + + if (name) + strcpy(cfn->name, name); + + cfn->cfn = fptr; + + return &cfn->header; +} + + +uc_value_t * +ucv_closure_new(uc_vm *vm, uc_function_t *function, bool arrow_fn) +{ + uc_closure_t *closure; + + closure = xalloc(sizeof(*closure) + (sizeof(uc_upvalref_t *) * function->nupvals)); + closure->header.type = UC_CLOSURE; + closure->header.refcount = 1; + closure->function = function; + closure->is_arrow = arrow_fn; + closure->upvals = function->nupvals ? ((void *)closure + ALIGN(sizeof(*closure))) : NULL; + + if (vm) + ucv_ref(&vm->values, &closure->ref); + + return &closure->header; +} + + +static uc_ressource_types_t res_types; + +uc_ressource_type_t * +ucv_ressource_type_add(const char *name, uc_value_t *proto, void (*freefn)(void *)) +{ + uc_ressource_type_t *existing; + + existing = ucv_ressource_type_lookup(name); + + if (existing) { + ucv_put(proto); + + return existing; + } + + uc_vector_grow(&res_types); + + res_types.entries[res_types.count].name = name; + res_types.entries[res_types.count].proto = proto; + res_types.entries[res_types.count].free = freefn; + + return &res_types.entries[res_types.count++]; +} + +static uc_ressource_type_t * +ucv_ressource_type_get(size_t type) +{ + return (type < res_types.count) ? &res_types.entries[type] : NULL; +} + +uc_ressource_type_t * +ucv_ressource_type_lookup(const char *name) +{ + size_t i; + + for (i = 0; i < res_types.count; i++) + if (!strcmp(res_types.entries[i].name, name)) + return &res_types.entries[i]; + + return NULL; +} + + +uc_value_t * +ucv_ressource_new(uc_ressource_type_t *type, void *data) +{ + uc_ressource_t *res; + + res = xalloc(sizeof(*res)); + res->header.type = UC_RESSOURCE; + res->header.refcount = 1; + res->type = type - res_types.entries; + res->data = data; + + return &res->header; +} + +void ** +ucv_ressource_dataptr(uc_value_t *uv, const char *name) +{ + uc_ressource_t *res = (uc_ressource_t *)uv; + uc_ressource_type_t *type; + + if (ucv_type(uv) != UC_RESSOURCE) + return NULL; + + if (name) { + type = ucv_ressource_type_lookup(name); + + if (!type || type != ucv_ressource_type_get(res->type)) + return NULL; + } + + return &res->data; +} + + +uc_value_t * +ucv_regexp_new(const char *pattern, bool icase, bool newline, bool global, char **error) +{ + int cflags = REG_EXTENDED, res; + uc_regexp_t *re; + size_t len; + + re = xalloc(sizeof(*re) + strlen(pattern) + 1); + re->header.type = UC_REGEXP; + re->header.refcount = 1; + re->icase = icase; + re->global = global; + re->newline = newline; + strcpy(re->source, pattern); + + if (icase) + cflags |= REG_ICASE; + + if (newline) + cflags |= REG_NEWLINE; + + res = regcomp(&re->regexp, pattern, cflags); + + if (res != 0) { + if (error) { + len = regerror(res, &re->regexp, NULL, 0); + *error = xalloc(len); + + regerror(res, &re->regexp, *error, len); + } + + free(re); + + return NULL; + } + + /* + json_object_object_add(re->header.jso, "source", xjs_new_string(pattern)); + json_object_object_add(re->header.jso, "i", xjs_new_boolean(icase)); + json_object_object_add(re->header.jso, "g", xjs_new_boolean(global)); + json_object_object_add(re->header.jso, "s", xjs_new_boolean(newline)); + */ + + return &re->header; +} + + +uc_value_t * +ucv_upvalref_new(size_t slot) +{ + uc_upvalref_t *up; + + up = xalloc(sizeof(*up)); + up->header.type = UC_UPVALUE; + up->header.refcount = 1; + up->slot = slot; + + return &up->header; +} + + +uc_value_t * +ucv_prototype_get(uc_value_t *uv) +{ + uc_ressource_type_t *restype; + uc_ressource_t *ressource; + uc_object_t *object; + uc_array_t *array; + + switch (ucv_type(uv)) { + case UC_ARRAY: + array = (uc_array_t *)uv; + + return array->proto; + + case UC_OBJECT: + object = (uc_object_t *)uv; + + return object->proto; + + case UC_RESSOURCE: + ressource = (uc_ressource_t *)uv; + restype = ucv_ressource_type_get(ressource->type); + + return restype ? restype->proto : NULL; + + default: + return NULL; + } +} + +bool +ucv_prototype_set(uc_value_t *uv, uc_value_t *proto) +{ + uc_object_t *object; + uc_array_t *array; + + if (ucv_type(proto) != UC_OBJECT) + return false; + + switch (ucv_type(uv)) { + case UC_ARRAY: + array = (uc_array_t *)uv; + array->proto = proto; + + return true; + + case UC_OBJECT: + object = (uc_object_t *)uv; + object->proto = proto; + + return true; + + default: + return false; + } +} + +uc_value_t * +ucv_property_get(uc_value_t *uv, const char *key) +{ + uc_value_t *val; + bool found; + + for (; uv; uv = ucv_prototype_get(uv)) { + val = ucv_object_get(uv, key, &found); + + if (found) + return val; + } + + return NULL; +} + + +uc_value_t * +ucv_from_json(uc_vm *vm, json_object *jso) +{ + //uc_array_t *arr; + uc_value_t *uv; + int64_t n; + size_t i; + + switch (json_object_get_type(jso)) { + case json_type_null: + return NULL; + + case json_type_boolean: + return ucv_boolean_new(json_object_get_boolean(jso)); + + case json_type_double: + return ucv_double_new(json_object_get_double(jso)); + + case json_type_int: + n = json_object_get_int64(jso); + + if (n == INT64_MAX) + return ucv_uint64_new(json_object_get_uint64(jso)); + + return ucv_int64_new(n); + + case json_type_object: + uv = ucv_object_new(vm); + + json_object_object_foreach(jso, key, val) + ucv_object_add(uv, key, ucv_from_json(vm, val)); + + return uv; + + case json_type_array: + /* XXX + arr = (uc_array_t *)ucv_array_new_length(vm, json_object_array_length(jso)); + + for (i = 0; i < arr->count; i++) + arr->entries[i] = ucv_from_json(vm, json_object_array_get_idx(jso, i)); + + return &arr->header; + */ + uv = ucv_array_new(vm); + + for (i = 0; i < json_object_array_length(jso); i++) + ucv_array_push(uv, ucv_from_json(vm, json_object_array_get_idx(jso, i))); + + return uv; + + case json_type_string: + return ucv_string_new_length(json_object_get_string(jso), json_object_get_string_len(jso)); + } + + return NULL; +} + +json_object * +ucv_to_json(uc_value_t *uv) +{ + uc_regexp_t *regexp; + uc_array_t *array; + json_object *jso; + size_t i; + char *s; + + switch (ucv_type(uv)) { + case UC_BOOLEAN: + return json_object_new_boolean(ucv_boolean_get(uv)); + + case UC_INTEGER: + if (ucv_is_u64(uv)) + return json_object_new_uint64(ucv_uint64_get(uv)); + + return json_object_new_int64(ucv_int64_get(uv)); + + case UC_DOUBLE: + return json_object_new_double(ucv_double_get(uv)); + + case UC_STRING: + return json_object_new_string_len(ucv_string_get(uv), ucv_string_length(uv)); + + case UC_ARRAY: + array = (uc_array_t *)uv; + jso = json_object_new_array_ext(array->count); + + for (i = 0; i < array->count; i++) + json_object_array_put_idx(jso, i, ucv_to_json(array->entries[i])); + + return jso; + + case UC_OBJECT: + jso = json_object_new_object(); + + ucv_object_foreach(uv, key, val) + json_object_object_add(jso, key, ucv_to_json(val)); + + return jso; + + case UC_REGEXP: + regexp = (uc_regexp_t *)uv; + i = asprintf(&s, "/%s/%s%s%s", + regexp->source, + regexp->global ? "g" : "", + regexp->icase ? "i" : "", + regexp->newline ? "s" : ""); + + if (i <= 0) + return NULL; + + jso = json_object_new_string_len(s, i); + + free(s); + + return jso; + + case UC_CLOSURE: + case UC_CFUNCTION: + case UC_FUNCTION: + case UC_RESSOURCE: + case UC_UPVALUE: + case UC_NULL: + return NULL; + } + + return NULL; +} + +static void +ucv_to_string_json_encoded(uc_stringbuf_t *pb, const char *s, size_t len, bool regexp) +{ + size_t i; + + if (!regexp) + ucv_stringbuf_append(pb, "\""); + + for (i = 0; i < len; i++, s++) { + switch (*s) { + case '"': + ucv_stringbuf_append(pb, "\\\""); + break; + + case '\\': + ucv_stringbuf_append(pb, "\\\\"); + break; + + case '\b': + ucv_stringbuf_append(pb, "\\b"); + break; + + case '\f': + ucv_stringbuf_append(pb, "\\f"); + break; + + case '\n': + ucv_stringbuf_append(pb, "\\n"); + break; + + case '\r': + ucv_stringbuf_append(pb, "\\r"); + break; + + case '\t': + ucv_stringbuf_append(pb, "\\t"); + break; + + case '/': + if (regexp) + ucv_stringbuf_append(pb, "\\"); + + ucv_stringbuf_append(pb, "/"); + break; + + default: + if (*s < 0x20) + ucv_stringbuf_printf(pb, "\\u%04x", *s); + else + ucv_stringbuf_addstr(pb, s, 1); + break; + } + } + + if (!regexp) + ucv_stringbuf_append(pb, "\""); +} + +static bool +ucv_call_tostring(uc_vm *vm, uc_stringbuf_t *pb, uc_value_t *uv, bool json) +{ + uc_value_t *proto = ucv_prototype_get(uv); + uc_value_t *tostr = ucv_object_get(proto, "tostring", NULL); + uc_value_t *str; + + if (!ucv_is_callable(tostr)) + return false; + + uc_vm_stack_push(vm, ucv_get(uv)); + uc_vm_stack_push(vm, ucv_get(tostr)); + + if (uc_vm_call(vm, true, 0) != EXCEPTION_NONE) + return false; + + str = uc_vm_stack_pop(vm); + + if (ucv_type(str) == UC_STRING) { + if (json) + ucv_to_string_json_encoded(pb, ucv_string_get(str), ucv_string_length(str), false); + else + ucv_stringbuf_addstr(pb, ucv_string_get(str), ucv_string_length(str)); + } + else if (json) { + ucv_stringbuf_append(pb, "\"\""); + } + + ucv_put(str); + + return true; +} + +void +_ucv_stringbuf_append(uc_stringbuf_t *pb, const char *str, size_t len) +{ + printbuf_memappend_fast(pb, str, len); +} + +void +ucv_to_stringbuf(uc_vm *vm, uc_stringbuf_t *pb, uc_value_t *uv, bool json) +{ + uc_ressource_type_t *restype; + uc_ressource_t *ressource; + uc_cfunction_t *cfunction; + uc_function_t *function; + uc_closure_t *closure; + uc_regexp_t *regexp; + uc_value_t *argname; + uc_array_t *array; + size_t i; + double d; + + if (ucv_is_marked(uv)) { + ucv_stringbuf_append(pb, "null"); + + return; + } + + if (vm != NULL && ucv_call_tostring(vm, pb, uv, json)) + return; + + ucv_set_mark(uv); + + switch (ucv_type(uv)) { + case UC_NULL: + ucv_stringbuf_append(pb, "null"); + break; + + case UC_BOOLEAN: + if (ucv_boolean_get(uv)) + ucv_stringbuf_append(pb, "true"); + else + ucv_stringbuf_append(pb, "false"); + break; + + case UC_INTEGER: + if (ucv_is_u64(uv)) + ucv_stringbuf_printf(pb, "%" PRIu64, ucv_uint64_get(uv)); + else + ucv_stringbuf_printf(pb, "%" PRId64, ucv_int64_get(uv)); + break; + + case UC_DOUBLE: + d = ucv_double_get(uv); + + if (json && isnan(d)) + ucv_stringbuf_append(pb, "\"NaN\""); + else if (json && d == INFINITY) + ucv_stringbuf_append(pb, "1e309"); + else if (json && d == -INFINITY) + ucv_stringbuf_append(pb, "-1e309"); + else if (isnan(d)) + ucv_stringbuf_append(pb, "NaN"); + else if (d == INFINITY) + ucv_stringbuf_append(pb, "Infinity"); + else if (d == -INFINITY) + ucv_stringbuf_append(pb, "-Infinity"); + else + ucv_stringbuf_printf(pb, "%g", d); + + break; + + case UC_STRING: + if (json) + ucv_to_string_json_encoded(pb, ucv_string_get(uv), ucv_string_length(uv), false); + else + ucv_stringbuf_addstr(pb, ucv_string_get(uv), ucv_string_length(uv)); + break; + + case UC_ARRAY: + array = (uc_array_t *)uv; + + ucv_stringbuf_append(pb, "["); + + for (i = 0; i < array->count; i++) { + if (i) + ucv_stringbuf_append(pb, ", "); + else + ucv_stringbuf_append(pb, " "); + + ucv_to_stringbuf(vm, pb, array->entries[i], true); + } + + ucv_stringbuf_append(pb, " ]"); + break; + + case UC_OBJECT: + ucv_stringbuf_append(pb, "{"); + + i = 0; + ucv_object_foreach(uv, key, val) { + if (i++) + ucv_stringbuf_append(pb, ", "); + else + ucv_stringbuf_append(pb, " "); + + ucv_to_string_json_encoded(pb, key, strlen(key), false); + ucv_stringbuf_append(pb, ": "); + ucv_to_stringbuf(vm, pb, val, true); + } + + ucv_stringbuf_append(pb, " }"); + break; + + case UC_REGEXP: + regexp = (uc_regexp_t *)uv; + + if (json) + ucv_stringbuf_append(pb, "\""); + + ucv_stringbuf_append(pb, "/"); + ucv_to_string_json_encoded(pb, regexp->source, strlen(regexp->source), true); + ucv_stringbuf_append(pb, "/"); + + if (regexp->global) + ucv_stringbuf_append(pb, "g"); + + if (regexp->icase) + ucv_stringbuf_append(pb, "i"); + + if (regexp->newline) + ucv_stringbuf_append(pb, "s"); + + if (json) + ucv_stringbuf_append(pb, "\""); + + break; + + case UC_CLOSURE: + closure = (uc_closure_t *)uv; + function = closure->function; + + if (json) + ucv_stringbuf_append(pb, "\""); + + if (!closure->is_arrow) { + ucv_stringbuf_append(pb, "function"); + + if (function->name[0]) { + ucv_stringbuf_append(pb, " "); + ucv_stringbuf_addstr(pb, function->name, strlen(function->name)); + } + } + + ucv_stringbuf_append(pb, "("); + + for (i = 1; i <= function->nargs; i++) { + argname = uc_chunk_debug_get_variable(&function->chunk, i - 1, i, false); + + if (i > 1) + ucv_stringbuf_append(pb, ", "); + + if (i == function->nargs && function->vararg) + ucv_stringbuf_append(pb, "..."); + + if (argname) + ucv_stringbuf_addstr(pb, ucv_string_get(argname), ucv_string_length(argname)); + else + ucv_stringbuf_printf(pb, "[arg%zu]", i); + + ucv_put(argname); + } + + ucv_stringbuf_printf(pb, ")%s { ... }%s", + closure->is_arrow ? " =>" : "", + json ? "\"" : ""); + + break; + + case UC_CFUNCTION: + cfunction = (uc_cfunction_t *)uv; + + ucv_stringbuf_printf(pb, "%sfunction%s%s(...) { [native code] }%s", + json ? "\"" : "", + cfunction->name ? " " : "", + cfunction->name ? cfunction->name : "", + json ? "\"" : ""); + + break; + + case UC_FUNCTION: + ucv_stringbuf_printf(pb, "%s<function %p>%s", + json ? "\"" : "", + uv, + json ? "\"" : ""); + + break; + + case UC_RESSOURCE: + ressource = (uc_ressource_t *)uv; + restype = ucv_ressource_type_get(ressource->type); + + ucv_stringbuf_printf(pb, "%s<%s %p>%s", + json ? "\"" : "", + restype ? restype->name : "ressource", + ressource->data, + json ? "\"" : ""); + + break; + + case UC_UPVALUE: + ucv_stringbuf_printf(pb, "%s<upvalref %p>%s", + json ? "\"" : "", + uv, + json ? "\"" : ""); + + break; + } + + ucv_clear_mark(uv); +} + +static char * +ucv_to_string_any(uc_vm *vm, uc_value_t *uv, bool json) +{ + uc_stringbuf_t *pb = xprintbuf_new(); + char *rv; + + ucv_to_stringbuf(vm, pb, uv, json); + + rv = pb->buf; + + free(pb); + + return rv; +} + +char * +ucv_to_string(uc_vm *vm, uc_value_t *uv) +{ + return ucv_to_string_any(vm, uv, false); +} + +char * +ucv_to_jsonstring(uc_vm *vm, uc_value_t *uv) +{ + return ucv_to_string_any(vm, uv, true); +} + +bool +ucv_equal(uc_value_t *uv1, uc_value_t *uv2) +{ + uc_type_t t1 = ucv_type(uv1); + uc_type_t t2 = ucv_type(uv2); + uint64_t u1, u2; + int64_t n1, n2; + bool b1, b2; + + if (t1 != t2) + return false; + + if (uv1 == uv2) + return true; + + switch (t1) { + case UC_NULL: + return true; + + case UC_BOOLEAN: + return ucv_boolean_get(uv1) == ucv_boolean_get(uv2); + + case UC_DOUBLE: + return ucv_double_get(uv1) == ucv_double_get(uv2); + + case UC_INTEGER: + n1 = ucv_int64_get(uv1); + b1 = (errno == 0); + + n2 = ucv_int64_get(uv2); + b2 = (errno == 0); + + if (b1 && b2) + return (n1 == n2); + + u1 = ucv_uint64_get(uv1); + b1 = (errno == 0); + + u2 = ucv_uint64_get(uv2); + b2 = (errno == 0); + + if (b1 && b2) + return (u1 == u2); + + return false; + + case UC_STRING: + u1 = ucv_string_length(uv1); + u2 = ucv_string_length(uv2); + + if (u1 != u2) + return false; + + return (memcmp(ucv_string_get(uv1), ucv_string_get(uv2), u1) == 0); + + case UC_ARRAY: + u1 = ucv_array_length(uv1); + u2 = ucv_array_length(uv2); + + if (u1 != u2) + return false; + + for (u1 = 0; u1 < u2; u1++) + if (!ucv_equal(ucv_array_get(uv1, u1), ucv_array_get(uv2, u1))) + return false; + + return true; + + case UC_OBJECT: + u1 = ucv_object_length(uv1); + u2 = ucv_object_length(uv2); + + if (u1 != u2) + return false; + + ucv_object_foreach(uv1, key, val) { + if (!ucv_equal(val, ucv_object_get(uv2, key, NULL))) + return false; + } + + ucv_object_foreach(uv2, key2, val2) { + ucv_object_get(uv1, key2, &b1); + + if (!b1) + return false; + } + + return true; + + default: + return false; + } +} + +void +ucv_gc(uc_vm *vm, bool final) +{ + uc_weakref_t *ref, *tmp; + uc_value_t *val; + size_t i; + + if (!final) { + /* mark reachable objects */ + ucv_gc_mark(vm->globals); + + for (i = 0; i < vm->callframes.count; i++) + ucv_gc_mark(vm->callframes.entries[i].ctx); + + for (i = 0; i < vm->stack.count; i++) + ucv_gc_mark(vm->stack.entries[i]); + } + + /* unref unreachable objects */ + for (ref = vm->values.next; ref != &vm->values; ref = ref->next) { + val = (void *)ref - offsetof(uc_array_t, ref); + + if (ucv_is_marked(val)) + ucv_clear_mark(val); + else + ucv_free(val, true); + } + + /* 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); + + if (val->type == UC_NULL) { + ucv_unref(ref); + free(val); + } + } +} + + +#ifdef __GNUC__ + +__attribute__((destructor)) +static void ucv_ressource_types_free(void) +{ + size_t i; + + for (i = 0; i < res_types.count; i++) + ucv_put(res_types.entries[i].proto); + + uc_vector_clear(&res_types); +} + +#endif @@ -0,0 +1,310 @@ +/* + * Copyright (C) 2021 Jo-Philipp Wich <jo@mein.io> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __TYPES_H_ +#define __TYPES_H_ + +#include <stdbool.h> +#include <stdint.h> +#include <regex.h> +#include <json-c/json.h> + +#include "source.h" +#include "chunk.h" + +typedef enum uc_type_t { + UC_NULL, + UC_INTEGER, + UC_BOOLEAN, + UC_STRING, + UC_DOUBLE, + UC_ARRAY, + UC_OBJECT, + UC_REGEXP, + UC_FUNCTION, + UC_CFUNCTION, + UC_CLOSURE, + UC_UPVALUE, + UC_RESSOURCE +} uc_type_t; + +typedef struct uc_value_t { + uint32_t type:4; + uint32_t mark:1; + uint32_t u64:1; + uint32_t refcount:26; +} uc_value_t; + +typedef struct uc_weakref_t { + struct uc_weakref_t *prev; + struct uc_weakref_t *next; +} uc_weakref_t; + +typedef struct { + uc_value_t header; + double dbl; +} uc_double_t; + +typedef struct { + uc_value_t header; + union { + int64_t s64; + uint64_t u64; + } i; +} uc_integer_t; + +typedef struct { + uc_value_t header; + size_t length; + char str[]; +} uc_string_t; + +typedef struct { + uc_value_t header; + uc_weakref_t ref; + size_t count; + uc_value_t *proto; + uc_value_t **entries; +} uc_array_t; + +typedef struct { + uc_value_t header; + uc_weakref_t ref; + uc_value_t *proto; + struct lh_table *table; +} uc_object_t; + +typedef struct { + uc_value_t header; + regex_t regexp; + bool icase, newline, global; + char source[]; +} uc_regexp_t; + +typedef struct { + uc_value_t header; + bool arrow, vararg; + size_t nargs; + size_t nupvals; + size_t srcpos; + uc_chunk chunk; + uc_source *source; + char name[]; +} uc_function_t; + +typedef struct uc_upvalref_t { + uc_value_t header; + size_t slot; + bool closed; + uc_value_t *value; + struct uc_upvalref_t *next; +} uc_upvalref_t; + +typedef struct { + uc_value_t header; + uc_weakref_t ref; + bool is_arrow; + uc_function_t *function; + uc_upvalref_t **upvals; +} uc_closure_t; + +typedef struct uc_vm uc_vm; +typedef uc_value_t *(*uc_cfn_ptr_t)(uc_vm *, size_t); + +typedef struct { + uc_value_t header; + uc_cfn_ptr_t cfn; + char name[]; +} uc_cfunction_t; + +typedef struct { + uc_value_t header; + size_t type; + void *data; +} uc_ressource_t; + +typedef struct { + const char *name; + uc_value_t *proto; + void (*free)(void *); +} uc_ressource_type_t; + +uc_declare_vector(uc_ressource_types_t, uc_ressource_type_t); + +typedef struct printbuf uc_stringbuf_t; + +void ucv_free(uc_value_t *, bool); +void ucv_put(uc_value_t *); + +uc_value_t *ucv_get(uc_value_t *uv); + +uc_type_t ucv_type(uc_value_t *); +const char *ucv_typename(uc_value_t *); + +uc_value_t *ucv_boolean_new(bool); +bool ucv_boolean_get(uc_value_t *); + +uc_value_t *ucv_string_new(const char *); +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); }) + +uc_stringbuf_t *ucv_stringbuf_new(void); +uc_value_t *ucv_stringbuf_finish(uc_stringbuf_t *); + +void _ucv_stringbuf_append(uc_stringbuf_t *, const char *, size_t); + +#define _ucv_is_literal(str) ("" str) +#define ucv_stringbuf_append(buf, str) _ucv_stringbuf_append(buf, _ucv_is_literal(str), sizeof(str) - 1) +#define ucv_stringbuf_addstr(buf, str, len) _ucv_stringbuf_append(buf, str, len) +#define ucv_stringbuf_printf(buf, fmt, ...) sprintbuf(buf, fmt, __VA_ARGS__) + +uc_value_t *ucv_int64_new(int64_t); +uc_value_t *ucv_uint64_new(uint64_t); +int64_t ucv_int64_get(uc_value_t *); +uint64_t ucv_uint64_get(uc_value_t *); + +uc_value_t *ucv_double_new(double); +double ucv_double_get(uc_value_t *); + +uc_value_t *ucv_array_new(uc_vm *); +uc_value_t *ucv_array_new_length(uc_vm *, size_t); +uc_value_t *ucv_array_get(uc_value_t *, size_t); +uc_value_t *ucv_array_pop(uc_value_t *); +uc_value_t *ucv_array_push(uc_value_t *, uc_value_t *); +uc_value_t *ucv_array_shift(uc_value_t *); +uc_value_t *ucv_array_unshift(uc_value_t *, uc_value_t *); +void ucv_array_sort(uc_value_t *, int (*)(const void *, const void *)); +bool ucv_array_delete(uc_value_t *, size_t, size_t); +bool ucv_array_set(uc_value_t *, size_t, uc_value_t *); +size_t ucv_array_length(uc_value_t *); + +uc_value_t *ucv_object_new(uc_vm *); +uc_value_t *ucv_object_get(uc_value_t *, const char *, bool *); +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) + +uc_value_t *ucv_function_new(const char *, size_t, uc_source *); +size_t ucv_function_srcpos(uc_value_t *, size_t); + +uc_value_t *ucv_cfunction_new(const char *, uc_cfn_ptr_t); + +uc_value_t *ucv_closure_new(uc_vm *, uc_function_t *, bool); + +uc_ressource_type_t *ucv_ressource_type_add(const char *, uc_value_t *, void (*)(void *)); +uc_ressource_type_t *ucv_ressource_type_lookup(const char *); + +uc_value_t *ucv_ressource_new(uc_ressource_type_t *, void *); +void **ucv_ressource_dataptr(uc_value_t *, const char *); + +uc_value_t *ucv_regexp_new(const char *, bool, bool, bool, char **); + +uc_value_t *ucv_upvalref_new(size_t); + +uc_value_t *ucv_prototype_get(uc_value_t *); +bool ucv_prototype_set(uc_value_t *, uc_value_t *); + +uc_value_t *ucv_property_get(uc_value_t *, const char *); + +uc_value_t *ucv_from_json(uc_vm *, json_object *); +json_object *ucv_to_json(uc_value_t *); + +char *ucv_to_string(uc_vm *, uc_value_t *); +char *ucv_to_jsonstring(uc_vm *, uc_value_t *); +void ucv_to_stringbuf(uc_vm *, uc_stringbuf_t *, uc_value_t *, bool); + +static inline bool +ucv_is_callable(uc_value_t *uv) +{ + switch (ucv_type(uv)) { + case UC_CLOSURE: + case UC_CFUNCTION: + return true; + + default: + return false; + } +} + +static inline bool +ucv_is_arrowfn(uc_value_t *uv) +{ + uc_closure_t *closure = (uc_closure_t *)uv; + + return (ucv_type(uv) == UC_CLOSURE && closure->is_arrow); +} + +static inline bool +ucv_is_u64(uc_value_t *uv) +{ + return (((uintptr_t)uv & 3) == 0 && uv != NULL && uv->u64 == true); +} + +static inline bool +ucv_is_scalar(uc_value_t *uv) +{ + switch (ucv_type(uv)) { + case UC_NULL: + case UC_BOOLEAN: + case UC_DOUBLE: + case UC_INTEGER: + case UC_STRING: + return true; + + default: + return false; + } +} + +static inline bool +ucv_is_marked(uc_value_t *uv) +{ + return (((uintptr_t)uv & 3) == 0 && uv != NULL && uv->mark == true); +} + +static inline void +ucv_set_mark(uc_value_t *uv) +{ + if (((uintptr_t)uv & 3) == 0 && uv != NULL) + uv->mark = true; +} + +static inline void +ucv_clear_mark(uc_value_t *uv) +{ + if (((uintptr_t)uv & 3) == 0 && uv != NULL) + uv->mark = false; +} + +bool ucv_equal(uc_value_t *, uc_value_t *); + +void ucv_gc(uc_vm *, bool); + +#endif /* __TYPES_H_ */ @@ -245,4 +245,15 @@ static inline int xvasprintf(char **strp, const char *fmt, va_list ap) { return len; } +static inline struct printbuf *xprintbuf_new(void) { + struct printbuf *pb = printbuf_new(); + + if (!pb) { + fprintf(stderr, "Out of memory\n"); + abort(); + } + + return pb; +} + #endif /* __UTIL_H_ */ @@ -23,8 +23,8 @@ #include "util.h" #include "chunk.h" #include "value.h" -#include "object.h" #include "lexer.h" /* TK_* */ +#include "vm.h" #define TAG_TYPE uint64_t #define TAG_BITS 3 @@ -44,70 +44,39 @@ #define UC_VALLIST_CHUNK_SIZE 8 -static int -uc_double_tostring(json_object *v, struct printbuf *pb, int level, int flags) -{ - bool strict = (level > 0) || (flags & JSON_C_TO_STRING_STRICT); - double d = json_object_get_double(v); - - if (isnan(d)) - return sprintbuf(pb, strict ? "\"NaN\"" : "NaN"); - - if (d == INFINITY) - return sprintbuf(pb, strict ? "1e309" : "Infinity"); - - if (d == -INFINITY) - return sprintbuf(pb, strict ? "-1e309" : "-Infinity"); - - return sprintbuf(pb, "%g", d); -} - -json_object * -uc_double_new(double v) -{ - json_object *d = json_object_new_double(v); - - if (!d) { - fprintf(stderr, "Out of memory\n"); - abort(); - } - - json_object_set_serializer(d, uc_double_tostring, NULL, NULL); - - return d; -} - bool -uc_val_is_truish(json_object *val) +uc_val_is_truish(uc_value_t *val) { double d; - switch (json_object_get_type(val)) { - case json_type_int: - return (json_object_get_int64(val) != 0); + switch (ucv_type(val)) { + case UC_INTEGER: + if (ucv_is_u64(val)) + return (ucv_uint64_get(val) != 0); + + return (ucv_int64_get(val) != 0); - case json_type_double: - d = json_object_get_double(val); + case UC_DOUBLE: + d = ucv_double_get(val); return (d != 0 && !isnan(d)); - case json_type_boolean: - return (json_object_get_boolean(val) != false); + case UC_BOOLEAN: + return ucv_boolean_get(val); - case json_type_string: - return (json_object_get_string_len(val) > 0); + case UC_STRING: + return (ucv_string_length(val) > 0); - case json_type_array: - case json_type_object: - return true; + case UC_NULL: + return false; default: - return false; + return true; } } -enum json_type -uc_cast_number(json_object *v, int64_t *n, double *d) +uc_type_t +uc_cast_number(uc_value_t *v, int64_t *n, double *d) { bool is_double = false; const char *s; @@ -116,27 +85,27 @@ uc_cast_number(json_object *v, int64_t *n, double *d) *d = 0.0; *n = 0; - switch (json_object_get_type(v)) { - case json_type_int: - *n = json_object_get_int64(v); + switch (ucv_type(v)) { + case UC_INTEGER: + *n = ucv_int64_get(v); - return json_type_int; + return UC_INTEGER; - case json_type_double: - *d = json_object_get_double(v); + case UC_DOUBLE: + *d = ucv_double_get(v); - return json_type_double; + return UC_DOUBLE; - case json_type_null: - return json_type_int; + case UC_NULL: + return UC_INTEGER; - case json_type_boolean: - *n = json_object_get_boolean(v) ? 1 : 0; + case UC_BOOLEAN: + *n = ucv_boolean_get(v); - return json_type_int; + return UC_INTEGER; - case json_type_string: - s = json_object_get_string(v); + case UC_STRING: + s = ucv_string_get(v); while (isspace(*s)) s++; @@ -162,141 +131,144 @@ uc_cast_number(json_object *v, int64_t *n, double *d) if (*e) { *d = NAN; - return json_type_double; + return UC_DOUBLE; } if (is_double) - return json_type_double; + return UC_DOUBLE; - return json_type_int; + return UC_INTEGER; default: *d = NAN; - return json_type_double; + return UC_DOUBLE; } } -static json_object * -uc_getproto(json_object *obj) +static char * +uc_tostring(uc_vm *vm, uc_value_t *val) { - uc_prototype *proto; - - switch (uc_object_type(obj)) { - case UC_OBJ_RESSOURCE: - proto = uc_ressource_prototype(obj); - break; - - case UC_OBJ_PROTOTYPE: - proto = uc_object_as_prototype(obj)->parent; - break; - - default: - proto = NULL; - } + if (ucv_type(val) != UC_STRING) + return ucv_to_string(vm, val); - return proto ? proto->header.jso : NULL; + return NULL; } -json_object * -uc_getval(json_object *scope, json_object *key) +static int64_t +uc_toidx(uc_value_t *val) { - json_object *o, *v; const char *k; int64_t idx; double d; char *e; - if (json_object_is_type(scope, json_type_array)) { - /* only consider doubles with integer values as array keys */ - if (json_object_is_type(key, json_type_double)) { - d = json_object_get_double(key); + /* only consider doubles with integer values as array keys */ + if (ucv_type(val) == UC_DOUBLE) { + d = ucv_double_get(val); - if ((double)(int64_t)(d) == d) - idx = (int64_t)d; - else - idx = -1; - } - else if (json_object_is_type(key, json_type_int)) { - idx = json_object_get_int64(key); - } - else if (json_object_is_type(key, json_type_string)) { - errno = 0; - k = json_object_get_string(key); - idx = strtoll(k, &e, 0); + if ((double)(int64_t)(d) != d) + return -1; - if (errno != 0 || e == k || *e != 0) - idx = -1; - } - else { - idx = -1; - } + return (int64_t)d; + } + else if (ucv_type(val) == UC_INTEGER) { + return ucv_int64_get(val); + } + else if (ucv_type(val) == UC_STRING) { + errno = 0; + k = ucv_string_get(val); + idx = strtoll(k, &e, 0); - if (idx >= 0 && idx < json_object_array_length(scope)) - return json_object_get(json_object_array_get_idx(scope, idx)); + if (errno != 0 || e == k || *e != 0) + return -1; + + return idx; + } + + return -1; +} + +uc_value_t * +uc_getval(uc_vm *vm, uc_value_t *scope, uc_value_t *key) +{ + uc_value_t *o, *v = NULL; + int64_t idx; + bool found; + char *k; + + if (ucv_type(scope) == UC_ARRAY) { + idx = uc_toidx(key); + + if (idx >= 0 && (uint64_t)idx < ucv_array_length(scope)) + return ucv_get(ucv_array_get(scope, idx)); } - for (o = scope, k = key ? json_object_get_string(key) : "null"; o; o = uc_getproto(o)) { - if (!json_object_is_type(o, json_type_object)) + k = uc_tostring(vm, key); + + for (o = scope; o; o = ucv_prototype_get(o)) { + if (ucv_type(o) != UC_OBJECT) continue; - if (json_object_object_get_ex(o, k, &v)) - return json_object_get(v); + v = ucv_object_get(o, k ? k : ucv_string_get(key), &found); + + if (found) + break; } - return NULL; + free(k); + + return ucv_get(v); } -json_object * -uc_setval(json_object *scope, json_object *key, json_object *val) +uc_value_t * +uc_setval(uc_vm *vm, uc_value_t *scope, uc_value_t *key, uc_value_t *val) { int64_t idx; + char *s; + bool rv; if (!key) return NULL; - if (json_object_is_type(scope, json_type_array)) { - errno = 0; - idx = json_object_get_int64(key); - - if (errno != 0) - return NULL; + if (ucv_type(scope) == UC_ARRAY) { + idx = uc_toidx(key); - if (json_object_array_put_idx(scope, idx, val)) + if (idx < 0 || !ucv_array_set(scope, idx, val)) return NULL; - return json_object_get(val); + return ucv_get(val); } - if (json_object_object_add(scope, key ? json_object_get_string(key) : "null", val)) - return NULL; + s = uc_tostring(vm, key); + rv = ucv_object_add(scope, s ? s : ucv_string_get(key), val); + free(s); - return json_object_get(val); + return rv ? ucv_get(val) : NULL; } bool -uc_cmp(int how, json_object *v1, json_object *v2) +uc_cmp(int how, uc_value_t *v1, uc_value_t *v2) { - enum json_type t1 = json_object_get_type(v1); - enum json_type t2 = json_object_get_type(v2); + uc_type_t t1 = ucv_type(v1); + uc_type_t t2 = ucv_type(v2); int64_t n1, n2, delta; double d1, d2; - if (t1 == json_type_string && t2 == json_type_string) { - delta = strcmp(json_object_get_string(v1), json_object_get_string(v2)); + if (t1 == UC_STRING && t2 == UC_STRING) { + delta = strcmp(ucv_string_get(v1), ucv_string_get(v2)); } else { - if ((t1 == json_type_array && t2 == json_type_array) || - (t1 == json_type_object && t2 == json_type_object)) { + if (t1 == t2 && !ucv_is_scalar(v1)) { delta = (void *)v1 - (void *)v2; } else { t1 = uc_cast_number(v1, &n1, &d1); t2 = uc_cast_number(v2, &n2, &d2); - if (t1 == json_type_double || t2 == json_type_double) { - d1 = (t1 == json_type_double) ? d1 : (double)n1; - d2 = (t2 == json_type_double) ? d2 : (double)n2; + if (t1 == UC_DOUBLE || t2 == UC_DOUBLE) { + d1 = (t1 == UC_DOUBLE) ? d1 : (double)n1; + d2 = (t2 == UC_DOUBLE) ? d2 : (double)n2; /* all comparison results except `!=` involving NaN are false */ if (isnan(d1) || isnan(d2)) @@ -339,44 +311,6 @@ uc_cmp(int how, json_object *v1, json_object *v2) } } -bool -uc_eq(json_object *v1, json_object *v2) -{ - uc_objtype_t o1 = uc_object_type(v1); - uc_objtype_t o2 = uc_object_type(v2); - enum json_type t1 = json_object_get_type(v1); - enum json_type t2 = json_object_get_type(v2); - - if (o1 != o2 || t1 != t2) - return false; - - switch (t1) { - case json_type_array: - case json_type_object: - return (v1 == v2); - - case json_type_boolean: - return (json_object_get_boolean(v1) == json_object_get_boolean(v2)); - - case json_type_double: - if (isnan(json_object_get_double(v1)) || isnan(json_object_get_double(v2))) - return false; - - return (json_object_get_double(v1) == json_object_get_double(v2)); - - case json_type_int: - return (json_object_get_int64(v1) == json_object_get_int64(v2)); - - case json_type_string: - return !strcmp(json_object_get_string(v1), json_object_get_string(v2)); - - case json_type_null: - return true; - } - - return false; -} - void uc_vallist_init(uc_value_list *list) { @@ -389,14 +323,14 @@ uc_vallist_init(uc_value_list *list) void uc_vallist_free(uc_value_list *list) { - json_object *o; + uc_value_t *o; size_t i; for (i = 0; i < list->isize; i++) { if (TAG_GET_TYPE(list->index[i]) == TAG_PTR) { o = uc_vallist_get(list, i); - uc_value_put(o); - uc_value_put(o); + ucv_put(o); + ucv_put(o); } } @@ -507,7 +441,7 @@ add_str(uc_value_list *list, const char *s, size_t slen) uint32_t sl; size_t sz; char *dst; - int i; + size_t i; if (slen > UINT32_MAX) { fprintf(stderr, "String constant too long\n"); @@ -609,7 +543,7 @@ add_ptr(uc_value_list *list, void *ptr) } ssize_t -uc_vallist_add(uc_value_list *list, json_object *value) +uc_vallist_add(uc_value_list *list, uc_value_t *value) { ssize_t existing; @@ -618,42 +552,43 @@ uc_vallist_add(uc_value_list *list, json_object *value) memset(&list->index[list->isize], 0, UC_VALLIST_CHUNK_SIZE); } - switch (json_object_get_type(value)) { - case json_type_int: - existing = find_num(list, json_object_get_int64(value)); + switch (ucv_type(value)) { + case UC_INTEGER: + /* XXX: u64 */ + existing = find_num(list, ucv_int64_get(value)); if (existing > -1) return existing; - add_num(list, json_object_get_int64(value)); + add_num(list, ucv_int64_get(value)); break; - case json_type_double: - existing = find_dbl(list, json_object_get_double(value)); + case UC_DOUBLE: + existing = find_dbl(list, ucv_double_get(value)); if (existing > -1) return existing; - add_dbl(list, json_object_get_double(value)); + add_dbl(list, ucv_double_get(value)); break; - case json_type_string: + case UC_STRING: existing = find_str(list, - json_object_get_string(value), - json_object_get_string_len(value)); + ucv_string_get(value), + ucv_string_length(value)); if (existing > -1) return existing; add_str(list, - json_object_get_string(value), - json_object_get_string_len(value)); + ucv_string_get(value), + ucv_string_length(value)); break; - case json_type_object: + case UC_FUNCTION: add_ptr(list, value); break; @@ -673,28 +608,28 @@ uc_vallist_type(uc_value_list *list, size_t idx) return TAG_GET_TYPE(list->index[idx]); } -json_object * +uc_value_t * uc_vallist_get(uc_value_list *list, size_t idx) { char str[sizeof(TAG_TYPE)]; - size_t len; - int n; + size_t n, len; switch (uc_vallist_type(list, idx)) { case TAG_NUM: - return xjs_new_int64(TAG_GET_NV(list->index[idx])); + return ucv_int64_new(TAG_GET_NV(list->index[idx])); case TAG_LNUM: if (TAG_GET_OFFSET(list->index[idx]) + sizeof(int64_t) > list->dsize) return NULL; - return xjs_new_int64(be64toh(*(int64_t *)(list->data + TAG_GET_OFFSET(list->index[idx])))); + /* XXX: u64 */ + return ucv_int64_new(be64toh(*(int64_t *)(list->data + TAG_GET_OFFSET(list->index[idx])))); case TAG_DBL: if (TAG_GET_OFFSET(list->index[idx]) + sizeof(double) > list->dsize) return NULL; - return uc_double_new(*(double *)(list->data + TAG_GET_OFFSET(list->index[idx]))); + return ucv_double_new(*(double *)(list->data + TAG_GET_OFFSET(list->index[idx]))); case TAG_STR: len = TAG_GET_STR_L(list->index[idx]); @@ -702,7 +637,7 @@ uc_vallist_get(uc_value_list *list, size_t idx) for (n = 0; n < len; n++) str[n] = (list->index[idx] >> ((n + 1) << 3)); - return xjs_new_string_len(str, len); + return ucv_string_new_length(str, len); case TAG_LSTR: if (TAG_GET_OFFSET(list->index[idx]) + sizeof(uint32_t) > list->dsize) @@ -713,13 +648,13 @@ uc_vallist_get(uc_value_list *list, size_t idx) if (TAG_GET_OFFSET(list->index[idx]) + sizeof(uint32_t) + len > list->dsize) return NULL; - return xjs_new_string_len(list->data + TAG_GET_OFFSET(list->index[idx]) + sizeof(uint32_t), len); + return ucv_string_new_length(list->data + TAG_GET_OFFSET(list->index[idx]) + sizeof(uint32_t), len); case TAG_PTR: if (TAG_GET_OFFSET(list->index[idx]) + sizeof(void *) > list->dsize) return NULL; - return uc_value_get(*(json_object **)(list->data + TAG_GET_OFFSET(list->index[idx]))); + return ucv_get(*(uc_value_t **)(list->data + TAG_GET_OFFSET(list->index[idx]))); default: return NULL; @@ -46,36 +46,25 @@ typedef struct { char *data; } uc_value_list; -json_object *uc_double_new(double v); +typedef struct uc_value_t uc_value_t; -bool uc_eq(json_object *v1, json_object *v2); -bool uc_cmp(int how, json_object *v1, json_object *v2); -bool uc_val_is_truish(json_object *val); +bool uc_cmp(int how, uc_value_t *v1, uc_value_t *v2); +bool uc_val_is_truish(uc_value_t *val); -enum json_type uc_cast_number(json_object *v, int64_t *n, double *d); +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); -json_object *uc_getval(json_object *scope, json_object *key); -json_object *uc_setval(json_object *scope, json_object *key, json_object *val); +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); void uc_vallist_init(uc_value_list *list); void uc_vallist_free(uc_value_list *list); -ssize_t uc_vallist_add(uc_value_list *list, json_object *value); +ssize_t uc_vallist_add(uc_value_list *list, uc_value_t *value); uc_value_type_t uc_vallist_type(uc_value_list *list, size_t idx); -struct json_object *uc_vallist_get(uc_value_list *list, size_t idx); - -#define uc_value_get(val) \ - ({ \ - struct json_object *__o = val; \ - /*fprintf(stderr, "get(%p // %s) [%d + 1] @ %s:%d\n", __o, json_object_to_json_string(__o), getrefcnt(__o), __FILE__, __LINE__);*/ \ - json_object_get(__o); \ - }) - -#define uc_value_put(val) \ - ({ \ - struct json_object *__o = val; \ - /*fprintf(stderr, "put(%p // %s) [%d - 1] @ %s:%d\n", __o, json_object_to_json_string(__o), getrefcnt(__o), __FILE__, __LINE__);*/ \ - json_object_put(__o); \ - }) +uc_value_t *uc_vallist_get(uc_value_list *list, size_t idx); #endif /* __VALUE_H_ */ @@ -51,8 +51,8 @@ static const uc_insn_definition insn_defs[__I_MAX] = { [I_LUPV] = { 0, 1, 4 }, [I_LVAL] = { 2, 1, 0 }, - [I_CLFN] = { 0, 1, 4, true }, - [I_ARFN] = { 0, 1, 4, true }, + [I_CLFN] = { 0, 1, 4 }, + [I_ARFN] = { 0, 1, 4 }, [I_SLOC] = { 0, 0, 4 }, [I_SUPV] = { 0, 0, 4 }, @@ -90,8 +90,8 @@ static const uc_insn_definition insn_defs[__I_MAX] = { [I_GT] = { 2, 1, 0 }, [I_IN] = { 2, 1, 0 }, - [I_JMP] = { 0, 0, -4, true }, - [I_JMPZ] = { 1, 0, -4, true }, + [I_JMP] = { 0, 0, -4 }, + [I_JMPZ] = { 1, 0, -4 }, [I_COPY] = { 0, 1, 1 }, [I_POP] = { 1, 0, 0 }, @@ -124,19 +124,19 @@ uc_vm_reset_stack(uc_vm *vm) { while (vm->stack.count > 0) { vm->stack.count--; - uc_value_put(vm->stack.entries[vm->stack.count]); + ucv_put(vm->stack.entries[vm->stack.count]); vm->stack.entries[vm->stack.count] = NULL; } } -static json_object * +static uc_value_t * uc_vm_callframe_pop(uc_vm *vm); static void uc_vm_reset_callframes(uc_vm *vm) { while (vm->callframes.count > 0) - uc_value_put(uc_vm_callframe_pop(vm)); + ucv_put(uc_vm_callframe_pop(vm)); } void uc_vm_init(uc_vm *vm, uc_parse_config *config) @@ -152,19 +152,22 @@ void uc_vm_init(uc_vm *vm, uc_parse_config *config) vm->open_upvals = NULL; + vm->values.prev = &vm->values; + vm->values.next = &vm->values; + uc_vm_reset_stack(vm); } void uc_vm_free(uc_vm *vm) { - uc_upvalref *ref; + uc_upvalref_t *ref; - uc_value_put(vm->exception.stacktrace); + ucv_put(vm->exception.stacktrace); free(vm->exception.message); while (vm->open_upvals) { ref = vm->open_upvals->next; - uc_value_put(vm->open_upvals->header.jso); + ucv_put(&vm->open_upvals->header); vm->open_upvals = ref; } @@ -172,6 +175,8 @@ void uc_vm_free(uc_vm *vm) uc_vm_reset_stack(vm); uc_vector_clear(&vm->stack); uc_vector_clear(&vm->callframes); + + ucv_gc(vm, true); } static uc_chunk * @@ -263,11 +268,12 @@ static void uc_vm_frame_dump(uc_vm *vm, uc_callframe *frame) { uc_chunk *chunk = uc_vm_frame_chunk(frame); - uc_function *function; - uc_closure *closure; - uc_upvalref *ref; - json_object *v; + uc_function_t *function; + uc_closure_t *closure; + uc_upvalref_t *ref; + uc_value_t *v; size_t i; + char *s; fprintf(stderr, " [*] CALLFRAME[%zx]\n", frame - vm->callframes.entries); @@ -275,8 +281,9 @@ uc_vm_frame_dump(uc_vm *vm, uc_callframe *frame) fprintf(stderr, " |- stackframe %zu/%zu\n", frame->stackframe, vm->stack.count); - fprintf(stderr, " |- ctx %s\n", - json_object_to_json_string(frame->ctx)); + s = ucv_to_string(NULL, frame->ctx); + fprintf(stderr, " |- ctx %s\n", s); + free(s); if (chunk) { fprintf(stderr, " |- %zu constants\n", @@ -284,12 +291,10 @@ uc_vm_frame_dump(uc_vm *vm, uc_callframe *frame) for (i = 0; i < chunk->constants.isize; i++) { v = uc_chunk_get_constant(chunk, i); - - fprintf(stderr, " | [%zu] %s\n", - i, - json_object_to_json_string(v)); - - uc_value_put(v); + s = ucv_to_jsonstring(NULL, v); + fprintf(stderr, " | [%zu] %s\n", i, s); + free(s); + ucv_put(v); } closure = frame->closure; @@ -301,80 +306,88 @@ uc_vm_frame_dump(uc_vm *vm, uc_callframe *frame) for (i = 0; i < function->nupvals; i++) { 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); + free(s); - if (ref->closed) - fprintf(stderr, " [%zu] <%p> %s {closed} %s\n", - i, - ref, - json_object_to_json_string(v), - json_object_to_json_string(ref->value)); - else - fprintf(stderr, " [%zu] <%p> %s {open[%zu]} %s\n", - i, - ref, - json_object_to_json_string(v), - ref->slot, - json_object_to_json_string(vm->stack.entries[ref->slot])); - - uc_value_put(v); + if (ref->closed) { + s = ucv_to_jsonstring(NULL, ref->value); + fprintf(stderr, "{closed} %s\n", s); + } + else { + s = ucv_to_jsonstring(NULL, vm->stack.entries[ref->slot]); + fprintf(stderr, "{open[%zu]} %s\n", ref->slot, s); + } + + ucv_put(v); + free(s); } } } void -uc_vm_stack_push(uc_vm *vm, json_object *value) +uc_vm_stack_push(uc_vm *vm, uc_value_t *value) { + char *s; + uc_vector_grow(&vm->stack); - uc_value_put(vm->stack.entries[vm->stack.count]); + ucv_put(vm->stack.entries[vm->stack.count]); vm->stack.entries[vm->stack.count] = value; vm->stack.count++; - if (vm->trace) - fprintf(stderr, " [+%zd] %s\n", - vm->stack.count - 1, - json_object_to_json_string(value)); + if (vm->trace) { + s = ucv_to_jsonstring(NULL, value); + fprintf(stderr, " [+%zd] %s\n", vm->stack.count - 1, s); + free(s); + } } -json_object * +uc_value_t * uc_vm_stack_pop(uc_vm *vm) { - json_object *rv; + uc_value_t *rv; + char *s; vm->stack.count--; rv = vm->stack.entries[vm->stack.count]; vm->stack.entries[vm->stack.count] = NULL; - if (vm->trace) - fprintf(stderr, " [-%zd] %s\n", - vm->stack.count, - json_object_to_json_string(rv)); + if (vm->trace) { + s = ucv_to_jsonstring(NULL, rv); + fprintf(stderr, " [-%zd] %s\n", vm->stack.count, s); + free(s); + } return rv; } -json_object * +uc_value_t * uc_vm_stack_peek(uc_vm *vm, size_t offset) { return vm->stack.entries[vm->stack.count + (-1 - offset)]; } static void -uc_vm_stack_set(uc_vm *vm, size_t offset, json_object *value) +uc_vm_stack_set(uc_vm *vm, size_t offset, uc_value_t *value) { - if (vm->trace) - fprintf(stderr, " [!%zu] %s\n", - offset, json_object_to_json_string(value)); + char *s; - uc_value_put(vm->stack.entries[offset]); + if (vm->trace) { + s = ucv_to_jsonstring(NULL, value); + fprintf(stderr, " [!%zu] %s\n", offset, s); + free(s); + } + + ucv_put(vm->stack.entries[offset]); vm->stack.entries[offset] = value; } static void -uc_vm_call_native(uc_vm *vm, json_object *ctx, uc_cfunction *fptr, bool mcall, size_t nargs) +uc_vm_call_native(uc_vm *vm, uc_value_t *ctx, uc_cfunction_t *fptr, bool mcall, size_t nargs) { - json_object *res = NULL; + uc_value_t *res = NULL; uc_callframe *frame; /* add new callframe */ @@ -393,24 +406,25 @@ uc_vm_call_native(uc_vm *vm, json_object *ctx, uc_cfunction *fptr, bool mcall, s res = fptr->cfn(vm, nargs); /* reset stack */ - uc_value_put(uc_vm_callframe_pop(vm)); + ucv_put(uc_vm_callframe_pop(vm)); /* push return value */ if (!vm->exception.type) uc_vm_stack_push(vm, res); else - uc_value_put(res); + ucv_put(res); } static bool -uc_vm_call_function(uc_vm *vm, json_object *ctx, json_object *fno, bool mcall, size_t argspec) +uc_vm_call_function(uc_vm *vm, uc_value_t *ctx, uc_value_t *fno, bool mcall, size_t argspec) { size_t i, j, stackoff, nargs = argspec & 0xffff, nspreads = argspec >> 16; uc_callframe *frame = uc_vm_current_frame(vm); - json_object *ellip, *arg; - uc_function *function; - uc_closure *closure; + uc_value_t *ellip, *arg; + uc_function_t *function; + uc_closure_t *closure; uint16_t slot, tmp; + char *s; /* XXX: make dependent on stack size */ if (vm->callframes.count >= 1000) { @@ -424,11 +438,11 @@ uc_vm_call_function(uc_vm *vm, json_object *ctx, json_object *fno, bool mcall, s /* argument list contains spread operations, we need to reshuffle the stack */ if (nspreads > 0) { /* create temporary array */ - ellip = xjs_new_array_size(nargs); + ellip = ucv_array_new_length(vm, nargs); /* pop original stack values and push to temp array in reverse order */ for (i = 0; i < nargs; i++) - json_object_array_add(ellip, uc_vm_stack_pop(vm)); + ucv_array_push(ellip, uc_vm_stack_pop(vm)); /* for each spread value index ... */ for (i = 0, slot = nargs; i < nspreads; i++) { @@ -437,61 +451,61 @@ uc_vm_call_function(uc_vm *vm, json_object *ctx, json_object *fno, bool mcall, s frame->ip += 2; /* push each preceeding non-spread value to the stack */ - for (j = slot; j > tmp + 1; j--) - uc_vm_stack_push(vm, uc_value_get(json_object_array_get_idx(ellip, j - 1))); + for (j = slot; j > tmp + 1UL; j--) + uc_vm_stack_push(vm, ucv_get(ucv_array_get(ellip, j - 1))); /* read spread value at index... */ slot = tmp; - arg = uc_value_get(json_object_array_get_idx(ellip, slot)); + arg = ucv_get(ucv_array_get(ellip, slot)); /* ... ensure that it is an array type ... */ - if (!json_object_is_type(arg, json_type_array)) { - uc_vm_raise_exception(vm, EXCEPTION_TYPE, - "(%s) is not iterable", - json_object_to_json_string(arg)); + if (ucv_type(arg) != UC_ARRAY) { + s = ucv_to_string(vm, arg); + uc_vm_raise_exception(vm, EXCEPTION_TYPE, "(%s) is not iterable", s); + free(s); return false; } /* ... and push each spread array value as argument to the stack */ - for (j = 0; j < json_object_array_length(arg); j++) - uc_vm_stack_push(vm, uc_value_get(json_object_array_get_idx(arg, j))); + for (j = 0; j < ucv_array_length(arg); j++) + uc_vm_stack_push(vm, ucv_get(ucv_array_get(arg, j))); - uc_value_put(arg); + ucv_put(arg); } /* push remaining non-spread arguments to the stack */ for (i = slot; i > 0; i--) - uc_vm_stack_push(vm, uc_value_get(json_object_array_get_idx(ellip, i - 1))); + uc_vm_stack_push(vm, ucv_get(ucv_array_get(ellip, i - 1))); /* free temp array */ - uc_value_put(ellip); + ucv_put(ellip); /* update arg count */ nargs = vm->stack.count - stackoff - 1; } /* is a native function */ - if (uc_object_is_type(fno, UC_OBJ_CFUNCTION)) { - uc_vm_call_native(vm, ctx, uc_object_as_cfunction(fno), mcall, nargs); + if (ucv_type(fno) == UC_CFUNCTION) { + uc_vm_call_native(vm, ctx, (uc_cfunction_t *)fno, mcall, nargs); return true; } - if (!uc_object_is_type(fno, UC_OBJ_CLOSURE)) { + if (ucv_type(fno) != UC_CLOSURE) { uc_vm_raise_exception(vm, EXCEPTION_TYPE, "left-hand side is not a function"); return false; } - closure = uc_object_as_closure(fno); + closure = (uc_closure_t *)fno; function = closure->function; /* fewer arguments on stack than function expects => pad */ if (nargs < function->nargs) { for (i = nargs; i < function->nargs; i++) { if (function->vararg && (i + 1) == function->nargs) - uc_vm_stack_push(vm, xjs_new_array_size(0)); + uc_vm_stack_push(vm, ucv_array_new_length(vm, 0)); else uc_vm_stack_push(vm, NULL); } @@ -501,10 +515,10 @@ uc_vm_call_function(uc_vm *vm, json_object *ctx, json_object *fno, bool mcall, s else if (nargs > function->nargs - function->vararg) { /* is a vararg function => pass excess args as array */ if (function->vararg) { - ellip = xjs_new_array_size(nargs - (function->nargs - 1)); + ellip = ucv_array_new_length(vm, nargs - (function->nargs - 1)); for (i = function->nargs; i <= nargs; i++) - json_object_array_add(ellip, uc_vm_stack_peek(vm, nargs - i)); + ucv_array_push(ellip, uc_vm_stack_peek(vm, nargs - i)); for (i = function->nargs; i <= nargs; i++) uc_vm_stack_pop(vm); @@ -515,7 +529,7 @@ uc_vm_call_function(uc_vm *vm, json_object *ctx, json_object *fno, bool mcall, s /* static amount of args => drop excess values */ else { for (i = function->nargs; i < nargs; i++) - uc_value_put(uc_vm_stack_pop(vm)); + ucv_put(uc_vm_stack_pop(vm)); } } @@ -543,19 +557,19 @@ uc_dump_insn(uc_vm *vm, uint8_t *pos, enum insn_type insn) { uc_callframe *frame = uc_vm_current_frame(vm); uc_chunk *chunk = uc_vm_frame_chunk(frame); - size_t msglen = 0, srcpos; - json_object *cnst = NULL; - char *msg = NULL; + uc_stringbuf_t *buf = NULL; + uc_value_t *cnst = NULL; + size_t srcpos; + char *s; - srcpos = uc_function_get_srcpos(frame->closure->function, pos - chunk->entries); + srcpos = ucv_function_srcpos((uc_value_t *)frame->closure->function, pos - chunk->entries); if (last_srcpos == 0 || last_source != frame->closure->function->source || srcpos != last_srcpos) { - format_source_context(&msg, &msglen, - frame->closure->function->source, - srcpos, true); + buf = xprintbuf_new(); - fprintf(stderr, "%s", msg); - free(msg); + format_source_context(buf, frame->closure->function->source, srcpos, true); + fwrite(buf->buf, 1, printbuf_length(buf), stderr); + printbuf_free(buf); last_source = frame->closure->function->source; last_srcpos = srcpos; @@ -574,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 : vm->arg.s16); + vm->arg.s16 < 0 ? -(unsigned)vm->arg.s16 : (unsigned)vm->arg.s16); break; case -4: fprintf(stderr, " {%c0x%x}", vm->arg.s32 < 0 ? '-' : '+', - vm->arg.s32 < 0 ? -(unsigned)vm->arg.s32 : vm->arg.s32); + vm->arg.s32 < 0 ? -(unsigned)vm->arg.s32 : (unsigned)vm->arg.s32); break; case 1: @@ -605,9 +619,11 @@ uc_dump_insn(uc_vm *vm, uint8_t *pos, enum insn_type insn) case I_LVAR: case I_SVAR: cnst = uc_chunk_get_constant(uc_vm_frame_chunk(uc_vector_last(&vm->callframes)), vm->arg.u32); + s = cnst ? ucv_to_jsonstring(NULL, cnst) : NULL; - fprintf(stderr, "\t; %s", cnst ? json_object_to_json_string(cnst) : "null"); - uc_value_put(cnst); + fprintf(stderr, "\t; %s", s ? s : "(?)"); + ucv_put(cnst); + free(s); break; case I_LLOC: @@ -615,9 +631,11 @@ uc_dump_insn(uc_vm *vm, uint8_t *pos, enum insn_type insn) case I_SLOC: case I_SUPV: cnst = uc_chunk_debug_get_variable(chunk, pos - chunk->entries, vm->arg.u32, (insn == I_LUPV || insn == I_SUPV)); + s = cnst ? ucv_to_jsonstring(NULL, cnst) : NULL; - fprintf(stderr, "\t; %s", cnst ? json_object_to_json_string(cnst) : "(?)"); - uc_value_put(cnst); + fprintf(stderr, "\t; %s", s ? s : "(?)"); + ucv_put(cnst); + free(s); break; case I_ULOC: @@ -629,11 +647,14 @@ uc_dump_insn(uc_vm *vm, uint8_t *pos, enum insn_type insn) if (!cnst) cnst = uc_chunk_get_constant(uc_vm_frame_chunk(uc_vector_last(&vm->callframes)), vm->arg.u32 & 0x00ffffff); + s = cnst ? ucv_to_jsonstring(NULL, cnst) : NULL; + fprintf(stderr, "\t; %s (%s)", - cnst ? json_object_to_json_string(cnst) : "(?)", + s ? s : "(?)", insn_names[vm->arg.u32 >> 24]); - uc_value_put(cnst); + ucv_put(cnst); + free(s); break; case I_UVAL: @@ -647,14 +668,38 @@ uc_dump_insn(uc_vm *vm, uint8_t *pos, enum insn_type insn) fprintf(stderr, "\n"); } -static int -uc_vm_exception_tostring(json_object *jso, struct printbuf *pb, int level, int flags) +static uc_value_t * +uc_vm_exception_tostring(uc_vm *vm, size_t nargs) { - bool strict = (level > 0) || (flags & JSON_C_TO_STRING_STRICT); - json_object *message = json_object_object_get(jso, "message"); + uc_callframe *frame = uc_vm_current_frame(vm); + uc_value_t *message = ucv_object_get(frame->ctx, "message", NULL); - return sprintbuf(pb, "%s", - strict ? json_object_to_json_string(message) : json_object_get_string(message)); + return message ? ucv_get(message) : ucv_string_new("Exception"); +} + +static uc_value_t *exception_prototype = NULL; + +static uc_value_t * +uc_vm_exception_new(uc_vm *vm, uc_exception_type_t type, const char *message, uc_value_t *stacktrace) +{ + uc_value_t *exo; + + if (exception_prototype == NULL) { + exception_prototype = ucv_object_new(vm); + + ucv_object_add(exception_prototype, "tostring", + ucv_cfunction_new("tostring", uc_vm_exception_tostring)); + } + + exo = ucv_object_new(vm); + + ucv_object_add(exo, "type", ucv_string_new(exception_type_strings[type])); + ucv_object_add(exo, "message", ucv_string_new(message)); + ucv_object_add(exo, "stacktrace", ucv_get(stacktrace)); + + ucv_prototype_set(exo, ucv_get(exception_prototype)); + + return exo; } static bool @@ -662,7 +707,7 @@ uc_vm_handle_exception(uc_vm *vm) { uc_callframe *frame = uc_vm_current_frame(vm); uc_chunk *chunk = NULL; - json_object *exo; + uc_value_t *exo; size_t i, pos; if (!frame->closure) @@ -680,16 +725,11 @@ uc_vm_handle_exception(uc_vm *vm) /* we found a matching range... first unwind stack */ while (vm->stack.count > frame->stackframe + chunk->ehranges.entries[i].slot) - uc_value_put(uc_vm_stack_pop(vm)); + ucv_put(uc_vm_stack_pop(vm)); /* prepare exception object and expose it to user handler code */ - exo = xjs_new_object(); + exo = uc_vm_exception_new(vm, vm->exception.type, vm->exception.message, vm->exception.stacktrace); - json_object_object_add(exo, "type", xjs_new_string(exception_type_strings[vm->exception.type])); - json_object_object_add(exo, "message", xjs_new_string(vm->exception.message)); - json_object_object_add(exo, "stacktrace", uc_value_get(vm->exception.stacktrace)); - - json_object_set_serializer(exo, uc_vm_exception_tostring, NULL, NULL); uc_vm_stack_push(vm, exo); /* reset exception information */ @@ -721,35 +761,35 @@ uc_vm_handle_exception(uc_vm *vm) return false; } -static json_object * +static uc_value_t * uc_vm_capture_stacktrace(uc_vm *vm, size_t i) { - json_object *stacktrace, *entry, *last = NULL; - uc_function *function; + uc_value_t *stacktrace, *entry, *last = NULL; + uc_function_t *function; uc_callframe *frame; size_t off, srcpos; char *name; - stacktrace = xjs_new_array(); + stacktrace = ucv_array_new(vm); for (; i > 0; i--) { frame = &vm->callframes.entries[i - 1]; - entry = xjs_new_object(); + entry = ucv_object_new(vm); if (frame->closure) { function = frame->closure->function; off = (frame->ip - uc_vm_frame_chunk(frame)->entries) - 1; - srcpos = uc_function_get_srcpos(function, off); + srcpos = ucv_function_srcpos((uc_value_t *)function, off); - json_object_object_add(entry, "filename", xjs_new_string(function->source->filename)); - json_object_object_add(entry, "line", xjs_new_int64(uc_source_get_line(function->source, &srcpos))); - json_object_object_add(entry, "byte", xjs_new_int64(srcpos)); + ucv_object_add(entry, "filename", ucv_string_new(function->source->filename)); + ucv_object_add(entry, "line", ucv_int64_new(uc_source_get_line(function->source, &srcpos))); + ucv_object_add(entry, "byte", ucv_int64_new(srcpos)); } if (i > 1) { if (frame->closure) { - if (frame->closure->function->name) + if (frame->closure->function->name[0]) name = frame->closure->function->name; else if (frame->closure->is_arrow) name = "[arrow function]"; @@ -760,29 +800,29 @@ uc_vm_capture_stacktrace(uc_vm *vm, size_t i) name = frame->cfunction->name; } - json_object_object_add(entry, "function", xjs_new_string(name)); + ucv_object_add(entry, "function", ucv_string_new(name)); } - if (!json_object_equal(last, entry)) { - json_object_array_add(stacktrace, entry); + if (!ucv_equal(last, entry)) { + ucv_array_push(stacktrace, entry); last = entry; } else { - uc_value_put(entry); + ucv_put(entry); } } return stacktrace; } -static json_object * +static uc_value_t * uc_vm_get_error_context(uc_vm *vm) { - json_object *stacktrace; + uc_value_t *stacktrace; uc_callframe *frame; + uc_stringbuf_t *buf; uc_chunk *chunk; - size_t offset, len = 0, i; - char *msg = NULL; + size_t offset, i; /* skip to first non-native function call frame */ for (i = vm->callframes.count; i > 0; i--) @@ -795,17 +835,17 @@ uc_vm_get_error_context(uc_vm *vm) return NULL; chunk = uc_vm_frame_chunk(frame); - offset = uc_function_get_srcpos(frame->closure->function, (frame->ip - chunk->entries) - 1); + offset = ucv_function_srcpos((uc_value_t *)frame->closure->function, (frame->ip - chunk->entries) - 1); stacktrace = uc_vm_capture_stacktrace(vm, i); + buf = ucv_stringbuf_new(); + if (offset) - format_error_context(&msg, &len, frame->closure->function->source, stacktrace, offset); + format_error_context(buf, frame->closure->function->source, stacktrace, offset); else - xasprintf(&msg, "At offset %zu", (frame->ip - chunk->entries) - 1); + ucv_stringbuf_printf(buf, "At offset %zu", (frame->ip - chunk->entries) - 1); - json_object_object_add(json_object_array_get_idx(stacktrace, 0), "context", xjs_new_string(msg)); - - free(msg); + ucv_object_add(ucv_array_get(stacktrace, 0), "context", ucv_stringbuf_finish(buf)); return stacktrace; } @@ -823,7 +863,7 @@ uc_vm_raise_exception(uc_vm *vm, uc_exception_type_t type, const char *fmt, ...) xvasprintf(&vm->exception.message, fmt, ap); va_end(ap); - uc_value_put(vm->exception.stacktrace); + ucv_put(vm->exception.stacktrace); vm->exception.stacktrace = uc_vm_get_error_context(vm); } @@ -837,15 +877,15 @@ uc_vm_insn_load(uc_vm *vm, enum insn_type insn) break; case I_LOAD8: - uc_vm_stack_push(vm, xjs_new_int64(vm->arg.s8)); + uc_vm_stack_push(vm, ucv_int64_new(vm->arg.s8)); break; case I_LOAD16: - uc_vm_stack_push(vm, xjs_new_int64(vm->arg.s16)); + uc_vm_stack_push(vm, ucv_int64_new(vm->arg.s16)); break; case I_LOAD32: - uc_vm_stack_push(vm, xjs_new_int64(vm->arg.s32)); + uc_vm_stack_push(vm, ucv_int64_new(vm->arg.s32)); break; default: @@ -856,33 +896,33 @@ uc_vm_insn_load(uc_vm *vm, enum insn_type insn) static void uc_vm_insn_load_regexp(uc_vm *vm, enum insn_type insn) { + uc_value_t *re, *jstr = uc_chunk_get_constant(uc_vm_current_chunk(vm), vm->arg.u32); bool icase = false, newline = false, global = false; - json_object *jstr = uc_chunk_get_constant(uc_vm_current_chunk(vm), vm->arg.u32); - const char *str; - uc_regexp *re; - char *err; + char *str, *err = NULL; - if (!json_object_is_type(jstr, json_type_string) || json_object_get_string_len(jstr) < 2) { + if (ucv_type(jstr) != UC_STRING || ucv_string_length(jstr) < 2) { uc_vm_stack_push(vm, NULL); - uc_value_put(jstr); + ucv_put(jstr); return; } - str = json_object_get_string(jstr); + str = ucv_string_get(jstr); global = (*str & (1 << 0)); icase = (*str & (1 << 1)); newline = (*str & (1 << 2)); - re = uc_regexp_new(++str, icase, newline, global, &err); + re = ucv_regexp_new(++str, icase, newline, global, &err); - uc_value_put(jstr); + ucv_put(jstr); if (re) - uc_vm_stack_push(vm, re->header.jso); + uc_vm_stack_push(vm, re); else uc_vm_raise_exception(vm, EXCEPTION_SYNTAX, "%s", err); + + free(err); } static void @@ -894,29 +934,32 @@ uc_vm_insn_load_null(uc_vm *vm, enum insn_type insn) static void uc_vm_insn_load_bool(uc_vm *vm, enum insn_type insn) { - uc_vm_stack_push(vm, xjs_new_boolean(insn == I_LTRUE)); + uc_vm_stack_push(vm, ucv_boolean_new(insn == I_LTRUE)); } static void uc_vm_insn_load_var(uc_vm *vm, enum insn_type insn) { - json_object *name, *val = NULL; - uc_prototype *scope, *next; + uc_value_t *name, *val = NULL; + uc_value_t *scope, *next; + bool found; scope = vm->globals; name = uc_chunk_get_constant(uc_vm_current_chunk(vm), vm->arg.u32); - while (json_object_get_type(name) == json_type_string) { - if (json_object_object_get_ex(scope->header.jso, json_object_get_string(name), &val)) + while (ucv_type(name) == UC_STRING) { + val = ucv_object_get(scope, ucv_string_get(name), &found); + + if (found) break; - next = scope->parent; + next = ucv_prototype_get(scope); if (!next) { if (vm->config->strict_declarations) { uc_vm_raise_exception(vm, EXCEPTION_REFERENCE, "access to undeclared variable %s", - json_object_get_string(name)); + ucv_string_get(name)); } break; @@ -925,21 +968,21 @@ uc_vm_insn_load_var(uc_vm *vm, enum insn_type insn) scope = next; } - uc_value_put(name); + ucv_put(name); - uc_vm_stack_push(vm, uc_value_get(val)); + uc_vm_stack_push(vm, ucv_get(val)); } static void uc_vm_insn_load_val(uc_vm *vm, enum insn_type insn) { - json_object *k = uc_vm_stack_pop(vm); - json_object *v = uc_vm_stack_pop(vm); + uc_value_t *k = uc_vm_stack_pop(vm); + uc_value_t *v = uc_vm_stack_pop(vm); - switch (json_object_get_type(v)) { - case json_type_object: - case json_type_array: - uc_vm_stack_push(vm, uc_getval(v, k)); + switch (ucv_type(v)) { + case UC_OBJECT: + case UC_ARRAY: + uc_vm_stack_push(vm, uc_getval(vm, v, k)); break; default: @@ -950,21 +993,20 @@ uc_vm_insn_load_val(uc_vm *vm, enum insn_type insn) break; } - - uc_value_put(k); - uc_value_put(v); + ucv_put(k); + ucv_put(v); } static void uc_vm_insn_load_upval(uc_vm *vm, enum insn_type insn) { uc_callframe *frame = uc_vm_current_frame(vm); - uc_upvalref *ref = frame->closure->upvals[vm->arg.u32]; + uc_upvalref_t *ref = frame->closure->upvals[vm->arg.u32]; if (ref->closed) - uc_vm_stack_push(vm, uc_value_get(ref->value)); + uc_vm_stack_push(vm, ucv_get(ref->value)); else - uc_vm_stack_push(vm, uc_value_get(vm->stack.entries[ref->slot])); + uc_vm_stack_push(vm, ucv_get(vm->stack.entries[ref->slot])); } static void @@ -972,15 +1014,16 @@ uc_vm_insn_load_local(uc_vm *vm, enum insn_type insn) { uc_callframe *frame = uc_vm_current_frame(vm); - uc_vm_stack_push(vm, uc_value_get(vm->stack.entries[frame->stackframe + vm->arg.u32])); + uc_vm_stack_push(vm, ucv_get(vm->stack.entries[frame->stackframe + vm->arg.u32])); } -static uc_upvalref * +static uc_upvalref_t * uc_vm_capture_upval(uc_vm *vm, size_t slot) { - uc_upvalref *curr = vm->open_upvals; - uc_upvalref *prev = NULL; - uc_upvalref *created; + uc_upvalref_t *curr = vm->open_upvals; + uc_upvalref_t *prev = NULL; + uc_upvalref_t *created; + char *s; while (curr && curr->slot > slot) { prev = curr; @@ -988,23 +1031,23 @@ uc_vm_capture_upval(uc_vm *vm, size_t slot) } if (curr && curr->slot == slot) { - if (vm->trace) - fprintf(stderr, " {+%zu} <%p> %s\n", - slot, - curr, - json_object_to_json_string(vm->stack.entries[slot])); + if (vm->trace) { + s = ucv_to_string(NULL, vm->stack.entries[slot]); + fprintf(stderr, " {+%zu} <%p> %s\n", slot, curr, s); + free(s); + } return curr; } - created = uc_upvalref_new(slot); + created = (uc_upvalref_t *)ucv_upvalref_new(slot); created->next = curr; - if (vm->trace) - fprintf(stderr, " {*%zu} <%p> %s\n", - slot, - created, - json_object_to_json_string(vm->stack.entries[slot])); + if (vm->trace) { + s = ucv_to_string(NULL, vm->stack.entries[slot]); + fprintf(stderr, " {*%zu} <%p> %s\n", slot, created, s); + free(s); + } if (prev) prev->next = created; @@ -1017,21 +1060,22 @@ uc_vm_capture_upval(uc_vm *vm, size_t slot) static void uc_vm_close_upvals(uc_vm *vm, size_t slot) { - uc_upvalref *ref; + uc_upvalref_t *ref; + char *s; while (vm->open_upvals && vm->open_upvals->slot >= slot) { ref = vm->open_upvals; - ref->value = uc_value_get(vm->stack.entries[ref->slot]); + ref->value = ucv_get(vm->stack.entries[ref->slot]); ref->closed = true; - if (vm->trace) - fprintf(stderr, " {!%zu} <%p> %s\n", - ref->slot, - ref, - json_object_to_json_string(ref->value)); + if (vm->trace) { + s = ucv_to_string(NULL, ref->value); + fprintf(stderr, " {!%zu} <%p> %s\n", ref->slot, ref, s); + free(s); + } vm->open_upvals = ref->next; - json_object_put(ref->header.jso); + ucv_put(&ref->header); } } @@ -1039,13 +1083,13 @@ static void uc_vm_insn_load_closure(uc_vm *vm, enum insn_type insn) { uc_callframe *frame = uc_vm_current_frame(vm); - json_object *fno = uc_chunk_get_constant(uc_vm_current_chunk(vm), vm->arg.u32); - uc_function *function = uc_object_as_function(fno); - uc_closure *closure = uc_closure_new(function, insn == I_ARFN); + uc_value_t *fno = uc_chunk_get_constant(uc_vm_current_chunk(vm), vm->arg.u32); + uc_function_t *function = (uc_function_t *)fno; + uc_closure_t *closure = (uc_closure_t *)ucv_closure_new(vm, function, insn == I_ARFN); volatile int32_t uv; size_t i; - uc_vm_stack_push(vm, closure->header.jso); + uc_vm_stack_push(vm, &closure->header); for (i = 0; i < function->nupvals; i++) { uv = ( @@ -1060,7 +1104,7 @@ uc_vm_insn_load_closure(uc_vm *vm, enum insn_type insn) else closure->upvals[i] = frame->closure->upvals[uv]; - uc_value_get(closure->upvals[i]->header.jso); + ucv_get(&closure->upvals[i]->header); frame->ip += 4; } @@ -1069,23 +1113,26 @@ uc_vm_insn_load_closure(uc_vm *vm, enum insn_type insn) static void uc_vm_insn_store_var(uc_vm *vm, enum insn_type insn) { - json_object *name, *v = uc_vm_stack_pop(vm); - uc_prototype *scope, *next; + uc_value_t *name, *v = uc_vm_stack_pop(vm); + uc_value_t *scope, *next; + bool found; scope = vm->globals; name = uc_chunk_get_constant(uc_vm_current_chunk(vm), vm->arg.u32); - while (json_object_get_type(name) == json_type_string) { - if (json_object_object_get_ex(scope->header.jso, json_object_get_string(name), NULL)) + while (ucv_type(name) == UC_STRING) { + ucv_object_get(scope, ucv_string_get(name), &found); + + if (found) break; - next = scope->parent; + next = ucv_prototype_get(scope); if (!next) { if (vm->config->strict_declarations) { uc_vm_raise_exception(vm, EXCEPTION_REFERENCE, "access to undeclared variable %s", - json_object_get_string(name)); + ucv_string_get(name)); } break; @@ -1094,53 +1141,45 @@ uc_vm_insn_store_var(uc_vm *vm, enum insn_type insn) scope = next; } - if (scope && json_object_get_type(name) == json_type_string) - json_object_object_add(scope->header.jso, json_object_get_string(name), uc_value_get(v)); + if (scope && ucv_type(name) == UC_STRING) + ucv_object_add(scope, ucv_string_get(name), ucv_get(v)); - uc_value_put(name); + ucv_put(name); uc_vm_stack_push(vm, v); } static void uc_vm_insn_store_val(uc_vm *vm, enum insn_type insn) { - json_object *v = uc_vm_stack_pop(vm); - json_object *k = uc_vm_stack_pop(vm); - json_object *o = uc_vm_stack_pop(vm); - - const char *typenames[] = { - [json_type_string] = "string", - [json_type_int] = "integer", - [json_type_double] = "double", - [json_type_boolean] = "boolean", - [json_type_null] = "null" - }; + uc_value_t *v = uc_vm_stack_pop(vm); + uc_value_t *k = uc_vm_stack_pop(vm); + uc_value_t *o = uc_vm_stack_pop(vm); - switch (json_object_get_type(o)) { - case json_type_object: - case json_type_array: - uc_vm_stack_push(vm, uc_setval(o, k, v)); + switch (ucv_type(o)) { + case UC_OBJECT: + case UC_ARRAY: + uc_vm_stack_push(vm, uc_setval(vm, o, k, v)); break; default: uc_vm_raise_exception(vm, EXCEPTION_TYPE, "attempt to set property on %s value", - typenames[json_object_get_type(o)]); + ucv_typename(o)); } - uc_value_put(o); - uc_value_put(k); + ucv_put(o); + ucv_put(k); } static void uc_vm_insn_store_upval(uc_vm *vm, enum insn_type insn) { uc_callframe *frame = uc_vm_current_frame(vm); - uc_upvalref *ref = frame->closure->upvals[vm->arg.u32]; - json_object *val = uc_value_get(uc_vm_stack_peek(vm, 0)); + uc_upvalref_t *ref = frame->closure->upvals[vm->arg.u32]; + uc_value_t *val = ucv_get(uc_vm_stack_peek(vm, 0)); if (ref->closed) { - uc_value_put(ref->value); + ucv_put(ref->value); ref->value = val; } else { @@ -1152,43 +1191,43 @@ static void uc_vm_insn_store_local(uc_vm *vm, enum insn_type insn) { uc_callframe *frame = uc_vm_current_frame(vm); - json_object *val = uc_value_get(uc_vm_stack_peek(vm, 0)); + uc_value_t *val = ucv_get(uc_vm_stack_peek(vm, 0)); uc_vm_stack_set(vm, frame->stackframe + vm->arg.u32, val); } -static json_object * -uc_vm_value_bitop(uc_vm *vm, enum insn_type operation, json_object *value, json_object *operand) +static uc_value_t * +uc_vm_value_bitop(uc_vm *vm, enum insn_type operation, uc_value_t *value, uc_value_t *operand) { - json_object *rv = NULL; + uc_value_t *rv = NULL; int64_t n1, n2; double d; - if (uc_cast_number(value, &n1, &d) == json_type_double) + if (uc_cast_number(value, &n1, &d) == UC_DOUBLE) n1 = isnan(d) ? 0 : (int64_t)d; - if (uc_cast_number(operand, &n2, &d) == json_type_double) + if (uc_cast_number(operand, &n2, &d) == UC_DOUBLE) n2 = isnan(d) ? 0 : (int64_t)d; switch (operation) { case I_LSHIFT: - rv = xjs_new_int64(n1 << n2); + rv = ucv_int64_new(n1 << n2); break; case I_RSHIFT: - rv = xjs_new_int64(n1 >> n2); + rv = ucv_int64_new(n1 >> n2); break; case I_BAND: - rv = xjs_new_int64(n1 & n2); + rv = ucv_int64_new(n1 & n2); break; case I_BXOR: - rv = xjs_new_int64(n1 ^ n2); + rv = ucv_int64_new(n1 ^ n2); break; case I_BOR: - rv = xjs_new_int64(n1 | n2); + rv = ucv_int64_new(n1 | n2); break; default: @@ -1198,32 +1237,32 @@ uc_vm_value_bitop(uc_vm *vm, enum insn_type operation, json_object *value, json_ return rv; } -static json_object * -uc_vm_value_arith(uc_vm *vm, enum insn_type operation, json_object *value, json_object *operand) +static uc_value_t * +uc_vm_value_arith(uc_vm *vm, enum insn_type operation, uc_value_t *value, uc_value_t *operand) { - json_object *rv = NULL; - enum json_type t1, t2; - const char *s1, *s2; + uc_value_t *rv = NULL; + uc_type_t t1, t2; + char *s, *s1, *s2; size_t len1, len2; int64_t n1, n2; double d1, d2; - char *s; if (operation > I_MOD) return uc_vm_value_bitop(vm, operation, value, operand); - if (operation == I_ADD && - (json_object_is_type(value, json_type_string) || - json_object_is_type(operand, json_type_string))) { - s1 = value ? json_object_get_string(value) : "null"; - s2 = operand ? json_object_get_string(operand) : "null"; - len1 = strlen(s1); - len2 = strlen(s2); + if (operation == I_ADD && (ucv_type(value) == UC_STRING || ucv_type(operand) == UC_STRING)) { + s1 = (ucv_type(value) != UC_STRING) ? ucv_to_string(vm, value) : NULL; + s2 = (ucv_type(operand) != UC_STRING) ? ucv_to_string(vm, operand) : NULL; + len1 = s1 ? strlen(s1) : ucv_string_length(value); + len2 = s2 ? strlen(s2) : ucv_string_length(operand); s = xalloc(len1 + len2 + 1); - snprintf(s, len1 + len2 + 1, "%s%s", s1, s2); + memcpy(s, s1 ? s1 : ucv_string_get(value), len1); + memcpy(s + len1, s2 ? s2 : ucv_string_get(operand), len2); + free(s1); + free(s2); - rv = xjs_new_string(s); + rv = ucv_string_new_length(s, len1 + len2); free(s); @@ -1233,38 +1272,38 @@ uc_vm_value_arith(uc_vm *vm, enum insn_type operation, json_object *value, json_ t1 = uc_cast_number(value, &n1, &d1); t2 = uc_cast_number(operand, &n2, &d2); - if (t1 == json_type_double || t2 == json_type_double) { - d1 = (t1 == json_type_double) ? d1 : (double)n1; - d2 = (t2 == json_type_double) ? d2 : (double)n2; + if (t1 == UC_DOUBLE || t2 == UC_DOUBLE) { + d1 = (t1 == UC_DOUBLE) ? d1 : (double)n1; + d2 = (t2 == UC_DOUBLE) ? d2 : (double)n2; switch (operation) { case I_ADD: case I_PLUS: - rv = uc_double_new(d1 + d2); + rv = ucv_double_new(d1 + d2); break; case I_SUB: - rv = uc_double_new(d1 - d2); + rv = ucv_double_new(d1 - d2); break; case I_MUL: - rv = uc_double_new(d1 * d2); + rv = ucv_double_new(d1 * d2); break; case I_DIV: if (d2 == 0.0) - rv = uc_double_new(INFINITY); + rv = ucv_double_new(INFINITY); else if (isnan(d2)) - rv = uc_double_new(NAN); + rv = ucv_double_new(NAN); else if (!isfinite(d2)) - rv = uc_double_new(isfinite(d1) ? 0.0 : NAN); + rv = ucv_double_new(isfinite(d1) ? 0.0 : NAN); else - rv = uc_double_new(d1 / d2); + rv = ucv_double_new(d1 / d2); break; case I_MOD: - rv = uc_double_new(NAN); + rv = ucv_double_new(NAN); break; default: @@ -1278,27 +1317,27 @@ uc_vm_value_arith(uc_vm *vm, enum insn_type operation, json_object *value, json_ switch (operation) { case I_ADD: case I_PLUS: - rv = xjs_new_int64(n1 + n2); + rv = ucv_int64_new(n1 + n2); break; case I_SUB: - rv = xjs_new_int64(n1 - n2); + rv = ucv_int64_new(n1 - n2); break; case I_MUL: - rv = xjs_new_int64(n1 * n2); + rv = ucv_int64_new(n1 * n2); break; case I_DIV: if (n2 == 0) - rv = uc_double_new(INFINITY); + rv = ucv_double_new(INFINITY); else - rv = xjs_new_int64(n1 / n2); + rv = ucv_int64_new(n1 / n2); break; case I_MOD: - rv = xjs_new_int64(n1 % n2); + rv = ucv_int64_new(n1 % n2); break; default: @@ -1315,25 +1354,28 @@ uc_vm_value_arith(uc_vm *vm, enum insn_type operation, json_object *value, json_ static void uc_vm_insn_update_var(uc_vm *vm, enum insn_type insn) { - json_object *name, *val, *inc = uc_vm_stack_pop(vm); - uc_prototype *scope, *next; + uc_value_t *name, *val, *inc = uc_vm_stack_pop(vm); + uc_value_t *scope, *next; + bool found; scope = vm->globals; name = uc_chunk_get_constant(uc_vm_current_chunk(vm), vm->arg.u32 & 0x00FFFFFF); - assert(json_object_is_type(name, json_type_string)); + assert(ucv_type(name) == UC_STRING); + + while (true) { + val = ucv_object_get(scope, ucv_string_get(name), &found); - while (true) { - if (json_object_object_get_ex(scope->header.jso, json_object_get_string(name), &val)) + if (found) break; - next = scope->parent; + next = ucv_prototype_get(scope); if (!next) { if (vm->config->strict_declarations) { uc_vm_raise_exception(vm, EXCEPTION_REFERENCE, "access to undeclared variable %s", - json_object_get_string(name)); + ucv_string_get(name)); } break; @@ -1344,26 +1386,26 @@ uc_vm_insn_update_var(uc_vm *vm, enum insn_type insn) val = uc_vm_value_arith(vm, vm->arg.u32 >> 24, val, inc); - json_object_object_add(scope->header.jso, json_object_get_string(name), uc_value_get(val)); + ucv_object_add(scope, ucv_string_get(name), ucv_get(val)); uc_vm_stack_push(vm, val); - uc_value_put(name); - uc_value_put(inc); + ucv_put(name); + ucv_put(inc); } static void uc_vm_insn_update_val(uc_vm *vm, enum insn_type insn) { - json_object *inc = uc_vm_stack_pop(vm); - json_object *k = uc_vm_stack_pop(vm); - json_object *v = uc_vm_stack_pop(vm); - json_object *val = NULL; + uc_value_t *inc = uc_vm_stack_pop(vm); + uc_value_t *k = uc_vm_stack_pop(vm); + uc_value_t *v = uc_vm_stack_pop(vm); + uc_value_t *val = NULL; - switch (json_object_get_type(v)) { - case json_type_object: - case json_type_array: - val = uc_getval(v, k); - uc_vm_stack_push(vm, uc_setval(v, k, uc_vm_value_arith(vm, vm->arg.u8, val, inc))); + switch (ucv_type(v)) { + case UC_OBJECT: + case UC_ARRAY: + val = uc_getval(vm, v, k); + uc_vm_stack_push(vm, uc_setval(vm, v, k, uc_vm_value_arith(vm, vm->arg.u8, val, inc))); break; default: @@ -1374,10 +1416,10 @@ uc_vm_insn_update_val(uc_vm *vm, enum insn_type insn) break; } - uc_value_put(val); - uc_value_put(inc); - uc_value_put(v); - uc_value_put(k); + ucv_put(val); + ucv_put(inc); + ucv_put(v); + ucv_put(k); } static void @@ -1385,9 +1427,9 @@ uc_vm_insn_update_upval(uc_vm *vm, enum insn_type insn) { uc_callframe *frame = uc_vm_current_frame(vm); size_t slot = vm->arg.u32 & 0x00FFFFFF; - uc_upvalref *ref = frame->closure->upvals[slot]; - json_object *inc = uc_vm_stack_pop(vm); - json_object *val; + uc_upvalref_t *ref = frame->closure->upvals[slot]; + uc_value_t *inc = uc_vm_stack_pop(vm); + uc_value_t *val; if (ref->closed) val = ref->value; @@ -1398,14 +1440,14 @@ uc_vm_insn_update_upval(uc_vm *vm, enum insn_type insn) uc_vm_stack_push(vm, val); - uc_value_put(inc); + ucv_put(inc); if (ref->closed) { - uc_value_put(ref->value); - ref->value = uc_value_get(uc_vm_stack_peek(vm, 0)); + ucv_put(ref->value); + ref->value = ucv_get(uc_vm_stack_peek(vm, 0)); } else { - uc_vm_stack_set(vm, ref->slot, uc_value_get(uc_vm_stack_peek(vm, 0))); + uc_vm_stack_set(vm, ref->slot, ucv_get(uc_vm_stack_peek(vm, 0))); } } @@ -1414,22 +1456,22 @@ uc_vm_insn_update_local(uc_vm *vm, enum insn_type insn) { uc_callframe *frame = uc_vm_current_frame(vm); size_t slot = vm->arg.u32 & 0x00FFFFFF; - json_object *inc = uc_vm_stack_pop(vm); - json_object *val; + uc_value_t *inc = uc_vm_stack_pop(vm); + uc_value_t *val; val = uc_vm_value_arith(vm, vm->arg.u32 >> 24, vm->stack.entries[frame->stackframe + slot], inc); uc_vm_stack_push(vm, val); - uc_value_put(inc); - uc_vm_stack_set(vm, frame->stackframe + slot, uc_value_get(uc_vm_stack_peek(vm, 0))); + ucv_put(inc); + uc_vm_stack_set(vm, frame->stackframe + slot, ucv_get(uc_vm_stack_peek(vm, 0))); } static void uc_vm_insn_narr(uc_vm *vm, enum insn_type insn) { - json_object *arr = xjs_new_array_size(vm->arg.u32); + uc_value_t *arr = ucv_array_new_length(vm, vm->arg.u32); uc_vm_stack_push(vm, arr); } @@ -1437,11 +1479,11 @@ uc_vm_insn_narr(uc_vm *vm, enum insn_type insn) static void uc_vm_insn_parr(uc_vm *vm, enum insn_type insn) { - json_object *arr = uc_vm_stack_peek(vm, vm->arg.u32); + uc_value_t *arr = uc_vm_stack_peek(vm, vm->arg.u32); size_t idx; for (idx = 0; idx < vm->arg.u32; idx++) - json_object_array_add(arr, uc_vm_stack_peek(vm, vm->arg.u32 - idx - 1)); + ucv_array_push(arr, uc_vm_stack_peek(vm, vm->arg.u32 - idx - 1)); for (idx = 0; idx < vm->arg.u32; idx++) uc_vm_stack_pop(vm); @@ -1452,79 +1494,81 @@ uc_vm_insn_parr(uc_vm *vm, enum insn_type insn) static void uc_vm_insn_marr(uc_vm *vm, enum insn_type insn) { - json_object *src = uc_vm_stack_pop(vm); - json_object *dst = uc_vm_stack_peek(vm, 0); + uc_value_t *src = uc_vm_stack_pop(vm); + uc_value_t *dst = uc_vm_stack_peek(vm, 0); size_t i; + char *s; - if (!json_object_is_type(src, json_type_array)) { - uc_vm_raise_exception(vm, EXCEPTION_TYPE, - "(%s) is not iterable", - json_object_to_json_string(src)); + if (ucv_type(src) != UC_ARRAY) { + s = ucv_to_string(vm, src); + uc_vm_raise_exception(vm, EXCEPTION_TYPE, "(%s) is not iterable", s); + ucv_put(src); + free(s); return; } - for (i = 0; i < json_object_array_length(src); i++) - json_object_array_add(dst, uc_value_get(json_object_array_get_idx(src, i))); + for (i = 0; i < ucv_array_length(src); i++) + ucv_array_push(dst, ucv_get(ucv_array_get(src, i))); - uc_value_put(src); + ucv_put(src); } static void uc_vm_insn_nobj(uc_vm *vm, enum insn_type insn) { - json_object *arr = xjs_new_object(); + uc_value_t *obj = ucv_object_new(vm); - uc_vm_stack_push(vm, arr); + uc_vm_stack_push(vm, obj); } static void uc_vm_insn_sobj(uc_vm *vm, enum insn_type insn) { - json_object *obj = uc_vm_stack_peek(vm, vm->arg.u32); + uc_value_t *obj = uc_vm_stack_peek(vm, vm->arg.u32); size_t idx; for (idx = 0; idx < vm->arg.u32; idx += 2) { - json_object_object_add(obj, - json_object_get_string(uc_vm_stack_peek(vm, vm->arg.u32 - idx - 1)), - uc_value_get(uc_vm_stack_peek(vm, vm->arg.u32 - idx - 2))); + ucv_object_add(obj, + ucv_string_get(uc_vm_stack_peek(vm, vm->arg.u32 - idx - 1)), + ucv_get(uc_vm_stack_peek(vm, vm->arg.u32 - idx - 2))); } for (idx = 0; idx < vm->arg.u32; idx++) - uc_value_put(uc_vm_stack_pop(vm)); + ucv_put(uc_vm_stack_pop(vm)); } static void uc_vm_insn_mobj(uc_vm *vm, enum insn_type insn) { - json_object *src = uc_vm_stack_pop(vm); - json_object *dst = uc_vm_stack_peek(vm, 0); - char *istr; + uc_value_t *src = uc_vm_stack_pop(vm); + uc_value_t *dst = uc_vm_stack_peek(vm, 0); size_t i; + char *s; - switch (json_object_get_type(src)) { - case json_type_object: + switch (ucv_type(src)) { + case UC_OBJECT: ; /* a label can only be part of a statement and a declaration is not a statement */ - json_object_object_foreach(src, k, v) - json_object_object_add(dst, k, uc_value_get(v)); + ucv_object_foreach(src, k, v) + ucv_object_add(dst, k, ucv_get(v)); - uc_value_put(src); + ucv_put(src); break; case json_type_array: - for (i = 0; i < json_object_array_length(src); i++) { - xasprintf(&istr, "%zu", i); - json_object_object_add(dst, istr, uc_value_get(json_object_array_get_idx(src, i))); - free(istr); + for (i = 0; i < ucv_array_length(src); i++) { + xasprintf(&s, "%zu", i); + ucv_object_add(dst, s, ucv_get(ucv_array_get(src, i))); + free(s); } - uc_value_put(src); + ucv_put(src); break; default: - uc_vm_raise_exception(vm, EXCEPTION_TYPE, - "Value (%s) is not iterable", - json_object_to_json_string(src)); + s = ucv_to_string(vm, src); + uc_vm_raise_exception(vm, EXCEPTION_TYPE, "Value (%s) is not iterable", s); + free(s); break; } @@ -1533,14 +1577,14 @@ uc_vm_insn_mobj(uc_vm *vm, enum insn_type insn) static void uc_vm_insn_arith(uc_vm *vm, enum insn_type insn) { - json_object *r2 = uc_vm_stack_pop(vm); - json_object *r1 = uc_vm_stack_pop(vm); - json_object *rv; + uc_value_t *r2 = uc_vm_stack_pop(vm); + uc_value_t *r1 = uc_vm_stack_pop(vm); + uc_value_t *rv; rv = uc_vm_value_arith(vm, insn, r1, r2); - uc_value_put(r1); - uc_value_put(r2); + ucv_put(r1); + ucv_put(r2); uc_vm_stack_push(vm, rv); } @@ -1548,23 +1592,23 @@ uc_vm_insn_arith(uc_vm *vm, enum insn_type insn) static void uc_vm_insn_plus_minus(uc_vm *vm, enum insn_type insn) { - struct json_object *v = uc_vm_stack_pop(vm); + uc_value_t *v = uc_vm_stack_pop(vm); bool is_sub = (insn == I_MINUS); - enum json_type t; + uc_type_t t; int64_t n; double d; t = uc_cast_number(v, &n, &d); - json_object_put(v); + ucv_put(v); switch (t) { - case json_type_int: - uc_vm_stack_push(vm, xjs_new_int64(is_sub ? -n : n)); + case UC_INTEGER: + uc_vm_stack_push(vm, ucv_int64_new(is_sub ? -n : n)); break; default: - uc_vm_stack_push(vm, uc_double_new(is_sub ? -d : d)); + uc_vm_stack_push(vm, ucv_double_new(is_sub ? -d : d)); break; } } @@ -1572,14 +1616,14 @@ uc_vm_insn_plus_minus(uc_vm *vm, enum insn_type insn) static void uc_vm_insn_bitop(uc_vm *vm, enum insn_type insn) { - json_object *r2 = uc_vm_stack_pop(vm); - json_object *r1 = uc_vm_stack_pop(vm); - json_object *rv; + uc_value_t *r2 = uc_vm_stack_pop(vm); + uc_value_t *r1 = uc_vm_stack_pop(vm); + uc_value_t *rv; rv = uc_vm_value_bitop(vm, insn, r1, r2); - uc_value_put(r1); - uc_value_put(r2); + ucv_put(r1); + ucv_put(r2); uc_vm_stack_push(vm, rv); } @@ -1587,23 +1631,23 @@ uc_vm_insn_bitop(uc_vm *vm, enum insn_type insn) static void uc_vm_insn_complement(uc_vm *vm, enum insn_type insn) { - struct json_object *v = uc_vm_stack_pop(vm); + uc_value_t *v = uc_vm_stack_pop(vm); int64_t n; double d; - if (uc_cast_number(v, &n, &d) == json_type_double) + if (uc_cast_number(v, &n, &d) == UC_DOUBLE) n = isnan(d) ? 0 : (int64_t)d; - json_object_put(v); + ucv_put(v); - uc_vm_stack_push(vm, xjs_new_int64(~n)); + uc_vm_stack_push(vm, ucv_int64_new(~n)); } static void uc_vm_insn_rel(uc_vm *vm, enum insn_type insn) { - json_object *r2 = uc_vm_stack_pop(vm); - json_object *r1 = uc_vm_stack_pop(vm); + uc_value_t *r2 = uc_vm_stack_pop(vm); + uc_value_t *r1 = uc_vm_stack_pop(vm); bool res = false; switch (insn) { @@ -1627,27 +1671,27 @@ uc_vm_insn_rel(uc_vm *vm, enum insn_type insn) break; } - uc_value_put(r1); - uc_value_put(r2); + ucv_put(r1); + ucv_put(r2); - uc_vm_stack_push(vm, xjs_new_boolean(res)); + uc_vm_stack_push(vm, ucv_boolean_new(res)); } static void uc_vm_insn_in(uc_vm *vm, enum insn_type insn) { - json_object *r2 = uc_vm_stack_pop(vm); - json_object *r1 = uc_vm_stack_pop(vm); - json_object *item; + uc_value_t *r2 = uc_vm_stack_pop(vm); + uc_value_t *r1 = uc_vm_stack_pop(vm); + uc_value_t *item; size_t arrlen, arridx; bool found = false; - const char *key; + char *key; - switch (json_object_get_type(r2)) { - case json_type_array: - for (arridx = 0, arrlen = json_object_array_length(r2); + switch (ucv_type(r2)) { + case UC_ARRAY: + for (arridx = 0, arrlen = ucv_array_length(r2); arridx < arrlen; arridx++) { - item = json_object_array_get_idx(r2, arridx); + item = ucv_array_get(r2, arridx); if (uc_cmp(TK_EQ, r1, item)) { found = true; @@ -1657,41 +1701,53 @@ uc_vm_insn_in(uc_vm *vm, enum insn_type insn) break; - case json_type_object: - key = r1 ? json_object_get_string(r1) : "null"; - found = json_object_object_get_ex(r2, key, NULL); + case UC_OBJECT: + if (ucv_type(r1) == UC_STRING) { + ucv_object_get(r2, ucv_string_get(r1), &found); + } + else { + key = ucv_to_string(vm, r1); + ucv_object_get(r2, key, &found); + free(key); + } + break; default: found = false; } - uc_value_put(r1); - uc_value_put(r2); + ucv_put(r1); + ucv_put(r2); - uc_vm_stack_push(vm, xjs_new_boolean(found)); + uc_vm_stack_push(vm, ucv_boolean_new(found)); } static void uc_vm_insn_equality(uc_vm *vm, enum insn_type insn) { - json_object *r2 = uc_vm_stack_pop(vm); - json_object *r1 = uc_vm_stack_pop(vm); - bool equal = uc_eq(r1, r2); + uc_value_t *r2 = uc_vm_stack_pop(vm); + uc_value_t *r1 = uc_vm_stack_pop(vm); + bool equal; + + if (ucv_is_scalar(r1) && ucv_is_scalar(r2)) + equal = ucv_equal(r1, r2); + else + equal = (r1 == r2); - uc_value_put(r1); - uc_value_put(r2); + ucv_put(r1); + ucv_put(r2); - uc_vm_stack_push(vm, xjs_new_boolean((insn == I_EQS) ? equal : !equal)); + uc_vm_stack_push(vm, ucv_boolean_new((insn == I_EQS) ? equal : !equal)); } static void uc_vm_insn_not(uc_vm *vm, enum insn_type insn) { - json_object *r1 = uc_vm_stack_pop(vm); + uc_value_t *r1 = uc_vm_stack_pop(vm); - uc_vm_stack_push(vm, xjs_new_boolean(!uc_val_is_truish(r1))); - uc_value_put(r1); + uc_vm_stack_push(vm, ucv_boolean_new(!uc_val_is_truish(r1))); + ucv_put(r1); } static void @@ -1718,7 +1774,7 @@ uc_vm_insn_jmpz(uc_vm *vm, enum insn_type insn) { uc_callframe *frame = uc_vm_current_frame(vm); uc_chunk *chunk = uc_vm_frame_chunk(frame); - json_object *v = uc_vm_stack_pop(vm); + uc_value_t *v = uc_vm_stack_pop(vm); int32_t addr = vm->arg.s32; /* ip already has been incremented */ @@ -1733,56 +1789,64 @@ uc_vm_insn_jmpz(uc_vm *vm, enum insn_type insn) if (!uc_val_is_truish(v)) frame->ip += addr; - uc_value_put(v); + ucv_put(v); } static void uc_vm_insn_next(uc_vm *vm, enum insn_type insn) { - json_object *k = uc_vm_stack_pop(vm); - json_object *v = uc_vm_stack_pop(vm); + uc_value_t *k = uc_vm_stack_pop(vm); + uc_value_t *v = uc_vm_stack_pop(vm); + void *end = (void *)~(uintptr_t)0; + uc_ressource_t *iterk; struct lh_entry *curr; - int64_t n; + uint64_t n; + + if (k != NULL && ucv_type(k) != UC_RESSOURCE) { + fprintf(stderr, "Invalid iterator value\n"); + abort(); + } + + if (k == NULL) { + k = ucv_ressource_new(NULL, NULL); + ((uc_ressource_t *)k)->type = UINT64_MAX; + } - switch (json_object_get_type(v)) { - case json_type_object: - curr = k ? json_object_get_userdata(k) : json_object_get_object(v)->head; + iterk = (uc_ressource_t *)k; - if (curr) { - if (!k) - k = xjs_new_string("[key]"); + switch (ucv_type(v)) { + case UC_OBJECT: + curr = iterk->data ? iterk->data : ((uc_object_t *)v)->table->head; - json_object_set_userdata(k, curr->next, NULL); + if (curr != NULL && curr != end) { + iterk->data = curr->next ? curr->next : end; - uc_vm_stack_push(vm, xjs_new_string(curr->k)); + uc_vm_stack_push(vm, ucv_string_new(curr->k)); if (insn == I_NEXTKV) - uc_vm_stack_push(vm, uc_value_get((json_object *)curr->v)); + uc_vm_stack_push(vm, ucv_get((uc_value_t *)curr->v)); uc_vm_stack_push(vm, k); - uc_value_put(v); + ucv_put(v); return; } break; - case json_type_array: - if (!k) - k = xjs_new_int64(0); - - n = json_object_get_int64(k); + case UC_ARRAY: + n = (uintptr_t)iterk->data; - if (json_object_is_type(k, json_type_int) && n < json_object_array_length(v)) { - json_object_int_inc(k, 1); + if (n < ucv_array_length(v)) { + iterk->data = (void *)(n + 1); if (insn == I_NEXTKV) - uc_vm_stack_push(vm, xjs_new_int64(n)); + uc_vm_stack_push(vm, ucv_uint64_new(n)); - uc_vm_stack_push(vm, uc_value_get(json_object_array_get_idx(v, n))); + uc_vm_stack_push(vm, ucv_get(ucv_array_get(v, n))); uc_vm_stack_push(vm, k); - uc_value_put(v); + ucv_put(v); return; } @@ -1799,87 +1863,83 @@ uc_vm_insn_next(uc_vm *vm, enum insn_type insn) if (insn == I_NEXTKV) uc_vm_stack_push(vm, NULL); - uc_value_put(k); - uc_value_put(v); + ucv_put(k); + ucv_put(v); } static void uc_vm_insn_close_upval(uc_vm *vm, enum insn_type insn) { uc_vm_close_upvals(vm, vm->stack.count - 1); - uc_value_put(uc_vm_stack_pop(vm)); + ucv_put(uc_vm_stack_pop(vm)); } static void uc_vm_insn_call(uc_vm *vm, enum insn_type insn) { - json_object *fno = uc_value_get(uc_vm_stack_peek(vm, vm->arg.u32 & 0xffff)); - json_object *ctx = NULL; + uc_value_t *fno = ucv_get(uc_vm_stack_peek(vm, vm->arg.u32 & 0xffff)); + uc_value_t *ctx = NULL; - if (!uc_object_is_type(fno, UC_OBJ_CLOSURE) || !uc_object_as_closure(fno)->is_arrow) + if (!ucv_is_arrowfn(fno)) ctx = NULL; else if (vm->callframes.count > 0) - ctx = uc_value_get(uc_vm_current_frame(vm)->ctx); + ctx = uc_vm_current_frame(vm)->ctx; - uc_vm_call_function(vm, ctx, fno, false, vm->arg.u32); + uc_vm_call_function(vm, ucv_get(ctx), fno, false, vm->arg.u32); } static void uc_vm_insn_mcall(uc_vm *vm, enum insn_type insn) { size_t key_slot = vm->stack.count - (vm->arg.u32 & 0xffff) - 1; - json_object *ctx = vm->stack.entries[key_slot - 1]; - json_object *key = vm->stack.entries[key_slot]; - json_object *fno = uc_getval(ctx, key); + uc_value_t *ctx = vm->stack.entries[key_slot - 1]; + uc_value_t *key = vm->stack.entries[key_slot]; + uc_value_t *fno = uc_getval(vm, ctx, key); uc_vm_stack_set(vm, key_slot, fno); /* arrow functions as method calls inherit the parent ctx */ - if (uc_object_is_type(fno, UC_OBJ_CLOSURE) && uc_object_as_closure(fno)->is_arrow) + if (ucv_is_arrowfn(fno)) ctx = uc_vm_current_frame(vm)->ctx; - uc_vm_call_function(vm, uc_value_get(ctx), uc_value_get(fno), true, vm->arg.u32); + uc_vm_call_function(vm, ucv_get(ctx), ucv_get(fno), true, vm->arg.u32); } static void uc_vm_insn_print(uc_vm *vm, enum insn_type insn) { - json_object *v = uc_vm_stack_pop(vm); - const char *p; - size_t len; + uc_value_t *v = uc_vm_stack_pop(vm); + char *p; - switch (json_object_get_type(v)) { - case json_type_object: - case json_type_array: - p = json_object_to_json_string_ext(v, JSON_C_TO_STRING_NOSLASHESCAPE|JSON_C_TO_STRING_SPACED); - len = strlen(p); + switch (ucv_type(v)) { + case UC_OBJECT: + case UC_ARRAY: + p = ucv_to_jsonstring(vm, v); + fwrite(p, 1, strlen(p), stdout); + free(p); break; - case json_type_string: - p = json_object_get_string(v); - len = json_object_get_string_len(v); + case UC_STRING: + fwrite(ucv_string_get(v), 1, ucv_string_length(v), stdout); break; - case json_type_null: - p = ""; - len = 0; + case UC_NULL: break; default: - p = json_object_get_string(v); - len = strlen(p); + p = ucv_to_string(vm, v); + fwrite(p, 1, strlen(p), stdout); + free(p); } - fwrite(p, 1, len, stdout); - - uc_value_put(v); + ucv_put(v); } -static json_object * +static uc_value_t * uc_vm_callframe_pop(uc_vm *vm) { uc_callframe *frame = uc_vm_current_frame(vm); - json_object *retval; + uc_value_t *retval; /* close upvalues */ uc_vm_close_upvals(vm, frame->stackframe); @@ -1891,18 +1951,18 @@ uc_vm_callframe_pop(uc_vm *vm) /* reset function stack frame */ while (vm->stack.count > frame->stackframe) - uc_value_put(uc_vm_stack_pop(vm)); + ucv_put(uc_vm_stack_pop(vm)); /* for method calls, release context as well */ if (frame->mcall) - uc_value_put(uc_vm_stack_pop(vm)); + ucv_put(uc_vm_stack_pop(vm)); /* release function */ - uc_value_put(frame->closure ? frame->closure->header.jso : NULL); - uc_value_put(frame->cfunction ? frame->cfunction->header.jso : NULL); + ucv_put((uc_value_t *)frame->closure); + ucv_put((uc_value_t *)frame->cfunction); /* release context */ - uc_value_put(frame->ctx); + ucv_put(frame->ctx); vm->callframes.count--; @@ -1920,9 +1980,9 @@ uc_vm_output_exception(uc_vm *vm) vm->exception.message); fprintf(stderr, "%s\n\n", - json_object_get_string( - json_object_object_get( - json_object_array_get_idx(vm->exception.stacktrace, 0), "context"))); + ucv_string_get( + ucv_object_get( + ucv_array_get(vm->exception.stacktrace, 0), "context", NULL))); } static uc_vm_status_t @@ -1930,7 +1990,7 @@ uc_vm_execute_chunk(uc_vm *vm) { uc_callframe *frame = uc_vm_current_frame(vm); uc_chunk *chunk = uc_vm_frame_chunk(frame); - json_object *retval; + uc_value_t *retval; enum insn_type insn; while (chunk) { @@ -1961,7 +2021,7 @@ uc_vm_execute_chunk(uc_vm *vm) break; case I_LTHIS: - uc_vm_stack_push(vm, uc_value_get(frame->ctx)); + uc_vm_stack_push(vm, ucv_get(frame->ctx)); break; case I_LVAR: @@ -2100,11 +2160,11 @@ uc_vm_execute_chunk(uc_vm *vm) break; case I_COPY: - uc_vm_stack_push(vm, uc_value_get(uc_vm_stack_peek(vm, vm->arg.u8))); + uc_vm_stack_push(vm, ucv_get(uc_vm_stack_peek(vm, vm->arg.u8))); break; case I_POP: - uc_value_put(uc_vm_stack_pop(vm)); + ucv_put(uc_vm_stack_pop(vm)); break; case I_CUPV: @@ -2127,7 +2187,7 @@ uc_vm_execute_chunk(uc_vm *vm) retval = uc_vm_callframe_pop(vm); if (vm->callframes.count == 0) { - uc_value_put(retval); + ucv_put(retval); return STATUS_OK; } @@ -2163,7 +2223,7 @@ uc_vm_execute_chunk(uc_vm *vm) return ERROR_RUNTIME; /* no exception handler in current function, pop callframe */ - uc_value_put(uc_vm_callframe_pop(vm)); + ucv_put(uc_vm_callframe_pop(vm)); /* resume execution at topmost remaining callframe */ frame = uc_vector_last(&vm->callframes); @@ -2176,25 +2236,25 @@ uc_vm_execute_chunk(uc_vm *vm) } static uc_vm_status_t -uc_vm_preload(uc_vm *vm, json_object *modules) +uc_vm_preload(uc_vm *vm, uc_value_t *modules) { - json_object *requirefn, *module, *name; + uc_value_t *requirefn, *module, *name; uc_exception_type_t ex; size_t i; - if (!json_object_is_type(modules, json_type_array)) + if (ucv_type(modules) != UC_ARRAY) return STATUS_OK; - requirefn = uc_prototype_lookup(vm->globals, "require"); + requirefn = ucv_property_get(vm->globals, "require"); - if (!uc_object_is_type(requirefn, UC_OBJ_CFUNCTION)) + if (ucv_type(requirefn) != UC_CFUNCTION) return STATUS_OK; - for (i = 0; i < json_object_array_length(modules); i++) { - name = json_object_array_get_idx(modules, i); + for (i = 0; i < ucv_array_length(modules); i++) { + name = ucv_array_get(modules, i); - uc_vm_stack_push(vm, uc_value_get(requirefn)); - uc_vm_stack_push(vm, uc_value_get(name)); + uc_vm_stack_push(vm, ucv_get(requirefn)); + uc_vm_stack_push(vm, ucv_get(name)); ex = uc_vm_call(vm, false, 1); @@ -2203,21 +2263,22 @@ uc_vm_preload(uc_vm *vm, json_object *modules) module = uc_vm_stack_pop(vm); - uc_value_put(uc_setval(vm->globals->header.jso, name, module)); + ucv_put(uc_setval(vm, vm->globals, name, module)); } return STATUS_OK; } uc_vm_status_t -uc_vm_execute(uc_vm *vm, uc_function *fn, uc_prototype *globals, json_object *modules) +uc_vm_execute(uc_vm *vm, uc_function_t *fn, uc_value_t *globals, uc_value_t *modules) { - uc_closure *closure = uc_closure_new(fn, false); + uc_closure_t *closure = (uc_closure_t *)ucv_closure_new(vm, fn, false); uc_callframe *frame; + uc_stringbuf_t *buf; uc_vm_status_t rv; vm->globals = globals; - uc_value_get(globals ? globals->header.jso : NULL); + ucv_get(globals); uc_vector_grow(&vm->callframes); @@ -2227,14 +2288,12 @@ uc_vm_execute(uc_vm *vm, uc_function *fn, uc_prototype *globals, json_object *mo frame->ip = uc_vm_frame_chunk(frame)->entries; if (vm->trace) { - size_t msglen = 0; - char *msg = NULL; + buf = xprintbuf_new(); - format_source_context(&msg, &msglen, - fn->source, 0, true); + format_source_context(buf, fn->source, 0, true); - fprintf(stderr, "%s", msg); - free(msg); + fwrite(buf->buf, 1, printbuf_length(buf), stderr); + printbuf_free(buf); uc_vm_frame_dump(vm, frame); } @@ -2249,7 +2308,7 @@ uc_vm_execute(uc_vm *vm, uc_function *fn, uc_prototype *globals, json_object *mo else rv = uc_vm_execute_chunk(vm); - uc_value_put(vm->globals->header.jso); + ucv_put(vm->globals); vm->globals = NULL; return rv; @@ -2258,11 +2317,11 @@ uc_vm_execute(uc_vm *vm, uc_function *fn, uc_prototype *globals, json_object *mo uc_exception_type_t uc_vm_call(uc_vm *vm, bool mcall, size_t nargs) { - json_object *ctx = mcall ? uc_value_get(uc_vm_stack_peek(vm, nargs - 1)) : NULL; - json_object *fno = uc_value_get(uc_vm_stack_peek(vm, nargs)); + uc_value_t *ctx = mcall ? ucv_get(uc_vm_stack_peek(vm, nargs + 1)) : NULL; + uc_value_t *fno = ucv_get(uc_vm_stack_peek(vm, nargs)); if (uc_vm_call_function(vm, ctx, fno, mcall, nargs & 0xffff)) { - if (!uc_object_is_type(fno, UC_OBJ_CFUNCTION)) + if (ucv_type(fno) != UC_CFUNCTION) uc_vm_execute_chunk(vm); } @@ -21,7 +21,6 @@ #include <stdarg.h> #include "chunk.h" -#include "object.h" #include "util.h" #include "lexer.h" @@ -102,7 +101,6 @@ typedef struct { int8_t stack_pop; int8_t stack_push; int8_t operand_bytes; - bool operand_is_skip; } uc_insn_definition; typedef enum { @@ -116,30 +114,31 @@ typedef enum { typedef struct { uc_exception_type_t type; - json_object *stacktrace; + uc_value_t *stacktrace; char *message; } uc_exception; typedef struct { uint8_t *ip; - uc_closure *closure; - uc_cfunction *cfunction; + uc_closure_t *closure; + uc_cfunction_t *cfunction; size_t stackframe; - json_object *ctx; + uc_value_t *ctx; bool mcall; } uc_callframe; uc_declare_vector(uc_callframes, uc_callframe); -uc_declare_vector(uc_stack, json_object *); +uc_declare_vector(uc_stack, uc_value_t *); typedef struct uc_vm { uc_stack stack; uc_exception exception; uc_callframes callframes; - uc_upvalref *open_upvals; + uc_upvalref_t *open_upvals; uc_parse_config *config; - uc_prototype *globals; + uc_value_t *globals; uc_source *sources; + uc_weakref_t values; union { uint32_t u32; int32_t s32; @@ -163,15 +162,15 @@ extern uint32_t insns[__I_MAX]; void uc_vm_init(uc_vm *vm, uc_parse_config *config); void uc_vm_free(uc_vm *vm); -void uc_vm_stack_push(uc_vm *vm, json_object *value); -json_object *uc_vm_stack_pop(uc_vm *vm); -json_object *uc_vm_stack_peek(uc_vm *vm, size_t offset); +void uc_vm_stack_push(uc_vm *vm, uc_value_t *value); +uc_value_t *uc_vm_stack_pop(uc_vm *vm); +uc_value_t *uc_vm_stack_peek(uc_vm *vm, size_t offset); uc_exception_type_t uc_vm_call(uc_vm *vm, bool mcall, size_t nargs); void __attribute__((format(printf, 3, 0))) uc_vm_raise_exception(uc_vm *vm, uc_exception_type_t type, const char *fmt, ...); -uc_vm_status_t uc_vm_execute(uc_vm *vm, uc_function *fn, uc_prototype *globals, json_object *modules); +uc_vm_status_t uc_vm_execute(uc_vm *vm, uc_function_t *fn, uc_value_t *globals, uc_value_t *modules); #endif /* __VM_H_ */ |