From 9acd91d41469ed4024e3a8aa85ef1fb2eec909bd Mon Sep 17 00:00:00 2001 From: Danny van Kooten Date: Thu, 12 Mar 2020 16:41:28 +0100 Subject: dot notation in hashmaps --- src/template.c | 36 +++++++++++++++++++++++++++++------- tests/test.h | 3 ++- tests/test_template.c | 23 ++++++++++++++++++----- 3 files changed, 49 insertions(+), 13 deletions(-) diff --git a/src/template.c b/src/template.c index e5296c8..db0128d 100644 --- a/src/template.c +++ b/src/template.c @@ -27,10 +27,26 @@ char *read_file(char *filename) { } int eval(char *dest, mpc_ast_t* t, struct hashmap *ctx) { - printf("%s: %s\n", t->tag, t->contents); - if (strstr(t->tag, "content|var")) { - char *value = (char *) hashmap_get(ctx, t->children[1]->contents); + char *value = NULL; + + // TODO: Optimize this so we can use it for 1..n keys + if (t->children[1]->children_num == 0) { + char *key = t->children[1]->contents; + value = hashmap_get(ctx, key); + } else { + char *key = t->children[1]->children[0]->contents; + ctx = hashmap_get(ctx, key); + if (ctx == NULL) { + // TODO: Handle unexisting keys + return 1; + } + + char *subkey = t->children[1]->children[2]->contents; + value = hashmap_get(ctx, subkey); + } + + // TODO: Handle unexisting keys if (value == NULL) { return 1; } @@ -40,6 +56,7 @@ int eval(char *dest, mpc_ast_t* t, struct hashmap *ctx) { if (strstr(t->tag, "content|for")) { char *tmp_key = t->children[2]->contents; + // TODO: Handle dot notation here. char *iterator_key = t->children[4]->contents; struct vector *list = hashmap_get(ctx, iterator_key); for (int i=0; i < list->size; i++) { @@ -63,6 +80,7 @@ int eval(char *dest, mpc_ast_t* t, struct hashmap *ctx) { mpc_parser_t *parser_init() { mpc_parser_t *Symbol = mpc_new("symbol"); + mpc_parser_t *Symbols = mpc_new("symbols"); mpc_parser_t *Text = mpc_new("text"); mpc_parser_t *Var_Open = mpc_new("var_open"); mpc_parser_t *Var_Close = mpc_new("var_close"); @@ -74,18 +92,19 @@ mpc_parser_t *parser_init() { mpc_parser_t *Content = mpc_new("content"); mpc_parser_t *Template = mpc_new("template"); mpca_lang(MPCA_LANG_WHITESPACE_SENSITIVE, - " symbol : /[a-zA-Z._]+/ ;" + " symbol : /[a-zA-Z_]+/ ;" + " symbols : \".\"?? ;" " var_open : /\{{2} ?/ ;" " var_close : / ?}{2}/ ;" - " var : ;" + " var : ;" " block_open: /\{\% ?/ ;" " block_close: / ?\%}/ ;" - " for : \"for \" \" in \" \"endfor\" ;" + " for : \"for \" \" in \" \"endfor\" ;" " text : /[^{][^{%]*/ ;" " content : | | ;" " body : * ;" " template : /^/ /$/ ;", - Symbol, Var_Open, Var_Close, Var, Block_Open, Block_Close, For, Text, Content, Body, Template, NULL); + Symbol, Symbols, Var_Open, Var_Close, Var, Block_Open, Block_Close, For, Text, Content, Body, Template, NULL); return Template; } @@ -99,7 +118,10 @@ char *template(char *tmpl, struct hashmap *ctx) { return NULL; } + printf("Template: %s\n", tmpl); + printf("AST: "); mpc_ast_print(r.output); + printf("\n"); // FIXME: Allocate precisely char *output = malloc(strlen(tmpl) * 2); diff --git a/tests/test.h b/tests/test.h index d0c0e0a..5c76448 100644 --- a/tests/test.h +++ b/tests/test.h @@ -6,7 +6,7 @@ #define START_TESTS int main() { #define END_TESTS } #define TEST(name) strcpy(current_test, #name); -#define assert_str(actual, expected) _assert(strcmp(actual, expected) == 0, __FILE__, __LINE__, "invalid string: expected %s, got %s", expected, actual) +#define assert_str(actual, expected) _assert(actual != NULL && strcmp(actual, expected) == 0, __FILE__, __LINE__, "invalid string: expected %s, got %s", expected, actual) #define assert(assertion, format, ...) _assert(assertion, __FILE__, __LINE__, format, ##__VA_ARGS__) /* used to store the running test name */ @@ -25,4 +25,5 @@ static void _assert(int assertion, const char filename[64], const int line, char vprintf(format, args); va_end(args); printf("\n"); + exit(1); } \ No newline at end of file diff --git a/tests/test_template.c b/tests/test_template.c index 55747e7..ac78677 100644 --- a/tests/test_template.c +++ b/tests/test_template.c @@ -10,7 +10,7 @@ TEST(text_only) { free(output); } -TEST(text_with_var) { +TEST(var) { char *input = "Hello {{name}}."; struct hashmap *ctx = hashmap_new(); hashmap_insert(ctx, "name", "world"); @@ -20,7 +20,7 @@ TEST(text_with_var) { free(output); } -TEST(text_multiline) { +TEST(multiline) { char *input = "Hello {{name}}.\nL2"; struct hashmap *ctx = hashmap_new(); hashmap_insert(ctx, "name", "world"); @@ -39,13 +39,26 @@ TEST(for_block) { vector_push(numbers, "2"); vector_push(numbers, "3"); hashmap_insert(ctx, "numbers", numbers); - + char *output = template(input, ctx); assert_str(output, "1, 2, 3, "); - vector_free(numbers); hashmap_free(ctx); free(output); } -END_TESTS \ No newline at end of file +TEST(var_dot_notation) { + char *input = "Hello {{user.name}}!"; + struct hashmap *user = hashmap_new(); + hashmap_insert(user, "name", "Danny"); + + struct hashmap *ctx = hashmap_new(); + hashmap_insert(ctx, "user", user); + + char *output = template(input, ctx); + assert_str(output, "Hello Danny!"); + hashmap_free(ctx); + free(output); +} + +END_TESTS -- cgit v1.2.3