feat: hmpl: section test passeeed
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
#include "hmpl.h"
|
#include "hmpl.h"
|
||||||
|
|
||||||
Json *eval_object(Arena *arena, const Json * const context, const char * const query) {
|
Json *eval_object(Arena *arena, const Json * const context, const char * const query) {
|
||||||
|
raise_debug("eval_object(%p, %s, %s)", arena, json_to_string(arena, context), query);
|
||||||
if (!context || !query) return NULL;
|
if (!context || !query) return NULL;
|
||||||
|
|
||||||
const Json *res = context;
|
const Json *res = context;
|
||||||
@@ -29,7 +30,7 @@ char *eval_string(Arena *arena, const Json * const context, const char * const q
|
|||||||
/* Modified: text is passed by reference so we can update it and free old allocations */
|
/* Modified: text is passed by reference so we can update it and free old allocations */
|
||||||
// {{[prefix]key}}
|
// {{[prefix]key}}
|
||||||
void hmpl_render_interpolation_tags(Arena *arena, char **text_ptr, const Json * const context, const char * const prefix) {
|
void hmpl_render_interpolation_tags(Arena *arena, char **text_ptr, const Json * const context, const char * const prefix) {
|
||||||
raise_debug("hmpl_render_interpolation_tags");
|
raise_debug("hmpl_render_interpolation_tags(%p, %s, %s)", arena, *text_ptr, prefix);
|
||||||
char start_pattern[256];
|
char start_pattern[256];
|
||||||
snprintf(start_pattern, sizeof(start_pattern), "{{%s", prefix);
|
snprintf(start_pattern, sizeof(start_pattern), "{{%s", prefix);
|
||||||
int start_pattern_length = strlen(start_pattern);
|
int start_pattern_length = strlen(start_pattern);
|
||||||
@@ -53,6 +54,7 @@ void hmpl_render_interpolation_tags(Arena *arena, char **text_ptr, const Json *
|
|||||||
|
|
||||||
char *replacement = eval_string(arena, context, key);
|
char *replacement = eval_string(arena, context, key);
|
||||||
if (!replacement) {
|
if (!replacement) {
|
||||||
|
raise_debug("no replacement for key: `%s`", key);
|
||||||
offset = (end - current_text) + 2;
|
offset = (end - current_text) + 2;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -61,6 +63,9 @@ void hmpl_render_interpolation_tags(Arena *arena, char **text_ptr, const Json *
|
|||||||
end - start + 2,
|
end - start + 2,
|
||||||
replacement);
|
replacement);
|
||||||
|
|
||||||
|
raise_zalupa("old_text: `%s`", current_text);
|
||||||
|
raise_zalupa("new_text: `%s`", new_text);
|
||||||
|
|
||||||
*text_ptr = new_text;
|
*text_ptr = new_text;
|
||||||
offset = start_index;
|
offset = start_index;
|
||||||
}
|
}
|
||||||
@@ -74,14 +79,14 @@ void hmpl_render_section_tags(Arena *arena, char **text_ptr, Json *context, cons
|
|||||||
char start_pattern[32];
|
char start_pattern[32];
|
||||||
snprintf(start_pattern, sizeof(start_pattern), "{{%s", prefix_start);
|
snprintf(start_pattern, sizeof(start_pattern), "{{%s", prefix_start);
|
||||||
Slice start_slice = slice_create(char, start_pattern, strlen(start_pattern), 0, strlen(start_pattern));
|
Slice start_slice = slice_create(char, start_pattern, strlen(start_pattern), 0, strlen(start_pattern));
|
||||||
raise_trace("start_slice: %s", start_slice.data);
|
raise_zalupa("start_slice: `%s`", start_slice.data);
|
||||||
|
|
||||||
// Create a mutable copy of separator_pattern
|
// Create a mutable copy of separator_pattern
|
||||||
char separator_copy[32];
|
char separator_copy[32];
|
||||||
strncpy(separator_copy, separator_pattern, sizeof(separator_copy) - 1);
|
strncpy(separator_copy, separator_pattern, sizeof(separator_copy) - 1);
|
||||||
separator_copy[sizeof(separator_copy) - 1] = '\0';
|
separator_copy[sizeof(separator_copy) - 1] = '\0';
|
||||||
Slice separator_slice = slice_create(char, separator_copy, strlen(separator_copy), 0, strlen(separator_copy));
|
Slice separator_slice = slice_create(char, separator_copy, strlen(separator_copy), 0, strlen(separator_copy));
|
||||||
raise_trace("separator_slice: %s", separator_slice.data);
|
raise_zalupa("separator_slice: `%s`", separator_slice.data);
|
||||||
if (separator_slice.len == 0) {
|
if (separator_slice.len == 0) {
|
||||||
raise_exception("Unexpected usage: separator pattern cannot be empty");
|
raise_exception("Unexpected usage: separator pattern cannot be empty");
|
||||||
}
|
}
|
||||||
@@ -102,19 +107,21 @@ void hmpl_render_section_tags(Arena *arena, char **text_ptr, Json *context, cons
|
|||||||
|
|
||||||
// Find separator
|
// Find separator
|
||||||
char *opening_tag_separator = strstr((char*)remaining_slice.data, (char*)separator_slice.data);
|
char *opening_tag_separator = strstr((char*)remaining_slice.data, (char*)separator_slice.data);
|
||||||
|
raise_zalupa("opening_tag_separator: `%s`", opening_tag_separator);
|
||||||
if (!opening_tag_separator) {
|
if (!opening_tag_separator) {
|
||||||
raise_exception("Malformed template: missing separator for section tag or not specified name for element");
|
raise_exception("Malformed template: missing separator for section tag or not specified name for element");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract element name (now before separator)
|
// Extract element name (now before separator)
|
||||||
size_t separator_index = opening_tag_separator - (char*)remaining_slice.data;
|
size_t separator_index = opening_tag_separator - (char*)remaining_slice.data - strlen(start_slice.data);
|
||||||
size_t element_name_start = start_slice.len;
|
size_t element_name_start = start_slice.len;
|
||||||
size_t element_name_length = separator_index;
|
size_t element_name_length = separator_index;
|
||||||
|
raise_zalupa("element_name_length: %zu", element_name_length);
|
||||||
|
|
||||||
char *element_name = arena_alloc(arena, element_name_length + 1);
|
char *element_name = arena_alloc(arena, element_name_length + 1);
|
||||||
substr_clone((char*)remaining_slice.data, element_name, element_name_start, element_name_length);
|
substr_clone((char*)remaining_slice.data, element_name, element_name_start, element_name_length);
|
||||||
element_name[element_name_length] = '\0';
|
raise_zalupa("element_name: `%s`", element_name);
|
||||||
|
|
||||||
// Find closing braces
|
// Find closing braces
|
||||||
Slice after_separator = slice_subslice(remaining_slice, separator_index + separator_slice.len,
|
Slice after_separator = slice_subslice(remaining_slice, separator_index + separator_slice.len,
|
||||||
@@ -126,33 +133,35 @@ void hmpl_render_section_tags(Arena *arena, char **text_ptr, Json *context, cons
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Extract key (now after separator)
|
// Extract key (now after separator)
|
||||||
size_t key_start = 0;
|
size_t key_start = strlen(start_slice.data);
|
||||||
size_t key_length = opening_tag_end - (char*)after_separator.data;
|
size_t key_length = opening_tag_end - (char*)after_separator.data - strlen(start_slice.data);
|
||||||
char *key = arena_alloc(arena, key_length + 1);
|
char *key = arena_alloc(arena, key_length + 1);
|
||||||
substr_clone((char*)after_separator.data, key, key_start, key_length);
|
substr_clone((char*)after_separator.data, key, key_start, key_length);
|
||||||
|
raise_zalupa("key: `%s`", key);
|
||||||
key[key_length] = '\0';
|
key[key_length] = '\0';
|
||||||
|
|
||||||
// Create pattern for closing tag
|
// +2 for "{{" and "}}"
|
||||||
char *close_tag_pattern = arena_alloc(arena, start_slice.len + key_length + 3); // +3 for "{{" and "}}"
|
char *close_tag_pattern = arena_alloc(arena, start_slice.len + key_length + strlen(prefix_end) + 2);
|
||||||
snprintf(close_tag_pattern, start_slice.len + key_length + 3,
|
snprintf(
|
||||||
"{{%s%s}}", prefix_end, key);
|
close_tag_pattern,
|
||||||
raise_trace("close_tag_pattern: %s", close_tag_pattern);
|
start_slice.len + key_length + strlen(prefix_end) + 2,
|
||||||
|
"{{%s%s}}",
|
||||||
|
prefix_end,
|
||||||
|
key
|
||||||
|
);
|
||||||
|
raise_zalupa("close_tag_pattern: `%s`", close_tag_pattern);
|
||||||
|
|
||||||
// Find closing tag
|
|
||||||
size_t after_opening_end = (opening_tag_end - (char*)after_separator.data) + 2;
|
size_t after_opening_end = (opening_tag_end - (char*)after_separator.data) + 2;
|
||||||
Slice after_opening_slice = slice_subslice(after_separator, after_opening_end,
|
Slice after_opening_slice = slice_subslice(
|
||||||
after_separator.len - after_opening_end);
|
after_separator,
|
||||||
|
after_opening_end,
|
||||||
|
after_separator.len - after_opening_end
|
||||||
|
);
|
||||||
|
raise_zalupa("after_opening_slice: `%s`", after_opening_slice.data);
|
||||||
|
|
||||||
// Find the exact closing tag by checking for complete tag pattern
|
// Find the exact closing tag by directly searching for the closing tag pattern
|
||||||
char *close_tag = NULL;
|
char *close_tag = strstr(after_opening_slice.data, close_tag_pattern);
|
||||||
char *search_start = (char*)after_opening_slice.data;
|
raise_zalupa("close_tag: `%s` (%p)", close_tag, close_tag);
|
||||||
while ((search_start = strstr(search_start, "{{")) != NULL) {
|
|
||||||
if (strncmp(search_start, close_tag_pattern, strlen(close_tag_pattern)) == 0) {
|
|
||||||
close_tag = search_start;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
search_start += 2; // Move past the "{{" we found
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!close_tag) {
|
if (!close_tag) {
|
||||||
raise_exception("Malformed template: missing loop end for key %s", key);
|
raise_exception("Malformed template: missing loop end for key %s", key);
|
||||||
@@ -161,6 +170,7 @@ void hmpl_render_section_tags(Arena *arena, char **text_ptr, Json *context, cons
|
|||||||
|
|
||||||
// Get array from context
|
// Get array from context
|
||||||
Json *arr = eval_object(arena, context, key);
|
Json *arr = eval_object(arena, context, key);
|
||||||
|
raise_zalupa("arr: %s", json_to_string(arena, arr));
|
||||||
|
|
||||||
if (arr && arr->type == JSON_ARRAY) {
|
if (arr && arr->type == JSON_ARRAY) {
|
||||||
// Count array elements
|
// Count array elements
|
||||||
@@ -172,11 +182,11 @@ void hmpl_render_section_tags(Arena *arena, char **text_ptr, Json *context, cons
|
|||||||
size_t replacement_offset = 0;
|
size_t replacement_offset = 0;
|
||||||
|
|
||||||
// Extract template block
|
// Extract template block
|
||||||
size_t block_start = after_opening_end;
|
|
||||||
size_t block_length = (close_tag - (char*)after_opening_slice.data);
|
size_t block_length = (close_tag - (char*)after_opening_slice.data);
|
||||||
char *block_buff = arena_alloc(arena, block_length + 1);
|
char *block_buff = arena_alloc(arena, block_length + 1);
|
||||||
substr_clone((char*)after_opening_slice.data, block_buff, block_start, block_length);
|
substr_clone((char*)after_opening_slice.data, block_buff, 0, block_length);
|
||||||
block_buff[block_length] = '\0';
|
block_buff[block_length] = '\0';
|
||||||
|
raise_zalupa("block_buff: `%s`", block_buff);
|
||||||
|
|
||||||
// Process each array element
|
// Process each array element
|
||||||
for (Json *elem = arr->child; elem; elem = elem->next) {
|
for (Json *elem = arr->child; elem; elem = elem->next) {
|
||||||
@@ -184,8 +194,9 @@ void hmpl_render_section_tags(Arena *arena, char **text_ptr, Json *context, cons
|
|||||||
|
|
||||||
char *prefix = arena_alloc(arena, element_name_length + 2);
|
char *prefix = arena_alloc(arena, element_name_length + 2);
|
||||||
snprintf(prefix, element_name_length + 2, "%s.", element_name);
|
snprintf(prefix, element_name_length + 2, "%s.", element_name);
|
||||||
|
raise_zalupa("prefix: `%s`", prefix);
|
||||||
|
|
||||||
hmpl_render_interpolation_tags(arena, &block, context, prefix);
|
hmpl_render_interpolation_tags(arena, &block, elem, prefix);
|
||||||
raise_trace("block after: %s", block);
|
raise_trace("block after: %s", block);
|
||||||
|
|
||||||
size_t block_len = strlen(block);
|
size_t block_len = strlen(block);
|
||||||
@@ -194,12 +205,12 @@ void hmpl_render_section_tags(Arena *arena, char **text_ptr, Json *context, cons
|
|||||||
}
|
}
|
||||||
|
|
||||||
replacement[replacement_offset] = '\0';
|
replacement[replacement_offset] = '\0';
|
||||||
raise_trace("replacement: %s", replacement);
|
raise_zalupa("replacement: %s", replacement);
|
||||||
|
|
||||||
// Calculate replacement positions
|
// Calculate replacement positions
|
||||||
size_t replace_start = start_index;
|
size_t replace_start = start_index;
|
||||||
size_t replace_length = (close_tag - (char*)after_opening_slice.data) +
|
size_t replace_length = (close_tag - opening_tag_start) + strlen(close_tag_pattern);
|
||||||
start_slice.len + key_length + 2;
|
raise_zalupa("replace_length: %zu = %zu - %zu + %zu", replace_length, (size_t)close_tag, start_index, strlen(close_tag_pattern));
|
||||||
|
|
||||||
// Perform replacement
|
// Perform replacement
|
||||||
char *new_text = arena_repstr(arena, (char*)text_slice.data, replace_start, replace_length, replacement);
|
char *new_text = arena_repstr(arena, (char*)text_slice.data, replace_start, replace_length, replacement);
|
||||||
|
|||||||
@@ -106,9 +106,7 @@
|
|||||||
"{{/array}}"
|
"{{/array}}"
|
||||||
|
|
||||||
#define TEST_DATA_SIMPLE_SECTION_ITERATION_RESULT \
|
#define TEST_DATA_SIMPLE_SECTION_ITERATION_RESULT \
|
||||||
"value1" \
|
" value1 value2 value3"
|
||||||
"value2" \
|
|
||||||
"value3"
|
|
||||||
|
|
||||||
#define TEST_DATA_COMPLEX_SECTION_ITERATION_CONTEXT \
|
#define TEST_DATA_COMPLEX_SECTION_ITERATION_CONTEXT \
|
||||||
"{" \
|
"{" \
|
||||||
|
|||||||
Reference in New Issue
Block a user