summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJo-Philipp Wich <jo@mein.io>2021-05-26 07:40:21 +0200
committerGitHub <noreply@github.com>2021-05-26 07:40:21 +0200
commitdaef8b35f421c5481116c27fa5132881549a76a6 (patch)
tree02084ca6771d425cef509d0a5504a5591dcdb7fd
parentc706eb101934ec05a1aa0fa75ab79f8b1ba405e8 (diff)
parent9874562545d93582a75bc2e6d58fc772e981a3ba (diff)
Merge pull request #14 from jow-/refactor
Refactoring & raw code mode support
-rw-r--r--CMakeLists.txt3
-rw-r--r--compiler.c12
-rw-r--r--lexer.c88
-rw-r--r--lexer.h3
-rw-r--r--lib.c29
-rw-r--r--lib.h3
-rw-r--r--main.c58
-rw-r--r--tests/cram/test_basic.t3
-rw-r--r--types.h1
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")
diff --git a/compiler.c b/compiler.c
index d978f38..4f20be0 100644
--- a/compiler.c
+++ b/compiler.c
@@ -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:
diff --git a/lexer.c b/lexer.c
index 95acfe6..1be6978 100644
--- a/lexer.c
+++ b/lexer.c
@@ -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);
diff --git a/lexer.h b/lexer.h
index 96cdff8..9f26beb 100644
--- a/lexer.h
+++ b/lexer.h
@@ -96,7 +96,8 @@ typedef enum {
TK_ARROW,
TK_DOT,
TK_RBRACK,
- TK_BOOL,
+ TK_TRUE,
+ TK_FALSE,
TK_NUMBER,
TK_DOUBLE,
TK_STRING,
diff --git a/lib.c b/lib.c
index c3a1599..98307f6 100644
--- a/lib.c
+++ b/lib.c
@@ -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;
+}
diff --git a/lib.h b/lib.h
index aad9a9d..2d27b04 100644
--- a/lib.h
+++ b/lib.h
@@ -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);
diff --git a/main.c b/main.c
index 3fd1f25..5d14c83 100644
--- a/main.c
+++ b/main.c
@@ -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
diff --git a/types.h b/types.h
index 3aaf8bc..a4377ad 100644
--- a/types.h
+++ b/types.h
@@ -205,6 +205,7 @@ typedef struct {
bool lstrip_blocks;
bool trim_blocks;
bool strict_declarations;
+ bool raw_mode;
} uc_parse_config;