aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDanny van Kooten <dannyvankooten@users.noreply.github.com>2020-03-20 12:03:04 +0100
committerDanny van Kooten <dannyvankooten@users.noreply.github.com>2020-03-20 12:03:04 +0100
commit306f057f985260d334a5e54405273f910120523c (patch)
tree30dda3b78e5c118404fec1755b439cf2524998b1
parent6400b4ecce681d698e47a1744c2f2f8f847476d9 (diff)
downloadunja-306f057f985260d334a5e54405273f910120523c.tar.gz
unja-306f057f985260d334a5e54405273f910120523c.zip
fix precedence for comparison operators & add '==', '!=', '>=', '<='
-rw-r--r--src/template.c48
-rw-r--r--tests/test_template.c140
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();