diff options
author | Danny van Kooten <dannyvankooten@users.noreply.github.com> | 2020-03-18 14:55:59 +0100 |
---|---|---|
committer | Danny van Kooten <dannyvankooten@users.noreply.github.com> | 2020-03-18 14:55:59 +0100 |
commit | a13b511a582e0414476b810d2a0096dae088ee78 (patch) | |
tree | 2c6fb9dfea7807239b00703dd1a5878d63c5db1f /src | |
parent | 379219bbe4a7843bb32ea6dc7eca375105f2a909 (diff) | |
download | unja-a13b511a582e0414476b810d2a0096dae088ee78.tar.gz unja-a13b511a582e0414476b810d2a0096dae088ee78.zip |
inheritance working for depth 1
Diffstat (limited to 'src')
-rw-r--r-- | src/template.c | 111 |
1 files changed, 71 insertions, 40 deletions
diff --git a/src/template.c b/src/template.c index d3066c3..cb2ad7b 100644 --- a/src/template.c +++ b/src/template.c @@ -61,6 +61,7 @@ mpc_parser_t *parser_init() { return template; } + mpc_parser_t *spaces = mpc_new("spaces"); mpc_parser_t *symbol = mpc_new("symbol"); mpc_parser_t *number = mpc_new("number"); mpc_parser_t *string = mpc_new("string"); @@ -78,19 +79,21 @@ 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"); + template = mpc_new("template"); - mpca_lang(MPCA_LANG_DEFAULT, + mpca_lang(MPCA_LANG_WHITESPACE_SENSITIVE, + " spaces : (' ')*;" " symbol : /[a-zA-Z][a-zA-Z0-9_.]*/ ;" " number : /[0-9]+/ ;" + " text : /[^{][^{%#]*/;" " string : '\"' /([^\"])*/ '\"' ;" " op : '+' | '-' | '*' | '/' | '>' | '<';" - " text : /[^{][^{%#]*/ ;" - " expression: (<symbol> | <number> | <string>) (<op> (<symbol> | <number> | <string>))* ;" - " print : \"{{\" /-? */ <expression> / *-?/ \"}}\" ;" + " expression: (<symbol> | <number> | <string>) (<spaces> <op> <spaces> (<symbol> | <number> | <string>))* ;" + " print : (/{{2}-? */) <expression> / *-?}}/ ;" " comment : \"{#\" /[^#][^#}]*/ \"#}\" ;" - " statement_open: \"{%\" /-? */;" - " statement_close: / *-?/ \"%}\";" - " for : <statement_open> \"for \" <symbol> \"in\" <symbol> <statement_close> <body> <statement_open> \"endfor\" <statement_close> ;" + " statement_open: /{\%-? */;" + " statement_close: / *-?\%}/;" + " for : <statement_open> \"for \" <symbol> \" in \" <symbol> <statement_close> <body> <statement_open> \"endfor\" <statement_close> ;" " block : <statement_open> \"block \" <symbol> <statement_close> <body> <statement_open> \"endblock\" <statement_close>;" " extends : <statement_open> \"extends \" <string> <statement_close>;" " if : <statement_open> \"if \" <expression> <statement_close> <body> (<statement_open> \"else\" <statement_close> <body>)? <statement_open> \"endif\" <statement_close> ;" @@ -98,13 +101,14 @@ mpc_parser_t *parser_init() { " content : <print> | <statement> | <text> | <comment>;" " body : <content>* ;" " template : /^/ <body> /$/ ;", + spaces, symbol, op, + text, number, string, print, expression, - text, comment, statement_open, statement_close, @@ -115,8 +119,8 @@ mpc_parser_t *parser_init() { statement_extends, content, body, - template, - NULL); + template); + return template; } @@ -142,6 +146,8 @@ struct hashmap *find_blocks_in_ast(mpc_ast_t *node, struct hashmap *map) { for (int i=0; i < node->children_num; i++) { find_blocks_in_ast(node->children[i], map); } + + return map; } struct env *env_new(char *dirname) { @@ -298,15 +304,21 @@ int object_is_truthy(struct unja_object *obj) { return 0; } -struct unja_object *eval_expression_value(mpc_ast_t* node, struct hashmap *ctx) { +struct context { + struct hashmap *vars; + struct env *env; + struct template *current_template; +}; + +struct unja_object *eval_expression_value(mpc_ast_t* node, struct context *ctx) { if (strstr(node->tag, "symbol|")) { - /* Return empty string if no context was passed. Should probably signal error here. */ - if (ctx == NULL) { + /* Return empty string if no vars were passed. Should probably signal error here. */ + if (ctx->vars == NULL) { return &null_object; } char *key = node->contents; - char *value = hashmap_resolve(ctx, key); + char *value = hashmap_resolve(ctx->vars, key); /* TODO: Handle unexisting symbols (returns NULL currently) */ if (value == NULL) { @@ -323,11 +335,11 @@ struct unja_object *eval_expression_value(mpc_ast_t* node, struct hashmap *ctx) } -struct unja_object *eval_expression(mpc_ast_t* expr, struct hashmap *ctx) { - if (expr->children_num >= 2 && strstr(expr->children[1]->tag, "op")) { +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[1]; - mpc_ast_t *right_node = expr->children[2]; + 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); @@ -360,36 +372,40 @@ struct unja_object *eval_expression(mpc_ast_t* expr, struct hashmap *ctx) { return eval_expression_value(left_node, ctx); } -int eval(struct buffer *buf, mpc_ast_t* t, struct hashmap *ctx) { +int eval(struct buffer *buf, mpc_ast_t* t, struct context *ctx) { static int trim_whitespace = 0; - - if (strstr(t->tag, "content|statement|extends")) { - char *template_name = t->children[2]->children[1]->contents; - // TODO: Render given template instead - // but replace blocks with blocks in current template - return 0; + // maybe eat whitespace going backward + if (t->children_num > 0 && strstr(t->children[0]->contents, "{{-")) { + buf->string = trim_trailing_whitespace(buf->string); } - if (strstr(t->tag, "content|statement|block")) { char *block_name = t->children[2]->contents; + + // find block in "lowest" template + struct template *templ = ctx->current_template; + mpc_ast_t *block = hashmap_get(templ->blocks, block_name); + if (block) { + return eval(buf, block->children[4], ctx); + } + + /* TODO: Keep looking for block in parent templates */ + + // just render this block if it wasn't found in any of the lower templates return eval(buf, t->children[4], ctx); } // eval print statement if (strstr(t->tag, "content|print")) { - // maybe eat whitespace going backward - if (strstr(t->children[1]->contents, "-")) { - buf->string = trim_trailing_whitespace(buf->string); - } + /* set flag for next eval() to trim leading whitespace from text */ - if (strstr(t->children[3]->contents, "-")) { + if (strstr(t->children[2]->contents, "-}}")) { trim_whitespace = 1; } - mpc_ast_t *expr = t->children[2]; + mpc_ast_t *expr = t->children[1]; struct unja_object *obj = eval_expression(expr, ctx); eval_object(buf, obj); object_free(obj); @@ -399,9 +415,9 @@ int eval(struct buffer *buf, mpc_ast_t* t, struct hashmap *ctx) { if (strstr(t->tag, "content|statement|for")) { char *tmp_key = t->children[2]->contents; char *iterator_key = t->children[4]->contents; - struct vector *list = hashmap_resolve(ctx, iterator_key); + struct vector *list = hashmap_resolve(ctx->vars, iterator_key); for (int i=0; i < list->size; i++) { - hashmap_insert(ctx, tmp_key, list->values[i]); + hashmap_insert(ctx->vars, tmp_key, list->values[i]); eval(buf, t->children[6], ctx); } return 0; @@ -442,7 +458,8 @@ int eval(struct buffer *buf, mpc_ast_t* t, struct hashmap *ctx) { return 0; } -char *render_ast(mpc_ast_t *ast, struct hashmap *ctx) { + +char *render_ast(mpc_ast_t *ast, struct context *ctx) { #if DEBUG printf("AST: \n"); mpc_ast_print(ast); @@ -458,22 +475,36 @@ char *render_ast(mpc_ast_t *ast, struct hashmap *ctx) { return buf.string; } -char *template_string(char *tmpl, struct hashmap *ctx) { +char *template_string(char *tmpl, struct hashmap *vars) { #if DEBUG printf("Template: %s\n", tmpl); #endif - mpc_ast_t *ast = parse(tmpl); - char *output = render_ast(ast, ctx); + mpc_ast_t *ast = parse(tmpl); + struct context ctx; + ctx.vars = vars; + ctx.env = NULL; + ctx.current_template = NULL; + char *output = render_ast(ast, &ctx); mpc_ast_delete(ast); return output; } -char *template(struct env *env, char *template_name, struct hashmap *ctx) { +char *template(struct env *env, char *template_name, struct hashmap *vars) { struct template *t = hashmap_get(env->templates, template_name); #if DEBUG printf("Template name: %s\n", t->name); printf("Parent: %s\n", t->parent ? t->parent : "None"); #endif - return render_ast(t->ast, ctx); + struct context ctx; + ctx.vars = vars; + ctx.env = env; + ctx.current_template = t; + + // find root template + while (t->parent != NULL) { + t = hashmap_get(env->templates, t->parent); + } + + return render_ast(t->ast, &ctx); }
\ No newline at end of file |