diff options
author | Jo-Philipp Wich <jo@mein.io> | 2021-04-27 12:43:38 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-04-27 12:43:38 +0200 |
commit | 8469c4b1be228f42c46f08852f028f7801b93cc9 (patch) | |
tree | f61121e8f89e39787a960e621fc8492e57fc4bc0 | |
parent | f360350bd874aeec0806c8df02c7a20a54c44406 (diff) | |
parent | 64eec7f90e945696572ee076b75d1f35e8f2248a (diff) |
Merge pull request #5 from jow-/new-type-system
New type system
-rw-r--r-- | .github/workflows/openwrt-ci.yml | 48 | ||||
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | .gitlab-ci.yml | 7 | ||||
-rw-r--r-- | CMakeLists.txt | 51 | ||||
-rw-r--r-- | chunk.c | 11 | ||||
-rw-r--r-- | chunk.h | 34 | ||||
-rw-r--r-- | compiler.c | 316 | ||||
-rw-r--r-- | compiler.h | 12 | ||||
-rw-r--r-- | lexer.c | 250 | ||||
-rw-r--r-- | lexer.h | 11 | ||||
-rw-r--r-- | lib.c | 1488 | ||||
-rw-r--r-- | lib.h | 151 | ||||
-rw-r--r-- | lib/fs.c | 313 | ||||
-rw-r--r-- | lib/math.c | 66 | ||||
-rw-r--r-- | lib/ubus.c | 127 | ||||
-rw-r--r-- | lib/uci.c | 445 | ||||
-rw-r--r-- | main.c | 96 | ||||
-rw-r--r-- | module.h | 15 | ||||
-rw-r--r-- | object.c | 493 | ||||
-rw-r--r-- | object.h | 201 | ||||
-rw-r--r-- | source.h | 10 | ||||
-rw-r--r-- | tests/CMakeLists.txt | 6 | ||||
-rw-r--r-- | tests/cram/CMakeLists.txt | 27 | ||||
-rw-r--r-- | tests/cram/test_basic.t | 59 | ||||
-rw-r--r-- | tests/custom/00_syntax/00_single_line_comments (renamed from tests/00_syntax/00_single_line_comments) | 0 | ||||
-rw-r--r-- | tests/custom/00_syntax/01_unterminated_comment (renamed from tests/00_syntax/01_unterminated_comment) | 0 | ||||
-rw-r--r-- | tests/custom/00_syntax/02_multi_line_comments (renamed from tests/00_syntax/02_multi_line_comments) | 0 | ||||
-rw-r--r-- | tests/custom/00_syntax/03_expression_blocks (renamed from tests/00_syntax/03_expression_blocks) | 0 | ||||
-rw-r--r-- | tests/custom/00_syntax/04_statement_blocks (renamed from tests/00_syntax/04_statement_blocks) | 0 | ||||
-rw-r--r-- | tests/custom/00_syntax/05_block_nesting (renamed from tests/00_syntax/05_block_nesting) | 0 | ||||
-rw-r--r-- | tests/custom/00_syntax/06_open_statement_block (renamed from tests/00_syntax/06_open_statement_block) | 0 | ||||
-rw-r--r-- | tests/custom/00_syntax/07_embedded_single_line_comments (renamed from tests/00_syntax/07_embedded_single_line_comments) | 0 | ||||
-rw-r--r-- | tests/custom/00_syntax/08_embedded_multi_line_comments (renamed from tests/00_syntax/08_embedded_multi_line_comments) | 0 | ||||
-rw-r--r-- | tests/custom/00_syntax/09_string_literals (renamed from tests/00_syntax/09_string_literals) | 0 | ||||
-rw-r--r-- | tests/custom/00_syntax/10_numeric_literals (renamed from tests/00_syntax/10_numeric_literals) | 0 | ||||
-rw-r--r-- | tests/custom/00_syntax/11_misc_literals (renamed from tests/00_syntax/11_misc_literals) | 0 | ||||
-rw-r--r-- | tests/custom/00_syntax/12_block_whitespace_control (renamed from tests/00_syntax/12_block_whitespace_control) | 0 | ||||
-rw-r--r-- | tests/custom/00_syntax/13_object_literals (renamed from tests/00_syntax/13_object_literals) | 0 | ||||
-rw-r--r-- | tests/custom/00_syntax/14_array_literals (renamed from tests/00_syntax/14_array_literals) | 0 | ||||
-rw-r--r-- | tests/custom/00_syntax/15_function_declarations (renamed from tests/00_syntax/15_function_declarations) | 0 | ||||
-rw-r--r-- | tests/custom/00_syntax/16_for_loop (renamed from tests/00_syntax/16_for_loop) | 0 | ||||
-rw-r--r-- | tests/custom/00_syntax/17_while_loop (renamed from tests/00_syntax/17_while_loop) | 0 | ||||
-rw-r--r-- | tests/custom/00_syntax/18_if_condition (renamed from tests/00_syntax/18_if_condition) | 0 | ||||
-rw-r--r-- | tests/custom/00_syntax/19_arrow_functions (renamed from tests/00_syntax/19_arrow_functions) | 0 | ||||
-rw-r--r-- | tests/custom/00_syntax/20_list_expressions (renamed from tests/00_syntax/20_list_expressions) | 0 | ||||
-rw-r--r-- | tests/custom/00_syntax/21_regex_literals (renamed from tests/00_syntax/21_regex_literals) | 2 | ||||
-rw-r--r-- | tests/custom/01_arithmetic/00_value_conversion (renamed from tests/01_arithmetic/00_value_conversion) | 0 | ||||
-rw-r--r-- | tests/custom/01_arithmetic/01_division (renamed from tests/01_arithmetic/01_division) | 0 | ||||
-rw-r--r-- | tests/custom/01_arithmetic/02_modulo (renamed from tests/01_arithmetic/02_modulo) | 0 | ||||
-rw-r--r-- | tests/custom/01_arithmetic/03_bitwise (renamed from tests/01_arithmetic/03_bitwise) | 0 | ||||
-rw-r--r-- | tests/custom/01_arithmetic/04_inc_dec (renamed from tests/01_arithmetic/04_inc_dec) | 0 | ||||
-rw-r--r-- | tests/custom/02_runtime/00_scoping (renamed from tests/02_runtime/00_scoping) | 0 | ||||
-rw-r--r-- | tests/custom/02_runtime/01_break_continue (renamed from tests/02_runtime/01_break_continue) | 0 | ||||
-rw-r--r-- | tests/custom/02_runtime/02_this (renamed from tests/02_runtime/02_this) | 0 | ||||
-rw-r--r-- | tests/custom/02_runtime/03_try_catch (renamed from tests/02_runtime/03_try_catch) | 0 | ||||
-rw-r--r-- | tests/custom/02_runtime/04_switch_case (renamed from tests/02_runtime/04_switch_case) | 0 | ||||
-rw-r--r-- | tests/custom/02_runtime/05_closure_scope (renamed from tests/02_runtime/05_closure_scope) | 0 | ||||
-rw-r--r-- | tests/custom/02_runtime/06_recursion (renamed from tests/02_runtime/06_recursion) | 0 | ||||
-rw-r--r-- | tests/custom/03_bugs/01_try_catch_stack_mismatch (renamed from tests/03_bugs/01_try_catch_stack_mismatch) | 0 | ||||
-rw-r--r-- | tests/custom/03_bugs/02_array_pop_use_after_free (renamed from tests/03_bugs/02_array_pop_use_after_free) | 0 | ||||
-rw-r--r-- | tests/custom/03_bugs/03_switch_fallthrough_miscompilation (renamed from tests/03_bugs/03_switch_fallthrough_miscompilation) | 0 | ||||
-rw-r--r-- | tests/custom/03_bugs/04_property_set_abort (renamed from tests/03_bugs/04_property_set_abort) | 0 | ||||
-rw-r--r-- | tests/custom/03_bugs/05_duplicate_ressource_type (renamed from tests/03_bugs/05_duplicate_ressource_type) | 0 | ||||
-rw-r--r-- | tests/custom/03_bugs/06_lexer_escape_at_boundary (renamed from tests/03_bugs/06_lexer_escape_at_boundary) | 0 | ||||
-rw-r--r-- | tests/custom/03_bugs/07_lexer_overlong_lines (renamed from tests/03_bugs/07_lexer_overlong_lines) | 0 | ||||
-rw-r--r-- | tests/custom/03_bugs/08_compiler_arrow_fn_expressions (renamed from tests/03_bugs/08_compiler_arrow_fn_expressions) | 0 | ||||
-rw-r--r-- | tests/custom/03_bugs/09_reject_invalid_array_indexes (renamed from tests/03_bugs/09_reject_invalid_array_indexes) | 0 | ||||
-rw-r--r-- | tests/custom/03_bugs/10_break_stack_mismatch (renamed from tests/03_bugs/10_break_stack_mismatch) | 0 | ||||
-rw-r--r-- | tests/custom/03_bugs/11_switch_stack_mismatch (renamed from tests/03_bugs/11_switch_stack_mismatch) | 0 | ||||
-rw-r--r-- | tests/custom/03_bugs/12_altblock_stack_mismatch (renamed from tests/03_bugs/12_altblock_stack_mismatch) | 0 | ||||
-rw-r--r-- | tests/custom/CMakeLists.txt | 22 | ||||
-rwxr-xr-x | tests/custom/run_tests.sh (renamed from run_tests.sh) | 13 | ||||
-rw-r--r-- | tests/fuzz/CMakeLists.txt | 16 | ||||
-rw-r--r-- | tests/fuzz/corpus/.keep | 0 | ||||
-rw-r--r-- | tests/fuzz/test-fuzz.c | 9 | ||||
-rw-r--r-- | types.c | 1809 | ||||
-rw-r--r-- | types.h | 428 | ||||
-rw-r--r-- | util.h | 13 | ||||
-rw-r--r-- | value.c | 355 | ||||
-rw-r--r-- | value.h | 40 | ||||
-rw-r--r-- | vm.c | 1056 | ||||
-rw-r--r-- | vm.h | 58 |
82 files changed, 4794 insertions, 3265 deletions
diff --git a/.github/workflows/openwrt-ci.yml b/.github/workflows/openwrt-ci.yml new file mode 100644 index 0000000..08a9ccb --- /dev/null +++ b/.github/workflows/openwrt-ci.yml @@ -0,0 +1,48 @@ +name: OpenWrt CI testing + +on: [ push, pull_request ] +env: + CI_ENABLE_UNIT_TESTING: 1 + CI_TARGET_BUILD_DEPENDS: ubus uci + +jobs: + native_testing: + name: Various native checks + runs-on: ubuntu-20.04 + + steps: + - uses: actions/checkout@v2 + + - uses: ynezz/gh-actions-openwrt-ci-native@v0.0.1 + + - name: Upload build artifacts + uses: actions/upload-artifact@v2 + if: failure() + with: + name: native-build-artifacts + if-no-files-found: ignore + path: | + build/scan + tests/cram/**/*.t.err + + sdk_build: + name: Build with OpenWrt ${{ matrix.sdk_platform }} SDK (out of tree) + runs-on: ubuntu-20.04 + + strategy: + fail-fast: false + matrix: + sdk_platform: + - ath79-generic + - imx6-generic + - malta-be + - mvebu-cortexa53 + + steps: + - uses: actions/checkout@v2 + + - name: Out of tree build with OpenWrt ${{ matrix.sdk_platform }} SDK + uses: ynezz/gh-actions-openwrt-ci-sdk@v0.0.1 + env: + CI_TARGET_SDK_RELEASE: master + CI_TARGET_SDK_IMAGE: ${{ matrix.sdk_platform }} @@ -8,3 +8,4 @@ parser.out contrib/lemon utpl lib/*.so +tests/cram/*.t.err diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..5ec04e4 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,7 @@ +variables: + CI_ENABLE_UNIT_TESTING: 1 + CI_TARGET_BUILD_DEPENDS: ubus uci + +include: + - remote: https://gitlab.com/ynezz/openwrt-ci/raw/master/openwrt-ci/gitlab/main.yml + - remote: https://gitlab.com/ynezz/openwrt-ci/raw/master/openwrt-ci/gitlab/pipeline.yml diff --git a/CMakeLists.txt b/CMakeLists.txt index 2046392..0d5fe54 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,9 +1,15 @@ -cmake_minimum_required(VERSION 2.6) +cmake_minimum_required(VERSION 3.17) include(CheckFunctionExists) include(CheckSymbolExists) PROJECT(ucode C) -ADD_DEFINITIONS(-Os -Wall -Werror --std=gnu99 -Wmissing-declarations -Wno-error=unused-variable -ffunction-sections -D_GNU_SOURCE) +ADD_DEFINITIONS(-Os -Wall -Werror --std=gnu99 -ffunction-sections -D_GNU_SOURCE) + +IF(CMAKE_C_COMPILER_VERSION VERSION_GREATER 6) + ADD_DEFINITIONS(-Wextra -Werror=implicit-function-declaration) + ADD_DEFINITIONS(-Wformat -Werror=format-security -Werror=format-nonliteral) +ENDIF() +ADD_DEFINITIONS(-Wmissing-declarations -Wno-error=unused-variable -Wno-unused-parameter) OPTION(FS_SUPPORT "Filesystem plugin support" ON) OPTION(MATH_SUPPORT "Math plugin support" ON) @@ -17,7 +23,7 @@ IF(NOT APPLE) SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "-Wl,--gc-sections") ENDIF() -find_library(json NAMES json-c json) +FIND_LIBRARY(json NAMES json-c json) IF(DEBUG) ADD_DEFINITIONS(-DDEBUG -g3 -O0) @@ -32,7 +38,9 @@ IF(JSONC_FOUND) INCLUDE_DIRECTORIES(${JSONC_INCLUDE_DIRS}) ENDIF() -ADD_EXECUTABLE(ucode 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) @@ -57,13 +65,13 @@ SET(LIBRARIES "") IF(FS_SUPPORT) SET(LIBRARIES ${LIBRARIES} fs_lib) ADD_LIBRARY(fs_lib MODULE lib/fs.c) - SET_TARGET_PROPERTIES(fs_lib PROPERTIES OUTPUT_NAME lib/fs PREFIX "") + SET_TARGET_PROPERTIES(fs_lib PROPERTIES OUTPUT_NAME fs PREFIX "") ENDIF() IF(MATH_SUPPORT) SET(LIBRARIES ${LIBRARIES} math_lib) ADD_LIBRARY(math_lib MODULE lib/math.c) - SET_TARGET_PROPERTIES(math_lib PROPERTIES OUTPUT_NAME lib/math PREFIX "") + SET_TARGET_PROPERTIES(math_lib PROPERTIES OUTPUT_NAME math PREFIX "") CHECK_FUNCTION_EXISTS(ceil CEIL_FUNCTION_EXISTS) IF (NOT CEIL_FUNCTION_EXISTS) TARGET_LINK_LIBRARIES(math_lib m) @@ -71,17 +79,40 @@ IF(MATH_SUPPORT) ENDIF() IF(UBUS_SUPPORT) + FIND_LIBRARY(ubus NAMES ubus) + FIND_LIBRARY(blobmsg_json NAMES blobmsg_json) + FIND_PATH(ubus_include_dir NAMES libubus.h) + INCLUDE_DIRECTORIES(${ubus_include_dir}) SET(LIBRARIES ${LIBRARIES} ubus_lib) ADD_LIBRARY(ubus_lib MODULE lib/ubus.c) - SET_TARGET_PROPERTIES(ubus_lib PROPERTIES OUTPUT_NAME lib/ubus PREFIX "") - TARGET_LINK_LIBRARIES(ubus_lib ubus blobmsg_json) + SET_TARGET_PROPERTIES(ubus_lib PROPERTIES OUTPUT_NAME ubus PREFIX "") + TARGET_LINK_LIBRARIES(ubus_lib ${ubus} ${blobmsg_json}) ENDIF() IF(UCI_SUPPORT) + FIND_LIBRARY(uci NAMES uci) + FIND_LIBRARY(ubox NAMES ubox) + FIND_PATH(uci_include_dir uci.h) + INCLUDE_DIRECTORIES(${uci_include_dir}) SET(LIBRARIES ${LIBRARIES} uci_lib) ADD_LIBRARY(uci_lib MODULE lib/uci.c) - SET_TARGET_PROPERTIES(uci_lib PROPERTIES OUTPUT_NAME lib/uci PREFIX "") - TARGET_LINK_LIBRARIES(uci_lib uci) + SET_TARGET_PROPERTIES(uci_lib PROPERTIES OUTPUT_NAME uci PREFIX "") + TARGET_LINK_LIBRARIES(uci_lib ${uci} ${ubox}) +ENDIF() + +IF(UNIT_TESTING) + ENABLE_TESTING() + ADD_DEFINITIONS(-DUNIT_TESTING) + ADD_SUBDIRECTORY(tests) + LIST(APPEND CMAKE_CTEST_ARGUMENTS "--output-on-failure") + + IF(CMAKE_C_COMPILER_ID STREQUAL "Clang") + ADD_EXECUTABLE(ucode-san ${UCODE_SOURCES}) + SET_PROPERTY(TARGET ucode-san PROPERTY ENABLE_EXPORTS 1) + TARGET_LINK_LIBRARIES(ucode-san ${json}) + TARGET_COMPILE_OPTIONS(ucode-san PRIVATE -g -fno-omit-frame-pointer -fsanitize=undefined,address,leak -fno-sanitize-recover=all) + TARGET_LINK_OPTIONS(ucode-san PRIVATE -fsanitize=undefined,address,leak) + ENDIF() ENDIF() INSTALL(TARGETS ucode RUNTIME DESTINATION bin) @@ -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)); @@ -22,42 +22,18 @@ #include "value.h" #include "util.h" - - -typedef struct { - size_t from, to, target, slot; -} uc_ehrange; - -typedef struct { - size_t from, to, slot, nameidx; -} uc_varrange; - -uc_declare_vector(uc_ehranges, uc_ehrange); -uc_declare_vector(uc_variables, uc_varrange); -uc_declare_vector(uc_offsetinfo, uint8_t); - -typedef struct { - size_t count; - uint8_t *entries; - uc_value_list constants; - uc_ehranges ehranges; - struct { - uc_variables variables; - uc_value_list varnames; - uc_offsetinfo offsets; - } debuginfo; -} uc_chunk; +#include "types.h" void uc_chunk_init(uc_chunk *chunk); void uc_chunk_free(uc_chunk *chunk); size_t uc_chunk_add(uc_chunk *chunk, uint8_t byte, size_t line); -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); +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; } } @@ -472,7 +468,12 @@ uc_compiler_emit_s32(uc_compiler *compiler, size_t srcpos, int32_t n) { uc_chunk *chunk = uc_compiler_current_chunk(compiler); size_t lineoff = uc_compiler_set_srcpos(compiler, srcpos); - uint32_t v = n + 0x7fffffff; + uint32_t v; + + if (n <= 0) + v = n + 0x7fffffff; + else + v = (uint32_t)n + 0x7fffffff; uc_chunk_add(chunk, v / 0x1000000, lineoff); uc_chunk_add(chunk, (v / 0x10000) % 0x100, 0); @@ -505,7 +506,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 +518,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); @@ -559,9 +560,9 @@ uc_compiler_get_jmpaddr(uc_compiler *compiler, size_t off) assert(off + 4 < chunk->count); return ( - chunk->entries[off + 1] * 0x1000000 + - chunk->entries[off + 2] * 0x10000 + - chunk->entries[off + 3] * 0x100 + + chunk->entries[off + 1] * 0x1000000UL + + chunk->entries[off + 2] * 0x10000UL + + chunk->entries[off + 3] * 0x100UL + chunk->entries[off + 4] ) - 0x7fffffff; } @@ -581,7 +582,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 +601,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 +612,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 +641,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 +651,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 +660,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 +676,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 +700,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 +720,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 +750,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 +772,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 +780,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 +990,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 +1051,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 +1067,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); - uc_compiler fncompiler = {}; + bool array = (ucv_type(args) == UC_ARRAY); + uc_compiler fncompiler = { 0 }; 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 +1081,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 +1114,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 +1129,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 +1141,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 +1168,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 +1177,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 +1234,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,14 +1281,14 @@ 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 uc_compiler_compile_call(uc_compiler *compiler, bool assignable) { uc_chunk *chunk = uc_compiler_current_chunk(compiler); - uc_jmplist spreads = {}; + uc_jmplist spreads = { 0 }; enum insn_type type; size_t i, nargs = 0; @@ -1358,20 +1360,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 +1388,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 +1408,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 @@ -1425,18 +1427,18 @@ uc_compiler_compile_delimitted_block(uc_compiler *compiler, uc_tokentype_t endty static void uc_compiler_compile_function(uc_compiler *compiler, bool assignable) { - uc_compiler fncompiler = {}; - json_object *name = NULL; + uc_compiler fncompiler = { 0 }; + 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 +1450,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 +1467,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 +1508,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 +1520,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 +1566,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 +1721,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 +1730,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 */ @@ -1757,7 +1760,6 @@ uc_compiler_compile_object(uc_compiler *compiler, bool assignable) if (len > 0) { uc_compiler_emit_insn(compiler, compiler->parser->prev.pos, I_SOBJ); uc_compiler_emit_u32(compiler, 0, len); - len = 0; } /* set initial size hint */ @@ -1766,7 +1768,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); @@ -1820,7 +1822,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; @@ -1839,7 +1841,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)) @@ -1894,7 +1896,7 @@ uc_compiler_compile_if(uc_compiler *compiler) uc_chunk *chunk = uc_compiler_current_chunk(compiler); size_t jmpz_off, jmp_off, i; bool expect_endif = false; - uc_jmplist elifs = {}; + uc_jmplist elifs = { 0 }; uc_tokentype_t type; /* parse & compile condition expression */ @@ -1999,7 +2001,7 @@ uc_compiler_compile_while(uc_compiler *compiler) { uc_chunk *chunk = uc_compiler_current_chunk(compiler); size_t cond_off, jmpz_off, end_off; - uc_patchlist p = {}; + uc_patchlist p = { 0 }; p.parent = compiler->patchlist; compiler->patchlist = &p; @@ -2047,7 +2049,7 @@ uc_compiler_compile_for_in(uc_compiler *compiler, bool local, uc_token *kvar, uc { uc_chunk *chunk = uc_compiler_current_chunk(compiler); size_t skip_jmp, test_jmp, key_slot, val_slot; - uc_patchlist p = {}; + uc_patchlist p = { 0 }; p.parent = compiler->patchlist; compiler->patchlist = &p; @@ -2063,10 +2065,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 */ @@ -2110,12 +2112,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 */ @@ -2157,7 +2159,7 @@ uc_compiler_compile_for_count(uc_compiler *compiler, bool local, uc_token *var) { uc_chunk *chunk = uc_compiler_current_chunk(compiler); size_t test_off = 0, incr_off, skip_off, cond_off = 0; - uc_patchlist p = {}; + uc_patchlist p = { 0 }; p.parent = compiler->patchlist; compiler->patchlist = &p; @@ -2166,14 +2168,14 @@ uc_compiler_compile_for_count(uc_compiler *compiler, bool local, uc_token *var) /* Initializer ---------------------------------------------------------- */ - /* 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); - - /* If we parsed at least on label, try continue parsing as variable + /* If we parsed at least one label, try continue parsing as variable * expression... */ if (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->uv); + uc_compiler_compile_labelexpr(compiler, true); uc_compiler_emit_insn(compiler, 0, I_POP); @@ -2257,7 +2259,7 @@ uc_compiler_compile_for_count(uc_compiler *compiler, bool local, uc_token *var) static void uc_compiler_compile_for(uc_compiler *compiler) { - uc_token keyvar = {}, valvar = {}; + uc_token keyvar = { 0 }, valvar = { 0 }; bool local; uc_compiler_parse_consume(compiler, TK_LPAREN); @@ -2268,19 +2270,15 @@ uc_compiler_compile_for(uc_compiler *compiler) local = uc_compiler_parse_match(compiler, TK_LOCAL); - if (local && !uc_compiler_parse_check(compiler, TK_LABEL)) - uc_compiler_syntax_error(compiler, compiler->parser->curr.pos, - "Expecting label after 'local'"); - 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 */ @@ -2291,17 +2289,23 @@ uc_compiler_compile_for(uc_compiler *compiler) goto out; } } + else if (local) { + uc_compiler_syntax_error(compiler, compiler->parser->curr.pos, + "Expecting label after 'local'"); + + goto out; + } /* * The previous expression ruled out a for-in loop, so continue parsing * 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 @@ -2310,8 +2314,8 @@ uc_compiler_compile_switch(uc_compiler *compiler) size_t i, test_jmp, skip_jmp, next_jmp, value_slot, default_off = 0; uc_chunk *chunk = uc_compiler_current_chunk(compiler); uc_locals *locals = &compiler->locals; - uc_jmplist cases = {}; - uc_patchlist p = {}; + uc_jmplist cases = { 0 }; + uc_patchlist p = { 0 }; p.parent = compiler->patchlist; compiler->patchlist = &p; @@ -2335,6 +2339,7 @@ uc_compiler_compile_switch(uc_compiler *compiler) /* handle `default:` */ if (uc_compiler_parse_match(compiler, TK_DEFAULT)) { if (default_off) { + uc_vector_clear(&cases); uc_compiler_syntax_error(compiler, compiler->parser->prev.pos, "more than one switch default case"); @@ -2521,7 +2526,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); @@ -2563,7 +2568,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); @@ -2612,7 +2617,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); } @@ -2703,12 +2708,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); @@ -2720,8 +2725,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,22 +32,22 @@ #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; - }; + } u; }; struct token { - int type; + unsigned type; union { uint32_t patn; char pat[4]; - }; - int plen; + } u; + unsigned plen; uc_token *(*parse)(uc_lexer *, bool); }; @@ -65,103 +65,103 @@ static uc_token *parse_number(uc_lexer *, bool); static uc_token *parse_label(uc_lexer *, bool); static const struct token tokens[] = { - { TK_ASLEFT, { .pat = "<<=" }, 3 }, - { TK_ASRIGHT, { .pat = ">>=" }, 3 }, - { TK_LEXP, { .pat = "{{-" }, 3 }, - { TK_REXP, { .pat = "-}}" }, 3 }, - { TK_LSTM, { .pat = "{%+" }, 3 }, - { TK_LSTM, { .pat = "{%-" }, 3 }, - { TK_RSTM, { .pat = "-%}" }, 3 }, - { TK_EQS, { .pat = "===" }, 3 }, - { TK_NES, { .pat = "!==" }, 3 }, - { TK_ELLIP, { .pat = "..." }, 3 }, - { TK_AND, { .pat = "&&" }, 2 }, - { TK_ASADD, { .pat = "+=" }, 2 }, - { TK_ASBAND, { .pat = "&=" }, 2 }, - { TK_ASBOR, { .pat = "|=" }, 2 }, - { TK_ASBXOR, { .pat = "^=" }, 2 }, - //{ TK_ASDIV, { .pat = "/=" }, 2 }, - { TK_ASMOD, { .pat = "%=" }, 2 }, - { TK_ASMUL, { .pat = "*=" }, 2 }, - { TK_ASSUB, { .pat = "-=" }, 2 }, - { TK_DEC, { .pat = "--" }, 2 }, - { TK_INC, { .pat = "++" }, 2 }, - { TK_EQ, { .pat = "==" }, 2 }, - { TK_NE, { .pat = "!=" }, 2 }, - { TK_LE, { .pat = "<=" }, 2 }, - { TK_GE, { .pat = ">=" }, 2 }, - { TK_LSHIFT, { .pat = "<<" }, 2 }, - { TK_RSHIFT, { .pat = ">>" }, 2 }, + { TK_ASLEFT, { .pat = "<<=" }, 3, NULL }, + { TK_ASRIGHT, { .pat = ">>=" }, 3, NULL }, + { TK_LEXP, { .pat = "{{-" }, 3, NULL }, + { TK_REXP, { .pat = "-}}" }, 3, NULL }, + { TK_LSTM, { .pat = "{%+" }, 3, NULL }, + { TK_LSTM, { .pat = "{%-" }, 3, NULL }, + { TK_RSTM, { .pat = "-%}" }, 3, NULL }, + { TK_EQS, { .pat = "===" }, 3, NULL }, + { TK_NES, { .pat = "!==" }, 3, NULL }, + { TK_ELLIP, { .pat = "..." }, 3, NULL }, + { TK_AND, { .pat = "&&" }, 2, NULL }, + { TK_ASADD, { .pat = "+=" }, 2, NULL }, + { TK_ASBAND, { .pat = "&=" }, 2, NULL }, + { TK_ASBOR, { .pat = "|=" }, 2, NULL }, + { TK_ASBXOR, { .pat = "^=" }, 2, NULL }, + //{ TK_ASDIV, { .pat = "/=" }, 2, NULL }, + { TK_ASMOD, { .pat = "%=" }, 2, NULL }, + { TK_ASMUL, { .pat = "*=" }, 2, NULL }, + { TK_ASSUB, { .pat = "-=" }, 2, NULL }, + { TK_DEC, { .pat = "--" }, 2, NULL }, + { TK_INC, { .pat = "++" }, 2, NULL }, + { TK_EQ, { .pat = "==" }, 2, NULL }, + { TK_NE, { .pat = "!=" }, 2, NULL }, + { TK_LE, { .pat = "<=" }, 2, NULL }, + { TK_GE, { .pat = ">=" }, 2, NULL }, + { TK_LSHIFT, { .pat = "<<" }, 2, NULL }, + { TK_RSHIFT, { .pat = ">>" }, 2, NULL }, { 0, { .pat = "//" }, 2, parse_comment }, { 0, { .pat = "/*" }, 2, parse_comment }, - { TK_OR, { .pat = "||" }, 2 }, - { TK_LEXP, { .pat = "{{" }, 2 }, - { TK_REXP, { .pat = "}}" }, 2 }, - { TK_LSTM, { .pat = "{%" }, 2 }, - { TK_RSTM, { .pat = "%}" }, 2 }, - { TK_ARROW, { .pat = "=>" }, 2 }, - { TK_ADD, { .pat = "+" }, 1 }, - { TK_ASSIGN, { .pat = "=" }, 1 }, - { TK_BAND, { .pat = "&" }, 1 }, - { TK_BOR, { .pat = "|" }, 1 }, - { TK_LBRACK, { .pat = "[" }, 1 }, - { TK_RBRACK, { .pat = "]" }, 1 }, - { TK_BXOR, { .pat = "^" }, 1 }, - { TK_LBRACE, { .pat = "{" }, 1 }, - { TK_RBRACE, { .pat = "}" }, 1 }, - { TK_COLON, { .pat = ":" }, 1 }, - { TK_COMMA, { .pat = "," }, 1 }, - { TK_COMPL, { .pat = "~" }, 1 }, - //{ TK_DIV, { .pat = "/" }, 1 }, - { TK_GT, { .pat = ">" }, 1 }, - { TK_NOT, { .pat = "!" }, 1 }, - { TK_LT, { .pat = "<" }, 1 }, - { TK_MOD, { .pat = "%" }, 1 }, - { TK_MUL, { .pat = "*" }, 1 }, - { TK_LPAREN, { .pat = "(" }, 1 }, - { TK_RPAREN, { .pat = ")" }, 1 }, - { TK_QMARK, { .pat = "?" }, 1 }, - { TK_SCOL, { .pat = ";" }, 1 }, - //{ TK_SUB, { .pat = "-" }, 1 }, - { TK_DOT, { .pat = "." }, 1 }, + { TK_OR, { .pat = "||" }, 2, NULL }, + { TK_LEXP, { .pat = "{{" }, 2, NULL }, + { TK_REXP, { .pat = "}}" }, 2, NULL }, + { TK_LSTM, { .pat = "{%" }, 2, NULL }, + { TK_RSTM, { .pat = "%}" }, 2, NULL }, + { TK_ARROW, { .pat = "=>" }, 2, NULL }, + { TK_ADD, { .pat = "+" }, 1, NULL }, + { TK_ASSIGN, { .pat = "=" }, 1, NULL }, + { TK_BAND, { .pat = "&" }, 1, NULL }, + { TK_BOR, { .pat = "|" }, 1, NULL }, + { TK_LBRACK, { .pat = "[" }, 1, NULL }, + { TK_RBRACK, { .pat = "]" }, 1, NULL }, + { TK_BXOR, { .pat = "^" }, 1, NULL }, + { TK_LBRACE, { .pat = "{" }, 1, NULL }, + { TK_RBRACE, { .pat = "}" }, 1, NULL }, + { TK_COLON, { .pat = ":" }, 1, NULL }, + { TK_COMMA, { .pat = "," }, 1, NULL }, + { TK_COMPL, { .pat = "~" }, 1, NULL }, + //{ TK_DIV, { .pat = "/" }, 1, NULL }, + { TK_GT, { .pat = ">" }, 1, NULL }, + { TK_NOT, { .pat = "!" }, 1, NULL }, + { TK_LT, { .pat = "<" }, 1, NULL }, + { TK_MOD, { .pat = "%" }, 1, NULL }, + { TK_MUL, { .pat = "*" }, 1, NULL }, + { TK_LPAREN, { .pat = "(" }, 1, NULL }, + { TK_RPAREN, { .pat = ")" }, 1, NULL }, + { TK_QMARK, { .pat = "?" }, 1, NULL }, + { TK_SCOL, { .pat = ";" }, 1, NULL }, + //{ TK_SUB, { .pat = "-" }, 1, NULL }, + { TK_DOT, { .pat = "." }, 1, NULL }, { TK_STRING, { .pat = "'" }, 1, parse_string }, { TK_STRING, { .pat = "\"" }, 1, parse_string }, { TK_REGEXP, { .pat = "/" }, 1, parse_regexp }, - { TK_LABEL, { .pat = "_" }, 1, parse_label }, - { TK_LABEL, { .pat = "az" }, 0, parse_label }, - { TK_LABEL, { .pat = "AZ" }, 0, parse_label }, + { TK_LABEL, { .pat = "_" }, 1, parse_label }, + { TK_LABEL, { .pat = "az" }, 0, parse_label }, + { TK_LABEL, { .pat = "AZ" }, 0, parse_label }, { TK_NUMBER, { .pat = "-" }, 1, parse_number }, { TK_NUMBER, { .pat = "09" }, 0, parse_number }, }; static const struct keyword reserved_words[] = { - { TK_ENDFUNC, "endfunction", 11 }, + { TK_ENDFUNC, "endfunction", 11, { 0 } }, { TK_DOUBLE, "Infinity", 8, { .d = INFINITY } }, - { TK_CONTINUE, "continue", 8 }, - { TK_ENDWHILE, "endwhile", 8 }, - { TK_FUNC, "function", 8 }, - { TK_DEFAULT, "default", 7 }, - { TK_RETURN, "return", 6 }, - { TK_ENDFOR, "endfor", 6 }, - { TK_SWITCH, "switch", 6 }, - { TK_LOCAL, "local", 5 }, - { TK_ENDIF, "endif", 5 }, - { TK_WHILE, "while", 5 }, - { TK_BREAK, "break", 5 }, - { TK_CATCH, "catch", 5 }, + { TK_CONTINUE, "continue", 8, { 0 } }, + { TK_ENDWHILE, "endwhile", 8, { 0 } }, + { TK_FUNC, "function", 8, { 0 } }, + { TK_DEFAULT, "default", 7, { 0 } }, + { TK_RETURN, "return", 6, { 0 } }, + { TK_ENDFOR, "endfor", 6, { 0 } }, + { TK_SWITCH, "switch", 6, { 0 } }, + { TK_LOCAL, "local", 5, { 0 } }, + { TK_ENDIF, "endif", 5, { 0 } }, + { TK_WHILE, "while", 5, { 0 } }, + { TK_BREAK, "break", 5, { 0 } }, + { TK_CATCH, "catch", 5, { 0 } }, { TK_BOOL, "false", 5, { .b = false } }, { TK_BOOL, "true", 4, { .b = true } }, - { TK_ELIF, "elif", 4 }, - { TK_ELSE, "else", 4 }, - { TK_THIS, "this", 4 }, - { TK_NULL, "null", 4 }, - { TK_CASE, "case", 4 }, + { TK_ELIF, "elif", 4, { 0 } }, + { TK_ELSE, "else", 4, { 0 } }, + { TK_THIS, "this", 4, { 0 } }, + { TK_NULL, "null", 4, { 0 } }, + { TK_CASE, "case", 4, { 0 } }, { TK_DOUBLE, "NaN", 3, { .d = NAN } }, - { TK_TRY, "try", 3 }, - { TK_FOR, "for", 3 }, - { TK_LOCAL, "let", 3 }, - { TK_IF, "if", 2 }, - { TK_IN, "in", 2 }, + { TK_TRY, "try", 3, { 0 } }, + { TK_FOR, "for", 3, { 0 } }, + { TK_LOCAL, "let", 3, { 0 } }, + { TK_IF, "if", 2, { 0 } }, + { TK_IN, "in", 2, { 0 } }, }; @@ -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,9 +360,9 @@ 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, "//")) { + if (!strcmp(tok->u.pat, "//")) { end = "\n"; elen = 1; } @@ -400,13 +400,13 @@ static uc_token * parse_string(uc_lexer *lex, bool no_regexp) { const struct token *tok = lex->tok; - char q = tok->pat[0]; + char q = tok->u.pat[0]; char *ptr, *c; uc_token *rv; int code; 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 */ @@ -438,7 +438,7 @@ parse_string(uc_lexer *lex, bool no_regexp) default: lex->is_escape = false; - c = strchr("a\ab\be\ef\fn\nr\rt\tv\v", *ptr); + c = strchr("a\ab\be\033f\fn\nr\rt\tv\v", *ptr); if (c && *c >= 'a') { lookbehind_append(lex, c + 1, 1); @@ -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; @@ -724,20 +725,20 @@ parse_label(uc_lexer *lex, bool no_regexp) size_t i; if (!lex->lookbehind && tok->plen) - lookbehind_append(lex, tok->pat, tok->plen); + lookbehind_append(lex, tok->u.pat, tok->plen); if (!buf_remaining(lex) || (lex->bufstart[0] != '_' && !isalnum(lex->bufstart[0]))) { for (i = 0, word = &reserved_words[0]; i < ARRAY_SIZE(reserved_words); i++, word = &reserved_words[i]) { - if (lex->lookbehindlen == word->plen && !strncmp(lex->lookbehind, word->pat, word->plen)) { + if (lex->lookbehind && lex->lookbehindlen == word->plen && !strncmp(lex->lookbehind, word->pat, word->plen)) { lookbehind_reset(lex); 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->u.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->u.b)); break; default: @@ -802,23 +803,23 @@ parse_number(uc_lexer *lex, bool no_regexp) if (*e == '.' || *e == 'e' || *e == 'E') { d = strtod(lex->lookbehind, &e); - if (tok->pat[0] == '-') + if (tok->u.pat[0] == '-') d = -d; if (e > lex->lookbehind && *e == 0) - 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] == '-') + if (tok->u.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); @@ -856,7 +857,8 @@ lex_step(uc_lexer *lex, FILE *fp, bool no_regexp) rem = lex->bufend - lex->bufstart; - memcpy(lex->buf, lex->bufstart, rem); + if (rem) + memcpy(lex->buf, lex->bufstart, rem); rlen = fread(lex->buf + rem, 1, lex->buflen - rem, fp); @@ -1008,7 +1010,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; @@ -1041,8 +1043,8 @@ lex_step(uc_lexer *lex, FILE *fp, bool no_regexp) c = buf_remaining(lex) ? lex->bufstart[0] : 0; - if (tok->plen ? ((search.n & masks[tok->plen]) == tok->patn) - : (c >= tok->pat[0] && c <= tok->pat[1])) { + if (tok->plen ? ((search.n & masks[tok->plen]) == tok->u.patn) + : (c >= tok->u.pat[0] && c <= tok->u.pat[1])) { lex->lastoff = lex->source->off; /* token has a parse method, switch state */ @@ -1059,14 +1061,14 @@ 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 */ else if ((lex->block == STATEMENTS && tok->type == TK_RSTM) || (lex->block == EXPRESSION && tok->type == TK_REXP)) { /* strip whitespace after block */ - if (tok->pat[0] == '-') + if (tok->u.pat[0] == '-') lex->modifier = MINUS; /* strip newline after statement block */ @@ -1093,7 +1095,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 +1105,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 +1190,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; @@ -1206,7 +1208,7 @@ uc_get_tokenname(int type) if (tokens[i].type != type) continue; - snprintf(buf, sizeof(buf), "'%s'", tokens[i].pat); + snprintf(buf, sizeof(buf), "'%s'", tokens[i].u.pat); return buf; } @@ -18,6 +18,7 @@ #define __LEXER_H_ #include "source.h" +#include "types.h" typedef enum { @@ -121,17 +122,11 @@ typedef enum { typedef struct { uc_tokentype_t type; - json_object *val; + uc_value_t *uv; size_t pos; } uc_token; typedef struct { - bool lstrip_blocks; - bool trim_blocks; - bool strict_declarations; -} uc_parse_config; - -typedef struct { uc_lex_state_t state; uc_parse_config *config; uc_source *source; @@ -170,6 +165,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,60 @@ #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__) +#include "source.h" 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 +107,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 +127,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 +238,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 +261,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 +334,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,125 +350,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; + uc_value_t *arr = uc_get_arg(0); - 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))); - - 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) { + 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); @@ -528,55 +445,80 @@ uc_chr(uc_vm *vm, size_t nargs) str[idx] = (char)n; } - return 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; - const char *key; - size_t arridx; + uc_value_t *obj = uc_get_arg(0); + uc_value_t *key = NULL; + uc_value_t *rv = NULL; + bool freeable; + size_t i; + char *k; - 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 = uc_get_arg(i); + k = uc_cast_string(vm, &key, &freeable); + rv = ucv_get(ucv_object_get(obj, k, NULL)); - key = json_object_get_string(uc_get_arg(arridx)); - rv = uc_value_get(json_object_object_get(obj, key ? key : "null")); + ucv_object_delete(obj, k); - json_object_object_del(obj, key ? key : "null"); + if (freeable) + free(k); } 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; - uc_vm_raise_exception(vm, EXCEPTION_USER, msg ? msg : "Died"); + s = msg ? uc_cast_string(vm, &msg, &freeable) : "Died"; + + uc_vm_raise_exception(vm, EXCEPTION_USER, "%s", 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); + uc_value_t *key = uc_get_arg(1); + bool found, freeable; + char *k; - 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)); + k = uc_cast_string(vm, &key, &freeable); + + ucv_object_get(obj, k, &found); + + if (freeable) + free(k); + + 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)); @@ -584,37 +526,38 @@ 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)); - char *val = key ? getenv(key) : NULL; + uc_value_t *key = uc_get_arg(0); + char *k = ucv_string_get(key); + char *val = k ? getenv(k) : NULL; - return val ? 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; } @@ -622,281 +565,233 @@ 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)); + uc_value_t *val = uc_get_arg(0); + char *e, *v; int64_t n; - char *e; - if (!val || !isxdigit(*val)) - return uc_double_new(NAN); + v = ucv_string_get(val); + + if (!v || !isxdigit(*v)) + return ucv_double_new(NAN); - n = strtoll(val, &e, 16); + n = strtoll(v, &e, 16); - if (e == val || *e) - return uc_double_new(NAN); + if (e == v || *e) + 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; - - len -= ret; - p += ret; - } - - item = json_object_get_string(json_object_array_get_idx(arr, arridx)); - - if (item) { - ret = snprintf(p, len, "%s", item); + buf = ucv_stringbuf_new(); - 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) { + (void)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); + uc_value_t *v = uc_get_arg(0); + uc_type_t t = ucv_type(v); - switch (o) { - case UC_OBJ_CFUNCTION: - case UC_OBJ_FUNCTION: - case UC_OBJ_CLOSURE: - return xjs_new_string("function"); + switch (t) { + case UC_CFUNCTION: + case UC_FUNCTION: + case UC_CLOSURE: + return ucv_string_new("function"); - case UC_OBJ_RESSOURCE: - return xjs_new_string("ressource"); + case UC_INTEGER: + return ucv_string_new("int"); - default: - switch (json_object_get_type(v)) { - case json_type_object: - return xjs_new_string("object"); + case UC_BOOLEAN: + return ucv_string_new("bool"); - case json_type_array: - return xjs_new_string("array"); - - case json_type_double: - return xjs_new_string("double"); - - case json_type_int: - return xjs_new_string("int"); - - case json_type_boolean: - return xjs_new_string("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); } @@ -908,15 +803,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) @@ -925,9 +820,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; @@ -939,40 +834,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) { @@ -987,7 +882,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; } @@ -1001,7 +896,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; } @@ -1011,71 +906,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 - (uint64_t)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); @@ -1083,10 +978,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; } @@ -1094,20 +989,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: @@ -1123,7 +1018,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; } @@ -1138,7 +1033,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; } @@ -1148,52 +1043,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 - (uint64_t)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) { + uc_value_t *rv = NULL; size_t idx, ulen; char *p, *str; int64_t n; @@ -1226,45 +1118,49 @@ uc_uchr(uc_vm *vm, size_t nargs) break; } - return 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) { @@ -1285,47 +1181,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++; @@ -1397,7 +1291,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++)); @@ -1412,7 +1306,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++)); @@ -1422,7 +1316,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; @@ -1432,33 +1326,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; @@ -1469,66 +1361,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; @@ -1545,7 +1441,7 @@ uc_require_so(uc_vm *vm, const char *path, json_object **res) return true; } - init = dlsym(dlh, "uc_module_entry"); + *(void **)(&init) = dlsym(dlh, "uc_module_entry"); if (!init) { uc_vm_raise_exception(vm, EXCEPTION_RUNTIME, @@ -1554,22 +1450,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; @@ -1598,9 +1494,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; @@ -1618,11 +1514,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; @@ -1632,12 +1527,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; @@ -1649,46 +1548,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) { - const char *name = json_object_get_string(uc_get_arg(0)); - - 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; } @@ -1698,11 +1596,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; @@ -1710,24 +1608,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; } @@ -1736,14 +1634,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; @@ -1751,10 +1649,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; @@ -1762,13 +1660,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; @@ -1778,11 +1676,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; @@ -1792,49 +1690,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; @@ -1845,24 +1745,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)) @@ -1870,40 +1773,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 *r = str ? json_object_get_string(str) : "null"; - const char *p = r; 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': @@ -1916,19 +1821,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; @@ -1937,51 +1847,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; @@ -1992,57 +1909,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"); @@ -2050,24 +1974,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)); @@ -2075,7 +1999,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"); @@ -2084,6 +2008,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; } @@ -2120,26 +2048,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"); @@ -2157,7 +2083,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, @@ -2166,64 +2092,79 @@ 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); - sigset_t sigmask, sigomask; + 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; pid_t cld; - size_t i; int rc; - switch (json_object_get_type(cmdline)) { - case json_type_string: + 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 (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[0] = xstrdup("/bin/sh"); + arglist[1] = xstrdup("-c"); + arglist[2] = ucv_to_string(vm, cmdline); arglist[3] = NULL; break; - case json_type_array: - arglist = xalloc(sizeof(*arglist) * (json_object_array_length(cmdline) + 1)); + case UC_ARRAY: + len = ucv_array_length(cmdline); + + if (len == 0) { + uc_vm_raise_exception(vm, EXCEPTION_TYPE, + "Passed command array is empty"); + + return NULL; + } + + arglist = xalloc(sizeof(*arglist) * (len + 1)); - for (i = 0; i < json_object_array_length(cmdline); i++) - arglist[i] = json_object_get_string(json_object_array_get_idx(cmdline, i)); + for (i = 0; i < len; i++) + arglist[i] = ucv_to_string(vm, ucv_array_get(cmdline, i)); arglist[i] = NULL; @@ -2236,14 +2177,7 @@ uc_system(uc_vm *vm, size_t nargs) return NULL; } - if (timeout && (!json_object_is_type(timeout, json_type_int) || json_object_get_int64(timeout) < 0)) { - uc_vm_raise_exception(vm, EXCEPTION_TYPE, - "Invalid timeout specified"); - - return NULL; - } - - tms = timeout ? json_object_get_int64(timeout) : 0; + tms = timeout ? ucv_int64_get(timeout) : 0; if (tms > 0) { sigemptyset(&sigmask); @@ -2298,14 +2232,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; } @@ -2314,6 +2251,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, @@ -2322,95 +2262,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; - - return p ? uc_value_get(p->header.jso) : NULL; - - case UC_OBJ_RESSOURCE: - p = uc_ressource_prototype(val); + uc_value_t *val = uc_get_arg(0); + uc_value_t *proto = NULL; - 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[] = { @@ -2467,7 +2373,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; @@ -629,29 +629,30 @@ uc_fs_getcwd(uc_vm *vm, size_t nargs) if (errno == ERANGE) continue; + free(buf); err_return(errno); } 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[] = { @@ -719,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); @@ -727,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); - struct uci_ptr ptr = {}; + 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 = { 0 }; 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 = {}; + struct uci_ptr ptr = { 0 }; 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; - struct uci_ptr ptr = {}; + 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 = { 0 }; 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); - struct uci_ptr ptr = {}; + 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 = { 0 }; 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; - struct uci_ptr ptr = {}; + 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 = { 0 }; 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); - struct uci_ptr ptr = {}; + 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 = { 0 }; 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,29 +695,29 @@ 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 = {}; + struct uci_ptr ptr = { 0 }; int rv, res = UCI_OK; 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); @@ -36,7 +36,7 @@ static void -print_usage(char *app) +print_usage(const char *app) { printf( "== Usage ==\n\n" @@ -51,18 +51,18 @@ print_usage(char *app) " -e Set global variables from given JSON object\n" " -E Set global variables from given JSON file\n" " -m Preload given module\n", - app); + basename(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,20 +87,20 @@ 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_vm vm = {}; - char c, c2, *err; - int rc = 0; + uc_value_t *globals = NULL; + uc_function_t *entry; + uc_vm vm = { 0 }; + int c, c2, rc = 0; + char *err; uc_vm_init(&vm, config); @@ -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; + 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; @@ -284,7 +285,12 @@ main(int argc, char **argv) if (source) fprintf(stderr, "Options -i and -s are exclusive\n"); - source = uc_source_new_buffer("[-s argument]", xstrdup(optarg), strlen(optarg)); + c = xstrdup(optarg); + source = uc_source_new_buffer("[-s argument]", c, strlen(c)); + + if (!source) + free(c); + break; case 'S': @@ -335,27 +341,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 +388,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_ */ @@ -22,17 +22,9 @@ #include <stdio.h> #include "util.h" +#include "types.h" -uc_declare_vector(uc_lineinfo, uint8_t); - -typedef struct { - char *filename, *buffer; - FILE *fp; - size_t usecount, off; - uc_lineinfo lineinfo; -} uc_source; - uc_source *uc_source_new_file(const char *path); uc_source *uc_source_new_buffer(const char *name, char *buf, size_t len); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 0000000..aed0100 --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,6 @@ +ADD_SUBDIRECTORY(cram) +ADD_SUBDIRECTORY(custom) + +IF(CMAKE_C_COMPILER_ID STREQUAL "Clang") + ADD_SUBDIRECTORY(fuzz) +ENDIF() diff --git a/tests/cram/CMakeLists.txt b/tests/cram/CMakeLists.txt new file mode 100644 index 0000000..a93add5 --- /dev/null +++ b/tests/cram/CMakeLists.txt @@ -0,0 +1,27 @@ +FIND_PACKAGE(PythonInterp 3 REQUIRED) +FILE(GLOB test_cases "test_*.t") + +SET(PYTHON_VENV_DIR "${CMAKE_CURRENT_BINARY_DIR}/.venv") +SET(PYTHON_VENV_PIP "${PYTHON_VENV_DIR}/bin/pip") +SET(PYTHON_VENV_CRAM "${PYTHON_VENV_DIR}/bin/cram") + +ADD_CUSTOM_COMMAND( + OUTPUT ${PYTHON_VENV_CRAM} + COMMAND ${PYTHON_EXECUTABLE} -m venv ${PYTHON_VENV_DIR} + COMMAND ${PYTHON_VENV_PIP} install cram +) +ADD_CUSTOM_TARGET(prepare-cram-venv ALL DEPENDS ${PYTHON_VENV_CRAM}) + +ADD_TEST( + NAME cram + COMMAND ${PYTHON_VENV_CRAM} ${test_cases} ${test_cases_san} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} +) + +SET_PROPERTY(TEST cram APPEND PROPERTY ENVIRONMENT "BUILD_BIN_DIR=$<TARGET_FILE_DIR:ucode>") + +IF(CMAKE_C_COMPILER_ID STREQUAL "Clang") + SET_PROPERTY(TEST cram APPEND PROPERTY ENVIRONMENT "UCODE_BIN=$<TARGET_FILE:ucode-san>") +ELSE() + SET_PROPERTY(TEST cram APPEND PROPERTY ENVIRONMENT "UCODE_BIN=valgrind --quiet --leak-check=full $<TARGET_FILE:ucode>") +ENDIF() diff --git a/tests/cram/test_basic.t b/tests/cram/test_basic.t new file mode 100644 index 0000000..3d4cd9e --- /dev/null +++ b/tests/cram/test_basic.t @@ -0,0 +1,59 @@ +setup common environment: + + $ [ -n "$BUILD_BIN_DIR" ] && export PATH="$BUILD_BIN_DIR:$PATH" + $ alias ucode="$UCODE_BIN" + + $ for m in $BUILD_BIN_DIR/*.so; do + > ln -s "$m" "$(pwd)/$(basename $m)"; \ + > done + +check that ucode provides exepected help: + + $ ucode | sed 's/ucode-san/ucode/' + == Usage == + + # ucode [-d] [-l] [-r] [-S] [-e '[prefix=]{"var": ...}'] [-E [prefix=]env.json] {-i <file> | -s "ucode script..."} + -h, --help\tPrint this help (esc) + -i file\tSpecify an ucode script to parse (esc) + -s "ucode script..."\tSpecify an ucode fragment to parse (esc) + -d Instead of executing the script, dump the resulting AST as dot + -l Do not strip leading block whitespace + -r Do not trim trailing block newlines + -S Enable strict mode + -e Set global variables from given JSON object + -E Set global variables from given JSON file + -m Preload given module + +check that ucode prints greetings: + + $ ucode -s "{% print('hello world') %}" + hello world (no-eol) + +check that ucode provides proper error messages: + + $ ucode -m foo + One of -i or -s is required + [1] + + $ ucode -m foo -s ' ' + Runtime error: No module named 'foo' could be found + At start of program + + [1] + + $ touch moo; ucode -m foo -i moo + Runtime error: No module named 'foo' could be found + At start of program + + [1] + +check that ucode can load fs module: + + $ ucode -m fs + One of -i or -s is required + [1] + + $ ucode -m fs -s ' ' + (no-eol) + + $ touch moo; ucode -m fs -i moo diff --git a/tests/00_syntax/00_single_line_comments b/tests/custom/00_syntax/00_single_line_comments index 24a32a2..24a32a2 100644 --- a/tests/00_syntax/00_single_line_comments +++ b/tests/custom/00_syntax/00_single_line_comments diff --git a/tests/00_syntax/01_unterminated_comment b/tests/custom/00_syntax/01_unterminated_comment index 1d3669c..1d3669c 100644 --- a/tests/00_syntax/01_unterminated_comment +++ b/tests/custom/00_syntax/01_unterminated_comment diff --git a/tests/00_syntax/02_multi_line_comments b/tests/custom/00_syntax/02_multi_line_comments index 99fc37e..99fc37e 100644 --- a/tests/00_syntax/02_multi_line_comments +++ b/tests/custom/00_syntax/02_multi_line_comments diff --git a/tests/00_syntax/03_expression_blocks b/tests/custom/00_syntax/03_expression_blocks index 3568016..3568016 100644 --- a/tests/00_syntax/03_expression_blocks +++ b/tests/custom/00_syntax/03_expression_blocks diff --git a/tests/00_syntax/04_statement_blocks b/tests/custom/00_syntax/04_statement_blocks index 920ed71..920ed71 100644 --- a/tests/00_syntax/04_statement_blocks +++ b/tests/custom/00_syntax/04_statement_blocks diff --git a/tests/00_syntax/05_block_nesting b/tests/custom/00_syntax/05_block_nesting index fcfd7da..fcfd7da 100644 --- a/tests/00_syntax/05_block_nesting +++ b/tests/custom/00_syntax/05_block_nesting diff --git a/tests/00_syntax/06_open_statement_block b/tests/custom/00_syntax/06_open_statement_block index 9c2d142..9c2d142 100644 --- a/tests/00_syntax/06_open_statement_block +++ b/tests/custom/00_syntax/06_open_statement_block diff --git a/tests/00_syntax/07_embedded_single_line_comments b/tests/custom/00_syntax/07_embedded_single_line_comments index 43f188c..43f188c 100644 --- a/tests/00_syntax/07_embedded_single_line_comments +++ b/tests/custom/00_syntax/07_embedded_single_line_comments diff --git a/tests/00_syntax/08_embedded_multi_line_comments b/tests/custom/00_syntax/08_embedded_multi_line_comments index 75aba5f..75aba5f 100644 --- a/tests/00_syntax/08_embedded_multi_line_comments +++ b/tests/custom/00_syntax/08_embedded_multi_line_comments diff --git a/tests/00_syntax/09_string_literals b/tests/custom/00_syntax/09_string_literals index 0967850..0967850 100644 --- a/tests/00_syntax/09_string_literals +++ b/tests/custom/00_syntax/09_string_literals diff --git a/tests/00_syntax/10_numeric_literals b/tests/custom/00_syntax/10_numeric_literals index 3e367d0..3e367d0 100644 --- a/tests/00_syntax/10_numeric_literals +++ b/tests/custom/00_syntax/10_numeric_literals diff --git a/tests/00_syntax/11_misc_literals b/tests/custom/00_syntax/11_misc_literals index 372741c..372741c 100644 --- a/tests/00_syntax/11_misc_literals +++ b/tests/custom/00_syntax/11_misc_literals diff --git a/tests/00_syntax/12_block_whitespace_control b/tests/custom/00_syntax/12_block_whitespace_control index 911171c..911171c 100644 --- a/tests/00_syntax/12_block_whitespace_control +++ b/tests/custom/00_syntax/12_block_whitespace_control diff --git a/tests/00_syntax/13_object_literals b/tests/custom/00_syntax/13_object_literals index 18fbbed..18fbbed 100644 --- a/tests/00_syntax/13_object_literals +++ b/tests/custom/00_syntax/13_object_literals diff --git a/tests/00_syntax/14_array_literals b/tests/custom/00_syntax/14_array_literals index 941ee4a..941ee4a 100644 --- a/tests/00_syntax/14_array_literals +++ b/tests/custom/00_syntax/14_array_literals diff --git a/tests/00_syntax/15_function_declarations b/tests/custom/00_syntax/15_function_declarations index 4257dd6..4257dd6 100644 --- a/tests/00_syntax/15_function_declarations +++ b/tests/custom/00_syntax/15_function_declarations diff --git a/tests/00_syntax/16_for_loop b/tests/custom/00_syntax/16_for_loop index 67edc21..67edc21 100644 --- a/tests/00_syntax/16_for_loop +++ b/tests/custom/00_syntax/16_for_loop diff --git a/tests/00_syntax/17_while_loop b/tests/custom/00_syntax/17_while_loop index 1e68d6b..1e68d6b 100644 --- a/tests/00_syntax/17_while_loop +++ b/tests/custom/00_syntax/17_while_loop diff --git a/tests/00_syntax/18_if_condition b/tests/custom/00_syntax/18_if_condition index 9e02767..9e02767 100644 --- a/tests/00_syntax/18_if_condition +++ b/tests/custom/00_syntax/18_if_condition diff --git a/tests/00_syntax/19_arrow_functions b/tests/custom/00_syntax/19_arrow_functions index 102c527..102c527 100644 --- a/tests/00_syntax/19_arrow_functions +++ b/tests/custom/00_syntax/19_arrow_functions diff --git a/tests/00_syntax/20_list_expressions b/tests/custom/00_syntax/20_list_expressions index d5ba459..d5ba459 100644 --- a/tests/00_syntax/20_list_expressions +++ b/tests/custom/00_syntax/20_list_expressions diff --git a/tests/00_syntax/21_regex_literals b/tests/custom/00_syntax/21_regex_literals index 3af53bb..6d85e97 100644 --- a/tests/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 -- diff --git a/tests/01_arithmetic/00_value_conversion b/tests/custom/01_arithmetic/00_value_conversion index c44ad00..c44ad00 100644 --- a/tests/01_arithmetic/00_value_conversion +++ b/tests/custom/01_arithmetic/00_value_conversion diff --git a/tests/01_arithmetic/01_division b/tests/custom/01_arithmetic/01_division index d4a2adb..d4a2adb 100644 --- a/tests/01_arithmetic/01_division +++ b/tests/custom/01_arithmetic/01_division diff --git a/tests/01_arithmetic/02_modulo b/tests/custom/01_arithmetic/02_modulo index 244d624..244d624 100644 --- a/tests/01_arithmetic/02_modulo +++ b/tests/custom/01_arithmetic/02_modulo diff --git a/tests/01_arithmetic/03_bitwise b/tests/custom/01_arithmetic/03_bitwise index faf4ffd..faf4ffd 100644 --- a/tests/01_arithmetic/03_bitwise +++ b/tests/custom/01_arithmetic/03_bitwise diff --git a/tests/01_arithmetic/04_inc_dec b/tests/custom/01_arithmetic/04_inc_dec index ae50ceb..ae50ceb 100644 --- a/tests/01_arithmetic/04_inc_dec +++ b/tests/custom/01_arithmetic/04_inc_dec diff --git a/tests/02_runtime/00_scoping b/tests/custom/02_runtime/00_scoping index 5fadf43..5fadf43 100644 --- a/tests/02_runtime/00_scoping +++ b/tests/custom/02_runtime/00_scoping diff --git a/tests/02_runtime/01_break_continue b/tests/custom/02_runtime/01_break_continue index a27d072..a27d072 100644 --- a/tests/02_runtime/01_break_continue +++ b/tests/custom/02_runtime/01_break_continue diff --git a/tests/02_runtime/02_this b/tests/custom/02_runtime/02_this index d8e85d2..d8e85d2 100644 --- a/tests/02_runtime/02_this +++ b/tests/custom/02_runtime/02_this diff --git a/tests/02_runtime/03_try_catch b/tests/custom/02_runtime/03_try_catch index 751ca1d..751ca1d 100644 --- a/tests/02_runtime/03_try_catch +++ b/tests/custom/02_runtime/03_try_catch diff --git a/tests/02_runtime/04_switch_case b/tests/custom/02_runtime/04_switch_case index 4c1fc57..4c1fc57 100644 --- a/tests/02_runtime/04_switch_case +++ b/tests/custom/02_runtime/04_switch_case diff --git a/tests/02_runtime/05_closure_scope b/tests/custom/02_runtime/05_closure_scope index c59a433..c59a433 100644 --- a/tests/02_runtime/05_closure_scope +++ b/tests/custom/02_runtime/05_closure_scope diff --git a/tests/02_runtime/06_recursion b/tests/custom/02_runtime/06_recursion index 470fc3a..470fc3a 100644 --- a/tests/02_runtime/06_recursion +++ b/tests/custom/02_runtime/06_recursion diff --git a/tests/03_bugs/01_try_catch_stack_mismatch b/tests/custom/03_bugs/01_try_catch_stack_mismatch index f6e5a0a..f6e5a0a 100644 --- a/tests/03_bugs/01_try_catch_stack_mismatch +++ b/tests/custom/03_bugs/01_try_catch_stack_mismatch diff --git a/tests/03_bugs/02_array_pop_use_after_free b/tests/custom/03_bugs/02_array_pop_use_after_free index 22f63ff..22f63ff 100644 --- a/tests/03_bugs/02_array_pop_use_after_free +++ b/tests/custom/03_bugs/02_array_pop_use_after_free diff --git a/tests/03_bugs/03_switch_fallthrough_miscompilation b/tests/custom/03_bugs/03_switch_fallthrough_miscompilation index 3e6410e..3e6410e 100644 --- a/tests/03_bugs/03_switch_fallthrough_miscompilation +++ b/tests/custom/03_bugs/03_switch_fallthrough_miscompilation diff --git a/tests/03_bugs/04_property_set_abort b/tests/custom/03_bugs/04_property_set_abort index 8af477f..8af477f 100644 --- a/tests/03_bugs/04_property_set_abort +++ b/tests/custom/03_bugs/04_property_set_abort diff --git a/tests/03_bugs/05_duplicate_ressource_type b/tests/custom/03_bugs/05_duplicate_ressource_type index 21166b2..21166b2 100644 --- a/tests/03_bugs/05_duplicate_ressource_type +++ b/tests/custom/03_bugs/05_duplicate_ressource_type diff --git a/tests/03_bugs/06_lexer_escape_at_boundary b/tests/custom/03_bugs/06_lexer_escape_at_boundary index e80b0a1..e80b0a1 100644 --- a/tests/03_bugs/06_lexer_escape_at_boundary +++ b/tests/custom/03_bugs/06_lexer_escape_at_boundary diff --git a/tests/03_bugs/07_lexer_overlong_lines b/tests/custom/03_bugs/07_lexer_overlong_lines index d2dd3be..d2dd3be 100644 --- a/tests/03_bugs/07_lexer_overlong_lines +++ b/tests/custom/03_bugs/07_lexer_overlong_lines diff --git a/tests/03_bugs/08_compiler_arrow_fn_expressions b/tests/custom/03_bugs/08_compiler_arrow_fn_expressions index 5cd8960..5cd8960 100644 --- a/tests/03_bugs/08_compiler_arrow_fn_expressions +++ b/tests/custom/03_bugs/08_compiler_arrow_fn_expressions diff --git a/tests/03_bugs/09_reject_invalid_array_indexes b/tests/custom/03_bugs/09_reject_invalid_array_indexes index a7e5272..a7e5272 100644 --- a/tests/03_bugs/09_reject_invalid_array_indexes +++ b/tests/custom/03_bugs/09_reject_invalid_array_indexes diff --git a/tests/03_bugs/10_break_stack_mismatch b/tests/custom/03_bugs/10_break_stack_mismatch index ae16dac..ae16dac 100644 --- a/tests/03_bugs/10_break_stack_mismatch +++ b/tests/custom/03_bugs/10_break_stack_mismatch diff --git a/tests/03_bugs/11_switch_stack_mismatch b/tests/custom/03_bugs/11_switch_stack_mismatch index cc3b41a..cc3b41a 100644 --- a/tests/03_bugs/11_switch_stack_mismatch +++ b/tests/custom/03_bugs/11_switch_stack_mismatch diff --git a/tests/03_bugs/12_altblock_stack_mismatch b/tests/custom/03_bugs/12_altblock_stack_mismatch index e350660..e350660 100644 --- a/tests/03_bugs/12_altblock_stack_mismatch +++ b/tests/custom/03_bugs/12_altblock_stack_mismatch diff --git a/tests/custom/CMakeLists.txt b/tests/custom/CMakeLists.txt new file mode 100644 index 0000000..c8007a0 --- /dev/null +++ b/tests/custom/CMakeLists.txt @@ -0,0 +1,22 @@ +ADD_TEST( + NAME custom + COMMAND run_tests.sh + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} +) +SET_PROPERTY(TEST custom APPEND PROPERTY ENVIRONMENT + "UCODE_BIN=valgrind --quiet --leak-check=full $<TARGET_FILE:ucode>" + "UCODE_LIB=${CMAKE_BINARY_DIR}" +) + +IF(CMAKE_C_COMPILER_ID STREQUAL "Clang") + ADD_TEST( + NAME custom-san + COMMAND run_tests.sh + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + ) + + SET_PROPERTY(TEST custom-san APPEND PROPERTY ENVIRONMENT + "UCODE_BIN=$<TARGET_FILE:ucode-san>" + "UCODE_LIB=${CMAKE_BINARY_DIR}" + ) +ENDIF() diff --git a/run_tests.sh b/tests/custom/run_tests.sh index 69010c5..61b116f 100755 --- a/run_tests.sh +++ b/tests/custom/run_tests.sh @@ -1,6 +1,11 @@ #!/usr/bin/env bash +testdir=$(dirname "$0") +topdir=$(readlink -f "$testdir/../..") + line='........................................' +ucode_bin=${UCODE_BIN:-"$topdir/ucode"} +ucode_lib=${UCODE_LIB:-"$topdir"} extract_sections() { local file=$1 @@ -47,7 +52,10 @@ run_testcase() { local code=$6 local fail=0 - ./ucode -e '{ "REQUIRE_SEARCH_PATH": [ "./lib/*.so" ] }' -i - <"$in" >"$dir/res.out" 2>"$dir/res.err" + ( + cd "$topdir" + $ucode_bin -e '{ "REQUIRE_SEARCH_PATH": [ "'"$ucode_lib"'/*.so" ] }' -i - <"$in" >"$dir/res.out" 2>"$dir/res.err" + ) touch "$dir/empty" printf "%d\n" $? > "$dir/res.code" @@ -162,7 +170,7 @@ use_test() { return 1 } -for catdir in tests/[0-9][0-9]_*; do +for catdir in "$testdir/"[0-9][0-9]_*; do [ -d "$catdir" ] || continue printf "\n##\n## Running %s tests\n##\n\n" "${catdir##*/[0-9][0-9]_}" @@ -176,3 +184,4 @@ for catdir in tests/[0-9][0-9]_*; do done printf "\nRan %d tests, %d okay, %d failures\n" $n_tests $((n_tests - n_fails)) $n_fails +exit $n_fails diff --git a/tests/fuzz/CMakeLists.txt b/tests/fuzz/CMakeLists.txt new file mode 100644 index 0000000..384e7e0 --- /dev/null +++ b/tests/fuzz/CMakeLists.txt @@ -0,0 +1,16 @@ +MACRO(ADD_FUZZER_TEST name) + ADD_EXECUTABLE(${name} ${name}.c) + TARGET_COMPILE_OPTIONS(${name} PRIVATE -g -O1 -fno-omit-frame-pointer -fsanitize=fuzzer,address,leak,undefined) + TARGET_INCLUDE_DIRECTORIES(${name} PRIVATE ${PROJECT_SOURCE_DIR}) + TARGET_LINK_OPTIONS(${name} PRIVATE -stdlib=libc++ -fsanitize=fuzzer,address,leak,undefined) + ADD_TEST( + NAME ${name} + COMMAND ${name} -max_len=256 -timeout=10 -max_total_time=300 ${CMAKE_CURRENT_SOURCE_DIR}/corpus + ) +ENDMACRO(ADD_FUZZER_TEST) + +FILE(GLOB test_cases "test-*.c") +FOREACH(test_case ${test_cases}) + GET_FILENAME_COMPONENT(test_case ${test_case} NAME_WE) + ADD_FUZZER_TEST(${test_case}) +ENDFOREACH(test_case) diff --git a/tests/fuzz/corpus/.keep b/tests/fuzz/corpus/.keep new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tests/fuzz/corpus/.keep diff --git a/tests/fuzz/test-fuzz.c b/tests/fuzz/test-fuzz.c new file mode 100644 index 0000000..40649e2 --- /dev/null +++ b/tests/fuzz/test-fuzz.c @@ -0,0 +1,9 @@ +#include <stdio.h> +#include <stdint.h> +#include <stddef.h> +#include <limits.h> + +int LLVMFuzzerTestOneInput(const uint8_t *input, size_t size) +{ + return 0; +} @@ -0,0 +1,1809 @@ +/* + * 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, (int)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; + void *k; + + 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) { + k = xstrdup(key); + + if (lh_table_insert_w_hash(object->table, k, val, hash, 0) != 0) { + free(k); + + return false; + } + + return true; + } + + 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 ? (uc_upvalref_t **)((uintptr_t)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 > 0 && type <= res_types.count) ? &res_types.entries[type - 1] : 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 ? (type - res_types.entries) + 1 : 0; + 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, *item; + 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) { + item = ucv_from_json(vm, val); + + if (!ucv_object_add(uv, key, item)) + ucv_put(item); + +#ifdef __clang_analyzer__ + /* Clang static analyzer does not understand that the object retains + * our item so pretend to free it here to suppress the false positive + * memory leak warning. */ + ucv_put(item); +#endif + } + + 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++) { + item = ucv_from_json(vm, json_object_array_get_idx(jso, i)); + + if (!ucv_array_push(uv, item)) + ucv_put(item); + +#ifdef __clang_analyzer__ + /* Clang static analyzer does not understand that the array retains + * our item so pretend to free it here to suppress the false positive + * memory leak warning. */ + ucv_put(item); +#endif + } + + 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; s != NULL && 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; + size_t l; + char *s; + + 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) { + s = ucv_string_get(str); + l = ucv_string_length(str); + + if (json) + ucv_to_string_json_encoded(pb, s, l, false); + else if (s) + ucv_stringbuf_addstr(pb, s, l); + } + 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, (int)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, l; + double d; + char *s; + + 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: + s = ucv_string_get(uv); + l = ucv_string_length(uv); + + if (s) { + if (json) + ucv_to_string_json_encoded(pb, s, l, false); + else + ucv_stringbuf_addstr(pb, s, l); + } + + 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) { + s = ucv_string_get(argname); + l = ucv_string_length(argname); + + if (s) + ucv_stringbuf_addstr(pb, s, l); + + ucv_put(argname); + + continue; + } + + ucv_stringbuf_printf(pb, "[arg%zu]", i); + } + + 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[0] ? " " : "", + cfunction->name[0] ? 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); + const char *s1, *s2; + 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: + s1 = ucv_string_get(uv1); + s2 = ucv_string_get(uv2); + u1 = ucv_string_length(uv1); + u2 = ucv_string_length(uv2); + + if (s1 == NULL || s2 == NULL || u1 != u2) + return false; + + return (memcmp(s1, s2, 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) { + (void)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 = (uc_value_t *)((uintptr_t)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 = (uc_value_t *)((uintptr_t)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,428 @@ +/* + * 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 "util.h" + + +/* Value types and generic value header */ + +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; + + +/* Constant list defintions */ + +typedef struct { + size_t isize; + size_t dsize; + uint64_t *index; + char *data; +} uc_value_list; + + +/* Source buffer defintions */ + +uc_declare_vector(uc_lineinfo, uint8_t); + +typedef struct { + char *filename, *buffer; + FILE *fp; + size_t usecount, off; + uc_lineinfo lineinfo; +} uc_source; + + +/* Bytecode chunk defintions */ + +typedef struct { + size_t from, to, target, slot; +} uc_ehrange; + +typedef struct { + size_t from, to, slot, nameidx; +} uc_varrange; + +uc_declare_vector(uc_ehranges, uc_ehrange); +uc_declare_vector(uc_variables, uc_varrange); +uc_declare_vector(uc_offsetinfo, uint8_t); + +typedef struct { + size_t count; + uint8_t *entries; + uc_value_list constants; + uc_ehranges ehranges; + struct { + uc_variables variables; + uc_value_list varnames; + uc_offsetinfo offsets; + } debuginfo; +} uc_chunk; + + +/* Value type structures */ + +typedef struct uc_weakref_t { + struct uc_weakref_t *prev; + struct uc_weakref_t *next; +} 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); + + +/* Parser definitions */ + +typedef struct { + bool lstrip_blocks; + bool trim_blocks; + bool strict_declarations; +} uc_parse_config; + + +/* VM definitions */ + +typedef enum { + EXCEPTION_NONE, + EXCEPTION_SYNTAX, + EXCEPTION_RUNTIME, + EXCEPTION_TYPE, + EXCEPTION_REFERENCE, + EXCEPTION_USER +} uc_exception_type_t; + +typedef struct { + uc_exception_type_t type; + uc_value_t *stacktrace; + char *message; +} uc_exception; + +typedef struct { + uint8_t *ip; + uc_closure_t *closure; + uc_cfunction_t *cfunction; + size_t stackframe; + uc_value_t *ctx; + bool mcall; +} uc_callframe; + +uc_declare_vector(uc_callframes, uc_callframe); +uc_declare_vector(uc_stack, uc_value_t *); + +struct uc_vm { + uc_stack stack; + uc_exception exception; + uc_callframes callframes; + uc_upvalref_t *open_upvals; + uc_parse_config *config; + uc_value_t *globals; + uc_source *sources; + uc_weakref_t values; + union { + uint32_t u32; + int32_t s32; + uint16_t u16; + int16_t s16; + uint8_t u8; + int8_t s8; + } arg; + size_t spread_values; + uint8_t trace; +}; + + +/* Value API */ + +typedef struct printbuf uc_stringbuf_t; + +void ucv_free(uc_value_t *, bool); +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) _ucv_string_get((uc_value_t **)&uv) + +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 = NULL; \ + uc_value_t *val = NULL; \ + struct lh_entry *entry##key; \ + struct lh_entry *entry_next##key = NULL; \ + for (entry##key = (ucv_type(obj) == UC_OBJECT) ? ((uc_object_t *)obj)->table->head : NULL; \ + (entry##key ? (key = (char *)lh_entry_k(entry##key), \ + val = (uc_value_t *)lh_entry_v(entry##key), \ + entry_next##key = entry##key->next, entry##key) \ + : 0); \ + entry##key = entry_next##key) + +uc_value_t *ucv_function_new(const char *, size_t, uc_source *); +size_t ucv_function_srcpos(uc_value_t *, size_t); + +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_ */ @@ -218,6 +218,7 @@ static inline struct json_tokener *xjs_new_tokener(void) { return tok; } +__attribute__((format(printf, 2, 0))) static inline int xasprintf(char **strp, const char *fmt, ...) { va_list ap; int len; @@ -234,6 +235,7 @@ static inline int xasprintf(char **strp, const char *fmt, ...) { return len; } +__attribute__((format(printf, 2, 0))) static inline int xvasprintf(char **strp, const char *fmt, va_list ap) { int len = vasprintf(strp, fmt, ap); @@ -245,4 +247,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)) { - delta = (void *)v1 - (void *)v2; + if (t1 == t2 && !ucv_is_scalar(v1)) { + delta = (intptr_t)v1 - (intptr_t)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); } } @@ -414,7 +348,7 @@ add_num(uc_value_list *list, int64_t n) list->index[list->isize++] = (TAG_TYPE)(TAG_NUM | TAG_SET_NV(n)); } else { - if (list->dsize + sz > TAG_MASK) { + if ((TAG_TYPE)list->dsize + sz > TAG_MASK) { fprintf(stderr, "Constant data too large\n"); abort(); } @@ -466,7 +400,7 @@ add_dbl(uc_value_list *list, double d) { size_t sz = TAG_ALIGN(sizeof(d)); - if (list->dsize + sz > TAG_MASK) { + if ((TAG_TYPE)list->dsize + sz > TAG_MASK) { fprintf(stderr, "Constant data too large\n"); abort(); } @@ -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"); @@ -516,7 +450,7 @@ add_str(uc_value_list *list, const char *s, size_t slen) sz = TAG_ALIGN(sizeof(uint32_t) + slen); - if (list->dsize + sz > TAG_MASK) { + if ((TAG_TYPE)list->dsize + sz > TAG_MASK) { fprintf(stderr, "Constant data too large\n"); abort(); } @@ -594,7 +528,7 @@ add_ptr(uc_value_list *list, void *ptr) { size_t sz = TAG_ALIGN(sizeof(ptr)); - if (list->dsize + sz > TAG_MASK) { + if ((TAG_TYPE)list->dsize + sz > TAG_MASK) { fprintf(stderr, "Constant data too large\n"); abort(); } @@ -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; @@ -29,6 +29,8 @@ #include <stdio.h> +#include "types.h" + typedef enum { TAG_INVAL = 0, TAG_NUM = 1, @@ -39,43 +41,19 @@ typedef enum { TAG_PTR = 6 } uc_value_type_t; -typedef struct { - size_t isize; - size_t dsize; - uint64_t *index; - char *data; -} uc_value_list; - -json_object *uc_double_new(double v); - -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); +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); +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 * @@ -227,9 +232,9 @@ uc_vm_decode_insn(uc_vm *vm, uc_callframe *frame, uc_chunk *chunk) case -4: vm->arg.s32 = ( - frame->ip[0] * 0x1000000 + - frame->ip[1] * 0x10000 + - frame->ip[2] * 0x100 + + frame->ip[0] * 0x1000000UL + + frame->ip[1] * 0x10000UL + + frame->ip[2] * 0x100UL + frame->ip[3] ) - 0x7fffffff; frame->ip += 4; @@ -242,9 +247,9 @@ uc_vm_decode_insn(uc_vm *vm, uc_callframe *frame, uc_chunk *chunk) case 4: vm->arg.u32 = ( - frame->ip[0] * 0x1000000 + - frame->ip[1] * 0x10000 + - frame->ip[2] * 0x100 + + frame->ip[0] * 0x1000000UL + + frame->ip[1] * 0x10000UL + + frame->ip[2] * 0x100UL + frame->ip[3] ); frame->ip += 4; @@ -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, (void *)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); + (uint16_t)(vm->arg.s16 < 0 ? -vm->arg.s16 : vm->arg.s16)); break; case -4: fprintf(stderr, " {%c0x%x}", vm->arg.s32 < 0 ? '-' : '+', - vm->arg.s32 < 0 ? -(unsigned)vm->arg.s32 : vm->arg.s32); + (uint32_t)(vm->arg.s32 < 0 ? -vm->arg.s32 : 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) +{ + uc_callframe *frame = uc_vm_current_frame(vm); + uc_value_t *message = ucv_object_get(frame->ctx, "message", NULL); + + 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) { - bool strict = (level > 0) || (flags & JSON_C_TO_STRING_STRICT); - json_object *message = json_object_object_get(jso, "message"); + 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)); - return sprintbuf(pb, "%s", - strict ? json_object_to_json_string(message) : json_object_get_string(message)); + 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(); - - 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)); + exo = uc_vm_exception_new(vm, vm->exception.type, vm->exception.message, 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,19 @@ 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 if (frame->ip != chunk->entries) + ucv_stringbuf_printf(buf, "At instruction %zu", (frame->ip - chunk->entries) - 1); else - xasprintf(&msg, "At offset %zu", (frame->ip - chunk->entries) - 1); - - json_object_object_add(json_object_array_get_idx(stacktrace, 0), "context", xjs_new_string(msg)); + ucv_stringbuf_append(buf, "At start of program"); - free(msg); + ucv_object_add(ucv_array_get(stacktrace, 0), "context", ucv_stringbuf_finish(buf)); return stacktrace; } @@ -823,7 +865,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 +879,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 +898,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 +936,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 +970,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 +995,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 +1016,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 +1033,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, (void *)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, (void *)created, s); + free(s); + } if (prev) prev->next = created; @@ -1017,21 +1062,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, (void *)ref, s); + free(s); + } vm->open_upvals = ref->next; - json_object_put(ref->header.jso); + ucv_put(&ref->header); } } @@ -1039,13 +1085,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 +1106,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 +1115,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 +1143,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); + 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); - const char *typenames[] = { - [json_type_string] = "string", - [json_type_int] = "integer", - [json_type_double] = "double", - [json_type_boolean] = "boolean", - [json_type_null] = "null" - }; - - 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 +1193,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 +1239,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 +1274,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 +1319,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 +1356,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) { - if (json_object_object_get_ex(scope->header.jso, json_object_get_string(name), &val)) + while (true) { + 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; @@ -1344,26 +1388,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 +1418,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 +1429,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 +1442,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 +1458,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 +1481,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 +1496,83 @@ 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); + uc_value_t *val; 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))); + val = uc_vm_stack_peek(vm, vm->arg.u32 - idx - 1); + ucv_object_add(obj, + ucv_string_get(val), + 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 +1581,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 +1596,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 +1620,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 +1635,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 +1675,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 +1705,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 +1778,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 +1793,62 @@ 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); - 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 *)(uintptr_t)(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 +1865,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 +1953,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--; @@ -1912,6 +1974,8 @@ uc_vm_callframe_pop(uc_vm *vm) static void uc_vm_output_exception(uc_vm *vm) { + uc_value_t *ctx; + if (vm->exception.type == EXCEPTION_USER) fprintf(stderr, "%s\n", vm->exception.message); else @@ -1919,10 +1983,9 @@ uc_vm_output_exception(uc_vm *vm) exception_type_strings[vm->exception.type] ? exception_type_strings[vm->exception.type] : "Error", vm->exception.message); - fprintf(stderr, "%s\n\n", - json_object_get_string( - json_object_object_get( - json_object_array_get_idx(vm->exception.stacktrace, 0), "context"))); + ctx = ucv_object_get(ucv_array_get(vm->exception.stacktrace, 0), "context", NULL); + + fprintf(stderr, "%s\n\n", ucv_string_get(ctx)); } static uc_vm_status_t @@ -1930,7 +1993,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 +2024,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 +2163,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 +2190,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 +2226,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 +2239,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 +2266,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 +2291,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 +2311,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 +2320,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,9 +21,9 @@ #include <stdarg.h> #include "chunk.h" -#include "object.h" #include "util.h" #include "lexer.h" +#include "types.h" #define __insns \ __insn(NOOP) \ @@ -102,57 +102,9 @@ typedef struct { int8_t stack_pop; int8_t stack_push; int8_t operand_bytes; - bool operand_is_skip; } uc_insn_definition; typedef enum { - EXCEPTION_NONE, - EXCEPTION_SYNTAX, - EXCEPTION_RUNTIME, - EXCEPTION_TYPE, - EXCEPTION_REFERENCE, - EXCEPTION_USER -} uc_exception_type_t; - -typedef struct { - uc_exception_type_t type; - json_object *stacktrace; - char *message; -} uc_exception; - -typedef struct { - uint8_t *ip; - uc_closure *closure; - uc_cfunction *cfunction; - size_t stackframe; - json_object *ctx; - bool mcall; -} uc_callframe; - -uc_declare_vector(uc_callframes, uc_callframe); -uc_declare_vector(uc_stack, json_object *); - -typedef struct uc_vm { - uc_stack stack; - uc_exception exception; - uc_callframes callframes; - uc_upvalref *open_upvals; - uc_parse_config *config; - uc_prototype *globals; - uc_source *sources; - union { - uint32_t u32; - int32_t s32; - uint16_t u16; - int16_t s16; - uint8_t u8; - int8_t s8; - } arg; - size_t spread_values; - uint8_t trace; -} uc_vm; - -typedef enum { STATUS_OK, ERROR_COMPILE, ERROR_RUNTIME @@ -163,15 +115,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_ */ |