summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJo-Philipp Wich <jo@mein.io>2020-09-10 18:37:24 +0200
committerJo-Philipp Wich <jo@mein.io>2020-09-10 18:37:24 +0200
commit9ea4368ff1e4842286e0e7a6aec58a2c2c799d5b (patch)
tree47d31fa6d686dd50220edfa505fcc21ce6c860fe
parent39164c57d893b02f9a253c661abc2459bcd57e5c (diff)
treewide: implement default lstrip_blocks and trim_blocks behaviour
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
-rw-r--r--ast.h2
-rw-r--r--lexer.c20
-rw-r--r--main.c34
-rw-r--r--tests/00_syntax/04_statement_blocks8
-rw-r--r--tests/00_syntax/07_embedded_single_line_comments3
-rw-r--r--tests/00_syntax/08_embedded_multi_line_comments3
-rw-r--r--tests/00_syntax/12_block_whitespace_control3
-rw-r--r--tests/00_syntax/15_function_declarations8
-rw-r--r--tests/00_syntax/16_for_loop9
-rw-r--r--tests/00_syntax/17_while_loop3
-rw-r--r--tests/00_syntax/18_if_condition6
-rw-r--r--tests/01_arithmetic/04_inc_dec1
12 files changed, 65 insertions, 35 deletions
diff --git a/ast.h b/ast.h
index 9840ad4..4c5318c 100644
--- a/ast.h
+++ b/ast.h
@@ -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 {
diff --git a/lexer.c b/lexer.c
index 0220421..0ce9643 100644
--- a/lexer.c
+++ b/lexer.c
@@ -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;
}
}
diff --git a/main.c b/main.c
index 334d66b..68b39c1 100644
--- a/main.c
+++ b/main.c
@@ -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 --