diff options
-rw-r--r-- | ast.h | 2 | ||||
-rw-r--r-- | lexer.c | 20 | ||||
-rw-r--r-- | main.c | 34 | ||||
-rw-r--r-- | tests/00_syntax/04_statement_blocks | 8 | ||||
-rw-r--r-- | tests/00_syntax/07_embedded_single_line_comments | 3 | ||||
-rw-r--r-- | tests/00_syntax/08_embedded_multi_line_comments | 3 | ||||
-rw-r--r-- | tests/00_syntax/12_block_whitespace_control | 3 | ||||
-rw-r--r-- | tests/00_syntax/15_function_declarations | 8 | ||||
-rw-r--r-- | tests/00_syntax/16_for_loop | 9 | ||||
-rw-r--r-- | tests/00_syntax/17_while_loop | 3 | ||||
-rw-r--r-- | tests/00_syntax/18_if_condition | 6 | ||||
-rw-r--r-- | tests/01_arithmetic/04_inc_dec | 1 |
12 files changed, 65 insertions, 35 deletions
@@ -78,6 +78,8 @@ struct ut_state { uint8_t semicolon_emitted:1; uint8_t start_tag_seen:1; uint8_t srand_called:1; + uint8_t trim_blocks:1; + uint8_t lstrip_blocks:1; size_t off; enum ut_block_type blocktype; struct { @@ -58,6 +58,7 @@ static const struct token tokens[] = { { T_ASRIGHT, ">>=", 3 }, { T_LEXP, "{{-", 3 }, { T_REXP, "-}}", 3 }, + { T_LSTM, "{%+", 3 }, { T_LSTM, "{%-", 3 }, { T_RSTM, "-%}", 3 }, { T_AND, "&&", 2 }, @@ -731,9 +732,16 @@ ut_get_token(struct ut_state *s, const char *input, int *mlen) s->off += *mlen; /* strip whitespace before block */ - if (p[2] == '-') + if (p[2] == '-') { while (p > o && isspace(p[-1])) p--; + } + + /* lstrip */ + else if (s->lstrip_blocks && s->blocktype == UT_BLOCK_STATEMENT && p[2] != '+') { + while (p > o && p[-1] != '\n' && isspace(p[-1])) + p--; + } if (p == o) return 0; @@ -789,9 +797,6 @@ ut_get_token(struct ut_state *s, const char *input, int *mlen) *mlen = 0; } else { - s->semicolon_emitted = false; - s->blocktype = UT_BLOCK_NONE; - /* strip whitespace after block */ if (*p == '-') { while (isspace(p[3])) { @@ -799,6 +804,13 @@ ut_get_token(struct ut_state *s, const char *input, int *mlen) p++; } } + else if (s->blocktype == UT_BLOCK_STATEMENT && + s->trim_blocks && p[2] == '\n') { + (*mlen)++; + } + + s->semicolon_emitted = false; + s->blocktype = UT_BLOCK_NONE; } } @@ -38,11 +38,13 @@ print_usage(char *app) { printf( "== Usage ==\n\n" - " # %s [-d] {-i <file> | -s \"utpl script...\"}\n" + " # %s [-d] [-l] [-r] {-i <file> | -s \"utpl script...\"}\n" " -h, --help Print this help\n" " -i file Specify an utpl script to parse\n" " -s \"utpl script...\" Specify an utpl code fragment to parse\n" - " -d Instead of executing the script, dump the resulting AST as dot\n", + " -d Instead of executing the script, dump the resulting AST as dot\n" + " -l Do not strip leading block whitespace\n" + " -r Do not trim trailing block newlines\n", app); } @@ -136,9 +138,8 @@ static void dump(struct ut_state *s, uint32_t off, int level) { #endif /* NDEBUG */ static enum ut_error_type -parse(const char *source, bool dumponly) +parse(struct ut_state *state, const char *source, bool dumponly) { - struct ut_state *state = calloc(1, sizeof(*state)); enum ut_error_type err; char *msg; @@ -173,8 +174,9 @@ parse(const char *source, bool dumponly) int main(int argc, char **argv) { - size_t rlen, tlen = 0; + struct ut_state *state; bool dumponly = false; + size_t rlen, tlen = 0; char buf[1024], *tmp; char *source = NULL; FILE *input = NULL; @@ -186,7 +188,17 @@ main(int argc, char **argv) goto out; } - while ((opt = getopt(argc, argv, "dhi:s:")) != -1) + state = calloc(1, sizeof(*state)); + + if (!state) { + rv = UT_ERROR_OUT_OF_MEMORY; + goto out; + } + + state->lstrip_blocks = 1; + state->trim_blocks = 1; + + while ((opt = getopt(argc, argv, "dhlri:s:")) != -1) { switch (opt) { case 'h': @@ -208,6 +220,14 @@ main(int argc, char **argv) dumponly = true; break; + case 'l': + state->lstrip_blocks = 0; + break; + + case 'r': + state->trim_blocks = 0; + break; + case 's': source = optarg; break; @@ -240,7 +260,7 @@ main(int argc, char **argv) } } - rv = source ? parse(source, dumponly) : 0; + rv = source ? parse(state, source, dumponly) : 0; out: if (input && input != stdin) diff --git a/tests/00_syntax/04_statement_blocks b/tests/00_syntax/04_statement_blocks index faafd9a..920ed71 100644 --- a/tests/00_syntax/04_statement_blocks +++ b/tests/00_syntax/04_statement_blocks @@ -8,11 +8,13 @@ Alternatively print it: {% -- End -- -- Testcase -- -The result of 3 * 7 is {% print(3 * 7) %}. -A statement block may contain multiple statements: {% +The result of 3 * 7 is {%+ print(3 * 7) %}. +A statement block may contain multiple statements: {%+ print("Hello "); print("World"); %} + To escape the start tag, output it as string expression: {{ "{%" }} -Alternatively print it: {% print("{%") %} +Alternatively print it: {%+ print("{%") %} + -- End -- diff --git a/tests/00_syntax/07_embedded_single_line_comments b/tests/00_syntax/07_embedded_single_line_comments index 8c5fd4a..43f188c 100644 --- a/tests/00_syntax/07_embedded_single_line_comments +++ b/tests/00_syntax/07_embedded_single_line_comments @@ -11,10 +11,11 @@ Statement blocks may use C++ comments too: Test Another test. The result of 5 + 9 is {{ // The block end tag is ignored: }} // And the expression block continues here! 5 + 9 }}. -Statement blocks may use C++ comments too: {% +Statement blocks may use C++ comments too: {%+ print("Test"); // A comment. // Another comment. print(" Another test."); %} + -- End -- diff --git a/tests/00_syntax/08_embedded_multi_line_comments b/tests/00_syntax/08_embedded_multi_line_comments index b27554f..75aba5f 100644 --- a/tests/00_syntax/08_embedded_multi_line_comments +++ b/tests/00_syntax/08_embedded_multi_line_comments @@ -12,7 +12,7 @@ Statement blocks may use C comments too: Test Another test. The final test. -- Testcase -- The result of 12 - 4 is {{ /* A comment before */ 12 - /* or even within */ 4 /* or after an expression */ }}. -Statement blocks may use C comments too: {% +Statement blocks may use C comments too: {%+ print("Test"); /* A comment. */ /* Another comment. */ @@ -20,4 +20,5 @@ Statement blocks may use C comments too: {% print(/* A comment within */ " The final test."); %} + -- End -- diff --git a/tests/00_syntax/12_block_whitespace_control b/tests/00_syntax/12_block_whitespace_control index 23f7380..911171c 100644 --- a/tests/00_syntax/12_block_whitespace_control +++ b/tests/00_syntax/12_block_whitespace_control @@ -22,7 +22,7 @@ expected too.This is after the block. -- Testcase -- Whitespace control applies to all block types: Comment before: | {#- test #} |, after: | {#- test #} |, both: | {#- test -#} | -Statement before: | {%- print("test") %} |, after: | {% print("test") -%} |, both: | {%- print("test") -%} | +Statement before: | {%- print("test") %} |, after: | {%+ print("test") -%} |, both: | {%- print("test") -%} | Expression before: | {{- "test" }} |, after: | {{ "test" -}} |, both: | {{- "test" -}} | By default whitespace {{ "around a block" }} is retained. @@ -37,6 +37,7 @@ Stripping works across multiple lines as well: print("test") %} + Likewise, stripping over multiple lines of trailing whitespace works as expected too. diff --git a/tests/00_syntax/15_function_declarations b/tests/00_syntax/15_function_declarations index 846f379..cb391a4 100644 --- a/tests/00_syntax/15_function_declarations +++ b/tests/00_syntax/15_function_declarations @@ -17,9 +17,9 @@ function() { ... } function test_fn(a, b) { ... } function test2_fn(a, b) { ... } - A function declaration using the alternative syntax: The function was called with arguments 123 and 456. + -- End -- -- Testcase -- @@ -50,10 +50,8 @@ The function was called with arguments 123 and 456. %} A function declaration using the alternative syntax: - -{%- function test3_fn(a, b): %} +{% function test3_fn(a, b): %} The function was called with arguments {{ a }} and {{ b }}. -{%- endfunction -%} - +{% endfunction %} {{ test3_fn(123, 456) }} -- End -- diff --git a/tests/00_syntax/16_for_loop b/tests/00_syntax/16_for_loop index 61e86a1..4c233bc 100644 --- a/tests/00_syntax/16_for_loop +++ b/tests/00_syntax/16_for_loop @@ -20,7 +20,6 @@ Iteration 7 Iteration 8 Iteration 9 - If the loop body consists of only one statement, the curly braces may be omitted: Iteration 0 @@ -34,7 +33,6 @@ Iteration 7 Iteration 8 Iteration 9 - Any of the init-, test- and increment expressions may be omitted. Loop without initialization statement: @@ -42,30 +40,25 @@ Iteration null Iteration 1 Iteration 2 - Loop without test statement: Iteration 0 Iteration 1 Iteration 2 - Loop without init-, test- or increment statement: Iteration 1 Iteration 2 Iteration 3 - For-in loop enumerating object properties: Key: foo Key: bar - For-in loop enumerating array items: Item: one Item: two Item: three - A counting for-loop using the alternative syntax: Iteration 0 Iteration 1 @@ -78,12 +71,10 @@ Iteration 7 Iteration 8 Iteration 9 - A for-in loop using the alternative syntax: Item 123 Item 456 Item 789 - -- End -- -- Testcase -- diff --git a/tests/00_syntax/17_while_loop b/tests/00_syntax/17_while_loop index 6d6dc4a..4dfaccc 100644 --- a/tests/00_syntax/17_while_loop +++ b/tests/00_syntax/17_while_loop @@ -18,7 +18,6 @@ Iteration 7 Iteration 8 Iteration 9 - If the loop body consists of only one statement, the curly braces may be omitted: Iteration 0 @@ -32,7 +31,6 @@ Iteration 7 Iteration 8 Iteration 9 - A counting while-loop using the alternative syntax: Iteration null Iteration 1 @@ -44,7 +42,6 @@ Iteration 6 Iteration 7 Iteration 8 Iteration 9 - -- End -- -- Testcase -- diff --git a/tests/00_syntax/18_if_condition b/tests/00_syntax/18_if_condition index 0148466..9601f11 100644 --- a/tests/00_syntax/18_if_condition +++ b/tests/00_syntax/18_if_condition @@ -40,6 +40,7 @@ This should print "one": } %} + This should print "two": {% x = 1; @@ -52,6 +53,7 @@ This should print "two": } %} + Multiple conditions can be used by chaining if/else statements: {% x = 2; @@ -70,6 +72,7 @@ Multiple conditions can be used by chaining if/else statements: } %} + If the conditional block consists of only one statement, the curly braces may be omitted: {% @@ -81,6 +84,7 @@ braces may be omitted: print("two"); %} + An if-condition using the alternative syntax: {% if (x == 1): -%} Variable x was set to one. @@ -88,6 +92,7 @@ Variable x was set to one. Variable x has another value. {% endif %} + Ternary expressions function similar to if/else statements but only allow for a single expression in the true and false branches: {% @@ -96,4 +101,5 @@ only allow for a single expression in the true and false branches: print(s); %} + -- End -- diff --git a/tests/01_arithmetic/04_inc_dec b/tests/01_arithmetic/04_inc_dec index 6647ced..5a048fe 100644 --- a/tests/01_arithmetic/04_inc_dec +++ b/tests/01_arithmetic/04_inc_dec @@ -28,7 +28,6 @@ Incrementing a non-numeric value will convert it to a number: 3.5 2 NaN - -- End -- -- Testcase -- |