aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/template.c84
-rw-r--r--tests/test_template.c1
2 files changed, 54 insertions, 31 deletions
diff --git a/src/template.c b/src/template.c
index 58874e4..3d336d0 100644
--- a/src/template.c
+++ b/src/template.c
@@ -80,6 +80,8 @@ mpc_parser_t *parser_init() {
mpc_parser_t *statement_extends = mpc_new("extends");
mpc_parser_t *body = mpc_new("body");
mpc_parser_t *content = mpc_new("content");
+ mpc_parser_t *factor = mpc_new("factor");
+ mpc_parser_t *term = mpc_new("term");
template = mpc_new("template");
mpca_lang(MPCA_LANG_WHITESPACE_SENSITIVE,
@@ -89,8 +91,10 @@ mpc_parser_t *parser_init() {
" text : /[^{][^{%#]*/;"
" string : '\"' /([^\"])*/ '\"' ;"
" op : '+' | '-' | '*' | '/' | '>' | '<';"
- " expression: (<symbol> | <number> | <string>) (<spaces> <op> <spaces> (<symbol> | <number> | <string>))* ;"
- " print : (/{{2}-? */) <expression> / *-?}}/ ;"
+ " factor : '(' <expression> ')' | <symbol> | <number> | <string> ;"
+ " term : <spaces> <factor> <spaces> (('*' | '/' | '%') <spaces> <factor> <spaces>)* ;"
+ " expression: <term> (('+' | '-') <term>)* ;"
+ " print : /{{2}-?/ <expression> /-?}}/ ;"
" comment : \"{#\" /[^#][^#}]*/ \"#}\" ;"
" statement_open: /{\%-? */;"
" statement_close: / *-?\%}/;"
@@ -103,6 +107,7 @@ mpc_parser_t *parser_init() {
" body : <content>* ;"
" template : /^/ <body> /$/ ;",
spaces,
+ factor, term,
symbol,
op,
text,
@@ -353,47 +358,64 @@ struct unja_object *eval_expression_value(mpc_ast_t* node, struct context *ctx)
return &null_object;
}
+struct unja_object *eval_infix_expression(struct unja_object *left, char *op, struct unja_object *right) {
+ /* if operator is + and either left or right node is of type string: concat */
+ if (op[0] == '+' && (left->type == OBJ_STRING && right->type == OBJ_STRING)) {
+ struct unja_object *result = make_string_object(left->string, right->string);
+ object_free(left);
+ object_free(right);
+ return result;
+ }
+
+ int result;
+ switch (op[0]) {
+ 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 '<': result = object_to_int(left) < object_to_int(right); break;
+ }
+
+ object_free(left);
+ object_free(right);
+ return make_int_object(result);
+}
struct unja_object *eval_expression(mpc_ast_t* expr, struct context *ctx) {
- if (expr->children_num >= 4 && strstr(expr->children[2]->tag, "op")) {
- mpc_ast_t *left_node = expr->children[0];
- mpc_ast_t *op = expr->children[2];
- mpc_ast_t *right_node = expr->children[4];
- struct unja_object *left = eval_expression_value(left_node, ctx);
- struct unja_object *right = eval_expression_value(right_node, ctx);
+ /* singular term */
+ if (strstr(expr->tag, "term")) {
+ return eval_expression_value(expr->children[1], ctx);
+ }
- /* if operator is + and either left or right node is of type string: concat */
- if (op->contents[0] == '+' && (left->type == OBJ_STRING && right->type == OBJ_STRING)) {
- struct unja_object *result = make_string_object(left->string, right->string);
- object_free(left);
- object_free(right);
- return result;
- }
-
- /* eval int infix expression */
- int result;
- switch (op->contents[0]) {
- 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 '<': result = object_to_int(left) < object_to_int(right); break;
- }
+ /* otherwise: with operator */
+ int offset = 0;
+ struct object *result;
+ mpc_ast_t *left_node = expr->children[0]->children[1];
+ struct unja_object *left = eval_expression_value(left_node, ctx);
- object_free(left);
- object_free(right);
- return make_int_object(result);
+ while (offset < expr->children_num - 1) {
+ mpc_ast_t *op = expr->children[offset+1];
+ mpc_ast_t *right_node = expr->children[offset+2]->children[1];
+ struct unja_object *right = eval_expression_value(right_node, ctx);
+ result = eval_infix_expression(left, op->contents, right);
+
+ left = result;
+ offset += 2;
}
- mpc_ast_t *left_node = expr;
- return eval_expression_value(left_node, ctx);
+ return result;
+
}
int eval(struct buffer *buf, mpc_ast_t* t, struct context *ctx) {
static int trim_whitespace = 0;
+ #if DEBUG
+ printf("Node: %s = %s\n", t->tag, t->contents);
+ #endif
+
// maybe eat whitespace going backward
if (t->children_num > 0 && strstr(t->children[0]->contents, "-")) {
buf->string = trim_trailing_whitespace(buf->string);
diff --git a/tests/test_template.c b/tests/test_template.c
index 9e23ca2..cb23dbf 100644
--- a/tests/test_template.c
+++ b/tests/test_template.c
@@ -67,6 +67,7 @@ TEST(expr_add) {
{"{{ 5 + foo }}.", "15."},
{"{{ \"foo\" + \"bar\" }}", "foobar"},
{"{{ \"Hello \" + name }}", "Hello Danny"},
+ {"{{ 5 + 5 + 5 }}.", "15."},
{"{{5+5}}", "10"},
{"{{ 5+5}}", "10"},
{"{{ 5 +5}}", "10"},