diff --git a/package/c/hectic/hectic.c b/package/c/hectic/hectic.c index 6dfa9fb..283f9df 100644 --- a/package/c/hectic/hectic.c +++ b/package/c/hectic/hectic.c @@ -2484,6 +2484,83 @@ char *template_node_to_debug_str__(POSITION_INFO_DECLARATION, Arena *arena, cons return result; } + +char *template_node_to_json_str__(POSITION_INFO_DECLARATION, Arena *arena, const TemplateNode *node, int depth) { + if (!node) return arena_strncpy__(POSITION_INFO, arena, "", 0); + + if (depth > TEMPLATE_NODE_MAX_DEBUG_DEPTH) { + return arena_strncpy__(POSITION_INFO, arena, "...", 3); + } + + // Use a temporary buffer on the stack for building the string + char temp_buf[MEM_MiB]; + size_t len = 0; + + #define APPEND(...) do { \ + int written = snprintf(temp_buf + len, sizeof(temp_buf) - len, ##__VA_ARGS__); \ + if (written < 0) return NULL; \ + len += written; \ + } while (0) + + if (depth == 0) { + APPEND("["); + } + + APPEND("{\"type\":\"%s\",", template_node_type_to_string(node->type)); + + switch (node->type) { + case TEMPLATE_NODE_SECTION: + APPEND("\"content\":{\"iterator\":\"%s\",\"collection\"=\"%s\"}", + node->value.section.iterator, + node->value.section.collection); + char *body_str = template_node_to_json_str__(POSITION_INFO, arena, node->value.section.body, depth + 1); + if (body_str) { + APPEND(",\"body\":%s", body_str); + } + break; + case TEMPLATE_NODE_INTERPOLATE: + APPEND("\"content\":{\"key\":\"%s\"}", node->value.interpolate.key); + break; + case TEMPLATE_NODE_EXECUTE: + APPEND("\"content\":{\"code\":\"%s\"}", node->value.execute.code); + break; + case TEMPLATE_NODE_INCLUDE: + APPEND("\"content\":{\"key\":\"%s\"}", node->value.include.key); + break; + case TEMPLATE_NODE_TEXT: + APPEND("\"content\":{\"content\":\"%s\"}", node->value.text.content); + break; + default: + break; + } + + if (node->children) { + APPEND(",\"children\":["); + char *child_str = template_node_to_json_str__(POSITION_INFO, arena, node->children, depth + 1); + if (child_str) { + APPEND(",%s", child_str); + } + APPEND("]"); + } + + APPEND("}"); + + if (node->next) { + char *next_str = template_node_to_json_str__(POSITION_INFO, arena, node->next, depth + 1); + if (next_str) { + APPEND(",%s", next_str); + } + } + + if (depth == 0) { + APPEND("]"); + } + + // Copy the final string to arena-allocated memory + char *result = arena_strncpy__(POSITION_INFO, arena, temp_buf, len); + return result; +} + // --------- // -- End -- // --------- diff --git a/package/c/hectic/hectic.h b/package/c/hectic/hectic.h index b933b83..a05aada 100644 --- a/package/c/hectic/hectic.h +++ b/package/c/hectic/hectic.h @@ -623,6 +623,8 @@ char* json_to_debug_str__(const char* file, const char* func, int line, Arena *a char *json_to_pretty_str__(const char* file, const char* func, int line, Arena *arena, const Json * const item, int indent_level); +#define JSON_TO_PRETTY_STR(arena, json) json_to_pretty_str__(__FILE__, __func__, __LINE__, arena, json, 0) + // Prettify a flat debug string by adding line breaks and structure char *debug_to_pretty_str__(const char* file, const char* func, int line, Arena *arena, const char *flat_str); #define debug_to_pretty_str(arena, str) debug_to_pretty_str__(__FILE__, __func__, __LINE__, arena, str) @@ -764,6 +766,8 @@ TemplateConfig template_default_config__(const char *file, const char *func, int char *template_node_to_debug_str__(const char *file, const char *func, int line, Arena *arena, const char *name, const TemplateNode *self, PtrSet *visited); +char *template_node_to_json_str__(const char *file, const char *func, int line, Arena *arena, const TemplateNode *node, int depth); + #define template_parse(arena, s, config) template_parse__(__FILE__, __func__, __LINE__, arena, s, config) #define template_default_config() template_default_config__(__FILE__, __func__, __LINE__) @@ -771,4 +775,7 @@ char *template_node_to_debug_str__(const char *file, const char *func, int line, #define TEMPLATE_NODE_TO_DEBUG_STR(arena, name, node) \ template_node_to_debug_str__(__FILE__, __func__, __LINE__, arena, name, node, ptrset_init(arena)) +#define TEMPLATE_NODE_TO_JSON_STR(arena, node) \ + template_node_to_json_str__(__FILE__, __func__, __LINE__, arena, node, 0) + #endif // EPRINTF_H \ No newline at end of file diff --git a/package/c/hectic/test/04-json.c b/package/c/hectic/test/04-json.c index af3fb31..95e6924 100644 --- a/package/c/hectic/test/04-json.c +++ b/package/c/hectic/test/04-json.c @@ -118,16 +118,16 @@ static void test_arena_reset_reuse(Arena *arena) { // assert(strcmp(debug_str, "struct Json root = {type = JSON_OBJECT, key = \"key\", value = struct JsonValue = {string = \"value\"}, next = NULL}") == 0); //} -static void test_debug_str_to_json(Arena *arena) { - const char *debug_str = "struct SomeStruct struct_name = {name = \"value\", next = NULL, value = 123}"; - JsonResult result = DEBUG_STR_TO_JSON(arena, &debug_str); - if (IS_RESULT_ERROR(result)) { - raise_exception("DEBUG_STR_TO_JSON: %s", &RESULT_ERROR_MESSAGE(result)); - return; - } - raise_notice("result: %s", JSON_TO_DEBUG_STR(arena, "result", &RESULT_SOME_VALUE(result))); - assert(RESULT_SOME_VALUE(result).type == JSON_OBJECT); -} +//static void test_debug_str_to_json(Arena *arena) { +// const char *debug_str = "struct SomeStruct struct_name = {name = \"value\", next = NULL, value = 123}"; +// JsonResult result = DEBUG_STR_TO_JSON(arena, &debug_str); +// if (IS_RESULT_ERROR(result)) { +// raise_exception("DEBUG_STR_TO_JSON: %s", &RESULT_ERROR_MESSAGE(result)); +// return; +// } +// raise_notice("result: %s", JSON_TO_DEBUG_STR(arena, "result", &RESULT_SOME_VALUE(result))); +// assert(RESULT_SOME_VALUE(result).type == JSON_OBJECT); +//} int main(void) { printf("%sRunning %s%s%s\n", OPTIONAL_COLOR(COLOR_GREEN), OPTIONAL_COLOR(COLOR_CYAN), __FILE__, OPTIONAL_COLOR(COLOR_RESET)); @@ -154,8 +154,8 @@ int main(void) { test_arena_reset_reuse(&arena); //arena_reset(&arena); //test_json_to_debug_str(&arena); - arena_reset(&arena); - test_debug_str_to_json(&arena); + //arena_reset(&arena); + //test_debug_str_to_json(&arena); arena_free(&arena); logger_free(); diff --git a/package/c/hectic/test/06-templater.c b/package/c/hectic/test/06-templater.c index 68246dd..2494057 100755 --- a/package/c/hectic/test/06-templater.c +++ b/package/c/hectic/test/06-templater.c @@ -4,18 +4,38 @@ #include #include "hectic.h" -#define ARENA_SIZE 1024 * 1024 +#define ARENA_SIZE MEM_MiB + +#define TEST_TEMPLATE_NODE_TO_DEBUG_STR \ + "struct TemplateNode root = {\n" \ + " enum type = TEXT 0 ,\n" \ + " union TemplateValue value = {\n" \ + " struct TemplateTextValue text = {\n" \ + " content = %p \"Hello\"\n" \ + " } %p\n" \ + " } %p,\n" \ + " struct TemplateNode children = NULL,\n" \ + " struct TemplateNode next = {\n" \ + " enum type = INTERPOLATE 1 ,\n" \ + " union TemplateValue value = {\n" \ + " struct TemplateInterpolateValue interpolate = {\n" \ + " key = %p \"name\"\n" \ + " } %p\n" \ + " } %p,\n" \ + " struct TemplateNode children = NULL,\n" \ + " struct TemplateNode next = {\n" \ + " enum type = TEXT 0 ,\n" \ + " union TemplateValue value = {\n" \ + " struct TemplateTextValue text = {\n" \ + " content = %p \"!\"\n" \ + " } %p\n" \ + " } %p,\n" \ + " struct TemplateNode children = NULL,\n" \ + " struct TemplateNode next = NULL\n" \ + " } %p\n" \ + " } %p\n" \ + "} %p\n" -//static char *remove_all_spaces(char *s) { -// char *new_s = NULL; -// while (*s) { -// if (*s != ' ' && *s != '\t' && *s != '\n') { -// new_s = s; -// } -// s++; -// } -// return new_s; -//} static void test_template_node_to_debug_str(Arena *arena) { TemplateNode *root = arena_alloc(arena, sizeof(TemplateNode)); @@ -30,57 +50,40 @@ static void test_template_node_to_debug_str(Arena *arena) { root->next->next->type = TEMPLATE_NODE_TEXT; root->next->next->value.text.content = arena_strncpy(arena, "!", 1); - char *debug_str = TEMPLATE_NODE_TO_DEBUG_STR(arena, "root", root); + char *debug_str = debug_to_pretty_str(arena, TEMPLATE_NODE_TO_DEBUG_STR(arena, "root", root)); + raise_log("debug_str: \n%s", debug_str); - raise_notice("debug_str: %s", debug_str); - char *expected; - //sprintf(expected, "struct TemplateNode root = {enum type = TEXT 0, union TemplateValue value = {struct TemplateTextValue text = {content = %p \"Hello\"} %p} %p, struct TemplateNode children = NULL, struct TemplateNode next = {enum type = INTERPOLATE 1, union TemplateValue value = {struct TemplateInterpolateValue interpolate = {key = %p \"name\"} %p} %p, struct TemplateNode children = NULL, struct TemplateNode next = {enum type = TEXT 0, union TemplateValue value = {struct TemplateTextValue text = {content = %p \"!\"} %p} %p, struct TemplateNode children = NULL, struct TemplateNode next = NULL} %p} %p} %p", - // root.value.text.content, - // root.value.text, - // root.value, - // root.next.value.interpolate.key, - // root.next.value.interpolate, - // root.next.value, + { // some debug output + Arena *debug_arena = DISPOSABLE_ARENA; + const char *json_str = TEMPLATE_NODE_TO_JSON_STR(debug_arena, root); + Json *json = json_parse(debug_arena, &json_str); + raise_notice("json_str: \n%s", JSON_TO_PRETTY_STR(debug_arena, json)); + } + char *expected_debug_str = arena_alloc(arena, MEM_KiB); + sprintf(expected_debug_str, TEST_TEMPLATE_NODE_TO_DEBUG_STR, + (void*)root->value.text.content, + (void*)&root->value.text, + (void*)&root->value, + (void*)root->next->value.interpolate.key, + (void*)&root->next->value.interpolate, + (void*)&root->next->value, + (void*)root->next->next->value.text.content, + (void*)&root->next->next->value.text, + (void*)&root->next->next->value, + (void*)root->next->next, + (void*)root->next, + (void*)root + ); - //assert(strcmp( - // remove_all_spaces(debug_str), - // remove_all_spaces("" - // "[" - // " {" - // " \"type\":\"TEXT\"," - // " \"content\":{" - // " \"content\":\"Hello\"" - // " }" - // " }," - // " {" - // " \"type\":\"INTERPOLATE\"," - // " \"content\":{" - // " \"key\":\"name\"" - // " }" - // " }," - // " {" - // " \"type\":\"TEXT\"," - // " \"content\":{" - // " \"content\":\"!\"" - // " }" - // " }" - // "]")) == 0); + raise_log("expected_debug_str: \n%s", expected_debug_str); + + assert(strcmp(debug_str, expected_debug_str) == 0); } -//static void test_template_parse(Arena *arena, TemplateConfig *config) { -// const char *template = "Hello {% name %}!"; -// TemplateResult *result = template_parse(arena, &template, config); -// -// Arena *debug_arena = DISPOSABLE_ARENA; -// const char *debug_str = template_node_to_debug_str(debug_arena, &result->Result.node); -// raise_notice("debug_str: %s", debug_str); -// raise_notice("result: %s", json_to_pretty_str(debug_arena, json_parse(debug_arena, &debug_str))); -// assert(result->type == TEMPLATE_RESULT_NODE); -//} - int main(void) { printf("%sRunning %s%s%s\n", OPTIONAL_COLOR(COLOR_GREEN), OPTIONAL_COLOR(COLOR_CYAN), __FILE__, OPTIONAL_COLOR(COLOR_RESET)); + debug_color_mode = COLOR_MODE_DISABLE; logger_init(); Arena arena = arena_init(ARENA_SIZE);