diff options
author | Jo-Philipp Wich <jo@mein.io> | 2021-05-26 07:40:21 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-05-26 07:40:21 +0200 |
commit | daef8b35f421c5481116c27fa5132881549a76a6 (patch) | |
tree | 02084ca6771d425cef509d0a5504a5591dcdb7fd | |
parent | c706eb101934ec05a1aa0fa75ab79f8b1ba405e8 (diff) | |
parent | 9874562545d93582a75bc2e6d58fc772e981a3ba (diff) |
Merge pull request #14 from jow-/refactor
Refactoring & raw code mode support
-rw-r--r-- | CMakeLists.txt | 3 | ||||
-rw-r--r-- | compiler.c | 12 | ||||
-rw-r--r-- | lexer.c | 88 | ||||
-rw-r--r-- | lexer.h | 3 | ||||
-rw-r--r-- | lib.c | 29 | ||||
-rw-r--r-- | lib.h | 3 | ||||
-rw-r--r-- | main.c | 58 | ||||
-rw-r--r-- | tests/cram/test_basic.t | 3 | ||||
-rw-r--r-- | types.h | 1 |
9 files changed, 104 insertions, 96 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index d34d79e..e9923f1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,7 +19,8 @@ OPTION(UCI_SUPPORT "UCI plugin support" ON) OPTION(LEGACY_SUPPORT "Support deprecated syntax features" ON) SET(LIB_SEARCH_PATH "${CMAKE_INSTALL_PREFIX}/lib/ucode/*.so:${CMAKE_INSTALL_PREFIX}/share/ucode/*.uc:./*.so:./*.uc" CACHE STRING "Default library search path") -ADD_DEFINITIONS(-DLIB_SEARCH_PATH="${LIB_SEARCH_PATH}") +STRING(REPLACE ":" "\", \"" LIB_SEARCH_DEFINE "${LIB_SEARCH_PATH}") +ADD_DEFINITIONS(-DLIB_SEARCH_PATH="${LIB_SEARCH_DEFINE}") IF(NOT APPLE) SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "-Wl,--gc-sections") @@ -60,7 +60,8 @@ uc_compiler_parse_rules[TK_ERROR + 1] = { [TK_NUMBER] = { uc_compiler_compile_constant, NULL, P_NONE }, [TK_DOUBLE] = { uc_compiler_compile_constant, NULL, P_NONE }, [TK_STRING] = { uc_compiler_compile_constant, NULL, P_NONE }, - [TK_BOOL] = { uc_compiler_compile_constant, NULL, P_NONE }, + [TK_TRUE] = { uc_compiler_compile_constant, NULL, P_NONE }, + [TK_FALSE] = { uc_compiler_compile_constant, NULL, P_NONE }, [TK_NULL] = { uc_compiler_compile_constant, NULL, P_NONE }, [TK_THIS] = { uc_compiler_compile_constant, NULL, P_NONE }, [TK_REGEXP] = { uc_compiler_compile_constant, NULL, P_NONE }, @@ -1455,9 +1456,12 @@ uc_compiler_compile_constant(uc_compiler *compiler, bool assignable) uc_compiler_emit_insn(compiler, compiler->parser->prev.pos, I_LNULL); break; - case TK_BOOL: - uc_compiler_emit_insn(compiler, compiler->parser->prev.pos, - ucv_boolean_get(compiler->parser->prev.uv) ? I_LTRUE : I_LFALSE); + case TK_TRUE: + uc_compiler_emit_insn(compiler, compiler->parser->prev.pos, I_LTRUE); + break; + + case TK_FALSE: + uc_compiler_emit_insn(compiler, compiler->parser->prev.pos, I_LFALSE); break; case TK_STRING: @@ -35,10 +35,6 @@ struct keyword { unsigned type; const char *pat; unsigned plen; - union { - double d; - bool b; - } u; }; struct token { @@ -135,37 +131,35 @@ static const struct token tokens[] = { }; static const struct keyword reserved_words[] = { - { TK_ENDFUNC, "endfunction", 11, { 0 } }, - { TK_DOUBLE, "Infinity", 8, { .d = INFINITY } }, - { TK_CONTINUE, "continue", 8, { 0 } }, - { TK_ENDWHILE, "endwhile", 8, { 0 } }, - { TK_FUNC, "function", 8, { 0 } }, - { TK_DEFAULT, "default", 7, { 0 } }, - { TK_DELETE, "delete", 6, { 0 } }, - { TK_RETURN, "return", 6, { 0 } }, - { TK_ENDFOR, "endfor", 6, { 0 } }, - { TK_SWITCH, "switch", 6, { 0 } }, + { TK_ENDFUNC, "endfunction", 11 }, + { TK_CONTINUE, "continue", 8 }, + { TK_ENDWHILE, "endwhile", 8 }, + { TK_FUNC, "function", 8 }, + { TK_DEFAULT, "default", 7 }, + { TK_DELETE, "delete", 6 }, + { TK_RETURN, "return", 6 }, + { TK_ENDFOR, "endfor", 6 }, + { TK_SWITCH, "switch", 6 }, #ifndef NO_LEGACY - { TK_LOCAL, "local", 5, { 0 } }, + { TK_LOCAL, "local", 5 }, #endif - { TK_ENDIF, "endif", 5, { 0 } }, - { TK_WHILE, "while", 5, { 0 } }, - { TK_BREAK, "break", 5, { 0 } }, - { TK_CATCH, "catch", 5, { 0 } }, - { TK_CONST, "const", 5, { 0 } }, - { TK_BOOL, "false", 5, { .b = false } }, - { TK_BOOL, "true", 4, { .b = true } }, - { 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, { 0 } }, - { TK_FOR, "for", 3, { 0 } }, - { TK_LOCAL, "let", 3, { 0 } }, - { TK_IF, "if", 2, { 0 } }, - { TK_IN, "in", 2, { 0 } }, + { TK_ENDIF, "endif", 5 }, + { TK_WHILE, "while", 5 }, + { TK_BREAK, "break", 5 }, + { TK_CATCH, "catch", 5 }, + { TK_CONST, "const", 5 }, + { TK_FALSE, "false", 5 }, + { TK_TRUE, "true", 4 }, + { TK_ELIF, "elif", 4 }, + { TK_ELSE, "else", 4 }, + { TK_THIS, "this", 4 }, + { TK_NULL, "null", 4 }, + { TK_CASE, "case", 4 }, + { TK_TRY, "try", 3 }, + { TK_FOR, "for", 3 }, + { TK_LOCAL, "let", 3 }, + { TK_IF, "if", 2 }, + { TK_IN, "in", 2 }, }; @@ -728,7 +722,6 @@ parse_label(uc_lexer *lex) { const struct token *tok = lex->tok; const struct keyword *word; - uc_token *rv; char *ptr; size_t i; @@ -741,20 +734,7 @@ parse_label(uc_lexer *lex) 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, ucv_double_new(word->u.d)); - break; - - case TK_BOOL: - rv = emit_op(lex, lex->source->off - word->plen, word->type, ucv_boolean_new(word->u.b)); - break; - - default: - rv = emit_op(lex, lex->source->off - word->plen, word->type, NULL); - } - - return rv; + return emit_op(lex, lex->source->off - word->plen, word->type, NULL); } } } @@ -1067,6 +1047,13 @@ lex_step(uc_lexer *lex, FILE *fp) return NULL; } + /* in raw code mode, ignore template tag tokens */ + if (lex->config && lex->config->raw_mode && + (tok->type == TK_LSTM || tok->type == TK_RSTM || + tok->type == TK_LEXP || tok->type == TK_REXP)) { + continue; + } + /* disallow nesting blocks */ if (tok->type == TK_LSTM || tok->type == TK_LEXP) { buf_consume(lex, tok->plen); @@ -1208,6 +1195,11 @@ uc_lexer_init(uc_lexer *lex, uc_parse_config *config, uc_source *source) lex->lastoff = 0; + if (config && config->raw_mode) { + lex->state = UT_LEX_IDENTIFY_TOKEN; + lex->block = STATEMENTS; + } + /* Skip any potential interpreter line */ if (lex->source->off == 0) uc_lexer_skip_shebang(lex); @@ -96,7 +96,8 @@ typedef enum { TK_ARROW, TK_DOT, TK_RBRACK, - TK_BOOL, + TK_TRUE, + TK_FALSE, TK_NUMBER, TK_DOUBLE, TK_STRING, @@ -2579,7 +2579,34 @@ static const uc_cfunction_list functions[] = { void -uc_lib_init(uc_value_t *scope) +uc_load_stdlib(uc_value_t *scope) { uc_add_proto_functions(scope, functions); } + +uc_value_t * +uc_alloc_global(uc_vm *vm) +{ + const char *path[] = { LIB_SEARCH_PATH }; + uc_value_t *global, *arr; + size_t i; + + global = ucv_object_new(vm); + + /* build default require() search path */ + arr = ucv_array_new(vm); + + for (i = 0; i < ARRAY_SIZE(path); i++) + ucv_array_push(arr, ucv_string_new(path[i])); + + ucv_object_add(global, "REQUIRE_SEARCH_PATH", arr); + + /* register global math constants */ + ucv_object_add(global, "NaN", ucv_double_new(NAN)); + ucv_object_add(global, "Infinity", ucv_double_new(INFINITY)); + + /* register global property */ + ucv_object_add(global, "global", ucv_get(global)); + + return global; +} @@ -25,7 +25,8 @@ typedef struct { uc_cfn_ptr_t func; } uc_cfunction_list; -void uc_lib_init(uc_value_t *scope); +void uc_load_stdlib(uc_value_t *scope); +uc_value_t *uc_alloc_global(uc_vm *vm); 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); @@ -40,7 +40,7 @@ print_usage(const char *app) { printf( "== Usage ==\n\n" - " # %s [-d] [-l] [-r] [-S] [-e '[prefix=]{\"var\": ...}'] [-E [prefix=]env.json] {-i <file> | -s \"ucode script...\"}\n" + " # %s [-d] [-l] [-r] [-S] [-R] [-e '[prefix=]{\"var\": ...}'] [-E [prefix=]env.json] {-i <file> | -s \"ucode script...\"}\n" " -h, --help Print this help\n" " -i file Specify an ucode script to parse\n" " -s \"ucode script...\" Specify an ucode fragment to parse\n" @@ -48,6 +48,7 @@ print_usage(const char *app) " -l Do not strip leading block whitespace\n" " -r Do not trim trailing block newlines\n" " -S Enable strict mode\n" + " -R Enable raw code mode\n" " -e Set global variables from given JSON object\n" " -E Set global variables from given JSON file\n" " -m Preload given module\n", @@ -55,34 +56,6 @@ print_usage(const char *app) } static void -globals_init(uc_vm *vm, uc_value_t *scope, int argc, char **argv) -{ - uc_value_t *arr = ucv_array_new(vm); - const char *p, *last; - int i; - - for (p = last = LIB_SEARCH_PATH;; p++) { - if (*p == ':' || *p == '\0') { - ucv_array_push(arr, ucv_string_new_length(last, p - last)); - - if (!*p) - break; - - last = p + 1; - } - } - - ucv_object_add(scope, "REQUIRE_SEARCH_PATH", arr); - - arr = ucv_array_new(vm); - - for (i = 0; i < argc; i++) - ucv_array_push(arr, ucv_string_new(argv[i])); - - ucv_object_add(scope, "ARGV", arr); -} - -static void register_variable(uc_value_t *scope, const char *key, uc_value_t *val) { char *name = strdup(key); @@ -105,10 +78,10 @@ parse(uc_parse_config *config, uc_source *src, uc_value_t *env, uc_value_t *modules, int argc, char **argv) { - uc_value_t *globals = NULL; + uc_value_t *globals = NULL, *arr; uc_function_t *entry; uc_vm vm = { 0 }; - int rc = 0; + int i, rc = 0; char *err; uc_vm_init(&vm, config); @@ -122,10 +95,16 @@ parse(uc_parse_config *config, uc_source *src, goto out; } - globals = ucv_object_new(&vm); + /* allocate global scope */ + globals = uc_alloc_global(&vm); - /* load global variables */ - globals_init(&vm, globals, argc, argv); + /* register ARGV array */ + arr = ucv_array_new_length(&vm, argc); + + for (i = 0; i < argc; i++) + ucv_array_push(arr, ucv_string_new(argv[i])); + + ucv_object_add(globals, "ARGV", arr); /* load env variables */ if (env) { @@ -134,10 +113,7 @@ parse(uc_parse_config *config, uc_source *src, } /* load std functions into global scope */ - uc_lib_init(globals); - - /* create instance of global scope, set "global" property on it */ - ucv_object_add(globals, "global", ucv_get(globals)); + uc_load_stdlib(globals); rc = uc_vm_execute(&vm, entry, globals, modules); @@ -239,7 +215,7 @@ main(int argc, char **argv) goto out; } - while ((opt = getopt(argc, argv, "hlrSe:E:i:s:m:")) != -1) + while ((opt = getopt(argc, argv, "hlrSRe:E:i:s:m:")) != -1) { switch (opt) { case 'h': @@ -287,6 +263,10 @@ main(int argc, char **argv) config.strict_declarations = true; break; + case 'R': + config.raw_mode = true; + break; + case 'e': c = strchr(optarg, '='); diff --git a/tests/cram/test_basic.t b/tests/cram/test_basic.t index 3d4cd9e..aab5b16 100644 --- a/tests/cram/test_basic.t +++ b/tests/cram/test_basic.t @@ -12,7 +12,7 @@ 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..."} + # ucode [-d] [-l] [-r] [-S] [-R] [-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) @@ -20,6 +20,7 @@ check that ucode provides exepected help: -l Do not strip leading block whitespace -r Do not trim trailing block newlines -S Enable strict mode + -R Enable raw code mode -e Set global variables from given JSON object -E Set global variables from given JSON file -m Preload given module @@ -205,6 +205,7 @@ typedef struct { bool lstrip_blocks; bool trim_blocks; bool strict_declarations; + bool raw_mode; } uc_parse_config; |