aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDanny van Kooten <dannyvankooten@users.noreply.github.com>2020-03-12 16:41:28 +0100
committerDanny van Kooten <dannyvankooten@users.noreply.github.com>2020-03-12 16:41:28 +0100
commit9acd91d41469ed4024e3a8aa85ef1fb2eec909bd (patch)
tree420f8b6b409f452815029e5de2db1535723bf26c
parent791e03d8199fa1177f970f45a8a436912d229d1c (diff)
downloadunja-9acd91d41469ed4024e3a8aa85ef1fb2eec909bd.tar.gz
unja-9acd91d41469ed4024e3a8aa85ef1fb2eec909bd.zip
dot notation in hashmaps
-rw-r--r--src/template.c36
-rw-r--r--tests/test.h3
-rw-r--r--tests/test_template.c23
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 : <symbol>\".\"?<symbol>? ;"
" var_open : /\{{2} ?/ ;"
" var_close : / ?}{2}/ ;"
- " var : <var_open> <symbol> <var_close> ;"
+ " var : <var_open> <symbols> <var_close> ;"
" block_open: /\{\% ?/ ;"
" block_close: / ?\%}/ ;"
- " for : <block_open> \"for \" <symbol> \" in \" <symbol> <block_close> <body> <block_open> \"endfor\" <block_close> ;"
+ " for : <block_open> \"for \" <symbol> \" in \" <symbols> <block_close> <body> <block_open> \"endfor\" <block_close> ;"
" text : /[^{][^{%]*/ ;"
" content : <var> | <for> | <text>;"
" body : <content>* ;"
" template : /^/ <body> /$/ ;",
- 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