diff options
author | Danny van Kooten <dannyvankooten@users.noreply.github.com> | 2020-03-20 12:03:04 +0100 |
---|---|---|
committer | Danny van Kooten <dannyvankooten@users.noreply.github.com> | 2020-03-20 12:03:04 +0100 |
commit | 306f057f985260d334a5e54405273f910120523c (patch) | |
tree | 30dda3b78e5c118404fec1755b439cf2524998b1 | |
parent | 6400b4ecce681d698e47a1744c2f2f8f847476d9 (diff) | |
download | unja-306f057f985260d334a5e54405273f910120523c.tar.gz unja-306f057f985260d334a5e54405273f910120523c.zip |
fix precedence for comparison operators & add '==', '!=', '>=', '<='
-rw-r--r-- | src/template.c | 48 | ||||
-rw-r--r-- | tests/test_template.c | 140 |
2 files changed, 150 insertions, 38 deletions
diff --git a/src/template.c b/src/template.c index 410ead7..9e739bc 100644 --- a/src/template.c +++ b/src/template.c @@ -68,7 +68,8 @@ mpc_parser_t *parser_init() { mpc_parser_t *string = mpc_new("string"); mpc_parser_t *text = mpc_new("text"); mpc_parser_t *print = mpc_new("print"); - mpc_parser_t *expression = mpc_new("expression"); + mpc_parser_t *lexp = mpc_new("lexp"); + mpc_parser_t *exp = mpc_new("expression"); mpc_parser_t *comment = mpc_new("comment"); mpc_parser_t *statement = mpc_new("statement"); mpc_parser_t *statement_open = mpc_new("statement_open"); @@ -91,9 +92,15 @@ mpc_parser_t *parser_init() { " string : '\"' /([^\"])*/ '\"' ;" " factor : '(' <expression> ')' | <symbol> | <number> | <string> ;" " term : <factor> (<spaces> ('*' | '/' | '%') <spaces> <factor>)* ;" - /* TODO: move > and < to lower predence grammar group */ - " expression: <term> (<spaces> ('+' | '-' | '>' | '<') <spaces> <term>)* ;" - " print : /{{2}-? */ <expression> / *-?}}/ ;" + " lexp : <term> (<spaces> ('+' | '-') <spaces> <term>)* ;" + " expression: <lexp> <spaces> '>' <spaces> <lexp> " + " | <lexp> <spaces> '<' <spaces> <lexp> " + " | <lexp> <spaces> \">=\" <spaces> <lexp> " + " | <lexp> <spaces> \"<=\" <spaces> <lexp> " + " | <lexp> <spaces> \"!=\" <spaces> <lexp> " + " | <lexp> <spaces> \"==\" <spaces> <lexp> " + " | <lexp> ;" + " print : /{{2}-? */ <lexp> / *-?}}/ ;" " comment : \"{#\" /[^#][^#}]*/ \"#}\" ;" " statement_open: /{\%-? */;" " statement_close: / *-?\%}/;" @@ -106,13 +113,15 @@ mpc_parser_t *parser_init() { " body : <content>* ;" " template : /^/ <body> /$/ ;", spaces, - factor, term, + factor, + term, symbol, text, number, string, print, - expression, + lexp, + exp, comment, statement_open, statement_close, @@ -133,6 +142,7 @@ mpc_ast_t *parse(char *tmpl) { mpc_result_t r; if (!mpc_parse("input", tmpl, parser, &r)) { + puts(tmpl); mpc_err_print(r.error); mpc_err_delete(r.error); return NULL; @@ -371,8 +381,30 @@ struct unja_object *eval_infix_expression(struct unja_object *left, char *op, st case '-': result = object_to_int(left) - object_to_int(right); break; case '/': result = object_to_int(left) / object_to_int(right); break; case '*': result = object_to_int(left) * object_to_int(right); break; - case '>': result = object_to_int(left) > object_to_int(right); break; - case '<': result = object_to_int(left) < object_to_int(right); break; + case '>': + if (op[1] == '=') { + result = object_to_int(left) >= object_to_int(right); + } else { + result = object_to_int(left) > object_to_int(right); + } + break; + case '<': + if (op[1] == '=') { + result = object_to_int(left) <= object_to_int(right); + } else { + result = object_to_int(left) < object_to_int(right); + } + break; + case '!': + if (op[1] == '=') { + result = object_to_int(left) != object_to_int(right); + } + break; + case '=': + if (op[1] == '=') { + result = object_to_int(left) == object_to_int(right); + } + break; } object_free(left); diff --git a/tests/test_template.c b/tests/test_template.c index 4521d6c..039e993 100644 --- a/tests/test_template.c +++ b/tests/test_template.c @@ -131,30 +131,6 @@ TEST(expr_multiply) { free(output); } -TEST(expr_gt) { - char *input = "Hello {{ 5 > 4 }}."; - char *output = template_string(input, NULL); - assert_str(output, "Hello 1."); - free(output); - - input = "Hello {{ 5 > 6 }}."; - output = template_string(input, NULL); - assert_str(output, "Hello 0."); - free(output); -} - -TEST(expr_lt) { - char *input = "Hello {{ 5 < 4 }}."; - char *output = template_string(input, NULL); - assert_str(output, "Hello 0."); - free(output); - - input = "Hello {{ 4 < 5 }}."; - output = template_string(input, NULL); - assert_str(output, "Hello 1."); - free(output); -} - TEST(expr_whitespace) { char *input = "Hello \n{{- \"world\" -}}\n."; char *output = template_string(input, NULL); @@ -227,12 +203,13 @@ TEST(if_block) { char *input; char *expected_output; } tests[] = { - {"{% if 5 > 10 %}1{% endif %}.", "."}, - {"{% if 10 > 5 %}1{% endif %}.", "1."}, - {"{% if foobar %}1{% endif %}.", "."}, - {"{% if name %}1{% endif %}.", "1."}, - {"{% if age > 10 %}1{% endif %}.", "1."}, - {"{% if 10+1 > 10 %}1{% endif %}.", "1."}, + {"{% if 5 > 10 %}1{% endif %}", ""}, + {"{% if 10 > 5 %}1{% endif %}", "1"}, + {"{% if foobar %}1{% endif %}", ""}, + {"{% if name %}1{% endif %}", "1"}, + {"{% if age > 10 %}1{% endif %}", "1"}, + {"{% if 10 + 1 > 10 %}1{% endif %}", "1"}, + {"{% if 6 > 10 - 5 %}1{% endif %}", "1"}, }; struct hashmap *ctx = hashmap_new(); @@ -247,6 +224,107 @@ TEST(if_block) { hashmap_free(ctx); } +TEST(expr_gt) { + struct { + char *input; + char *expected_output; + } tests[] = { + {"{% if 10 > 9 %}1{% endif %}", "1"}, + {"{% if 10 > 10 %}1{% endif %}", ""}, + {"{% if 10 > 11 %}1{% endif %}", ""}, + }; + + for (int i=0; i < ARRAY_SIZE(tests); i++) { + char *output = template_string(tests[i].input, NULL); + assert_str(output, tests[i].expected_output); + free(output); + } +} + +TEST(expr_gte) { + struct { + char *input; + char *expected_output; + } tests[] = { + {"{% if 10 >= 9 %}1{% endif %}", "1"}, + {"{% if 10 >= 10 %}1{% endif %}", "1"}, + {"{% if 10 >= 11 %}1{% endif %}", ""}, + }; + + for (int i=0; i < ARRAY_SIZE(tests); i++) { + char *output = template_string(tests[i].input, NULL); + assert_str(output, tests[i].expected_output); + free(output); + } +} + +TEST(expr_lt) { + struct { + char *input; + char *expected_output; + } tests[] = { + {"{% if 10 < 9 %}1{% endif %}", ""}, + {"{% if 10 < 10 %}1{% endif %}", ""}, + {"{% if 10 < 11 %}1{% endif %}", "1"}, + }; + + for (int i=0; i < ARRAY_SIZE(tests); i++) { + char *output = template_string(tests[i].input, NULL); + assert_str(output, tests[i].expected_output); + free(output); + } +} + +TEST(expr_lte) { + struct { + char *input; + char *expected_output; + } tests[] = { + {"{% if 10 <= 9 %}1{% endif %}", ""}, + {"{% if 10 <= 10 %}1{% endif %}", "1"}, + {"{% if 10 <= 11 %}1{% endif %}", "1"}, + }; + + for (int i=0; i < ARRAY_SIZE(tests); i++) { + char *output = template_string(tests[i].input, NULL); + assert_str(output, tests[i].expected_output); + free(output); + } +} + + +TEST(expr_eq) { + struct { + char *input; + char *expected_output; + } tests[] = { + {"{% if 10 == 20 %}1{% endif %}", ""}, + {"{% if 10 == 10 %}1{% endif %}", "1"}, + }; + + for (int i=0; i < ARRAY_SIZE(tests); i++) { + char *output = template_string(tests[i].input, NULL); + assert_str(output, tests[i].expected_output); + free(output); + } +} + +TEST(expr_not_eq) { + struct { + char *input; + char *expected_output; + } tests[] = { + {"{% if 10 != 20 %}1{% endif %}", "1"}, + {"{% if 10 != 10 %}1{% endif %}", ""}, + }; + + for (int i=0; i < ARRAY_SIZE(tests); i++) { + char *output = template_string(tests[i].input, NULL); + assert_str(output, tests[i].expected_output); + free(output); + } +} + TEST(if_block_whitespace) { char *input = "\n{%- if 10 > 5 -%}\nOK\n{%- endif -%}\n"; char *output = template_string(input, NULL); @@ -264,6 +342,8 @@ TEST(if_else_block) { {"{% if foobar %}1{% else %}2{% endif %}", "2"}, {"{% if name %}1{% else %}2{% endif %}", "1"}, {"{% if age < 10 %}1{% else %}2{% endif %}", "2"}, + {"{% if age + 5 < 10 %}1{% else %}2{% endif %}", "2"}, + {"{% if age + 5 > 29 %}1{% else %}2{% endif %}", "1"}, }; struct hashmap *ctx = hashmap_new(); |