diff --git a/package/c/hectic/hectic.c b/package/c/hectic/hectic.c index 28a3b48..c932f46 100644 --- a/package/c/hectic/hectic.c +++ b/package/c/hectic/hectic.c @@ -206,7 +206,7 @@ PtrSet *ptrset_init__(POSITION_INFO_DECLARATION, Arena *arena) { return set; } -bool debug_ptrset_contains__(PtrSet *set, void *ptr) { +bool debug_ptrset_contains__(PtrSet *set, const void *ptr) { for (size_t i = 0; i < set->size; i++) { if (set->data[i] == ptr) return true; @@ -214,7 +214,7 @@ bool debug_ptrset_contains__(PtrSet *set, void *ptr) { return false; } -void debug_ptrset_add__(CTX_DECLARATION, PtrSet *set, void *ptr) { +void debug_ptrset_add__(CTX_DECLARATION, PtrSet *set, const void *ptr) { if (set->size == set->capacity) { set->capacity = set->capacity ? set->capacity * 2 : 4; set->data = arena_realloc__(CTX(arena), set->data, set->capacity, set->capacity * sizeof(void*)); @@ -282,7 +282,7 @@ char *debug_join_debug_strings_v(CTX_DECLARATION, int count, va_list args) { return joined; } -char *struct_to_debug_str__(CTX_DECLARATION, const char *type, const char *name, void *ptr, int count, ...) { +char *struct_to_debug_str__(CTX_DECLARATION, const char *type, const char *name, const void *ptr, int count, ...) { raise_message(LOG_LEVEL_TRACE, POSITION_INFO, "DEBUG STR: type: %s, name: %s, ptr: %p, count: %d", type, name, ptr, count); va_list args; @@ -1809,8 +1809,8 @@ bool template_validate_config__(POSITION_INFO_DECLARATION, const TemplateConfig if (strncmp(*s, pattern, strlen(pattern))) { \ raise_message(LOG_LEVEL_EXCEPTION, POSITION_INFO, "PARSE: " message_arg); \ result->type = RESULT_ERROR; \ - result->Result.error.code = code_arg; \ - result->Result.error.message = message_arg; \ + result->Result.Error.code = code_arg; \ + result->Result.Error.message = message_arg; \ return result; \ } @@ -2023,8 +2023,8 @@ TemplateResult *template_parse__(POSITION_INFO_DECLARATION, Arena *arena, const TemplateResult *error_result = arena_alloc__(POSITION_INFO, arena, sizeof(TemplateResult)); error_result->type = RESULT_ERROR; - error_result->Result.error.code = TEMPLATE_ERROR_UNKNOWN_TAG; - error_result->Result.error.message = "Unknown tag prefix"; + error_result->Result.Error.code = TEMPLATE_ERROR_UNKNOWN_TAG; + error_result->Result.Error.message = "Unknown tag prefix"; return error_result; } @@ -2059,7 +2059,7 @@ TemplateResult *template_parse__(POSITION_INFO_DECLARATION, Arena *arena, const #define TEMPLATE_NODE_MAX_DEBUG_DEPTH 20 -static const char *template_error_code_to_string(TemplateErrorCode code) { +const char *template_error_code_to_string(TemplateErrorCode code) { switch (code) { case TEMPLATE_ERROR_NONE: return "NONE"; case TEMPLATE_ERROR_UNKNOWN_TAG: return "UNKNOWN_TAG"; @@ -2075,7 +2075,7 @@ static const char *template_error_code_to_string(TemplateErrorCode code) { } } -static char *template_node_type_to_string(TemplateNodeType type) { +char *template_node_type_to_string(TemplateNodeType type) { switch (type) { case TEMPLATE_NODE_SECTION: return "SECTION"; case TEMPLATE_NODE_INTERPOLATE: return "INTERPOLATE"; @@ -2089,83 +2089,90 @@ static char *template_node_type_to_string(TemplateNodeType type) { } } -char *template_node_to_debug_str__(POSITION_INFO_DECLARATION, Arena *arena, const TemplateNode *node, int depth) { - if (!node) return arena_strncpy__(POSITION_INFO, arena, "", 0); +//char *log_rules_to_debug_str__(CTX_DECLARATION, char *name, LogRule *self, PtrSet *visited) { +// char *result = arena_alloc(arena, MEM_KiB); +// STRUCT_TO_DEBUG_STR(arena, result, LogRule, name, self, visited, 6, +// string_to_debug_str__(POSITION_INFO, arena, "level", log_level_to_string(self->level)), +// string_to_debug_str__(POSITION_INFO, arena, "file_pattern", self->file_pattern), +// string_to_debug_str__(POSITION_INFO, arena, "function_pattern", self->function_pattern), +// int_to_debug_str__(POSITION_INFO, arena, "line_start", self->line_start), +// int_to_debug_str__(POSITION_INFO, arena, "line_end", self->line_end), +// log_rules_to_debug_str__(POSITION_INFO, arena, "next", self->next, visited) +// ); +// return result; +//} - if (depth > TEMPLATE_NODE_MAX_DEBUG_DEPTH) { - return arena_strncpy__(POSITION_INFO, arena, "...", 3); - } +char *template_section_value_to_debug_str__(POSITION_INFO_DECLARATION, Arena *arena, const char *name, const TemplateSectionValue *self, PtrSet *visited) { + char *result = arena_alloc(arena, MEM_KiB); + STRUCT_TO_DEBUG_STR(arena, result, TemplateSectionValue, name, self, visited, 3, + string_to_debug_str__(POSITION_INFO, arena, "iterator", self->iterator), + string_to_debug_str__(POSITION_INFO, arena, "collection", self->collection), + template_node_to_debug_str__(POSITION_INFO, arena, "body", self->body, visited) + ); + return result; +} - // 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) +char *template_interpolate_value_to_debug_str__(POSITION_INFO_DECLARATION, Arena *arena, const char *name, const TemplateInterpolateValue *self, PtrSet *visited) { + char *result = arena_alloc(arena, MEM_KiB); + STRUCT_TO_DEBUG_STR(arena, result, TemplateInterpolateValue, name, self, visited, 1, + string_to_debug_str__(POSITION_INFO, arena, "key", self->key) + ); + return result; +} - if (depth == 0) { - APPEND("["); - } +char *template_execute_value_to_debug_str__(POSITION_INFO_DECLARATION, Arena *arena, const char *name, const TemplateExecuteValue *self, PtrSet *visited) { + char *result = arena_alloc(arena, MEM_KiB); + STRUCT_TO_DEBUG_STR(arena, result, TemplateExecuteValue, name, self, visited, 1, + string_to_debug_str__(POSITION_INFO, arena, "code", self->code) + ); + return result; +} - APPEND("{\"type\":\"%s\",", template_node_type_to_string(node->type)); +char *template_include_value_to_debug_str__(POSITION_INFO_DECLARATION, Arena *arena, const char *name, const TemplateIncludeValue *self, PtrSet *visited) { + char *result = arena_alloc(arena, MEM_KiB); + STRUCT_TO_DEBUG_STR(arena, result, TemplateIncludeValue, name, self, visited, 1, + string_to_debug_str__(POSITION_INFO, arena, "key", self->key) + ); + return result; +} - 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_debug_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; - } +char *template_text_value_to_debug_str__(POSITION_INFO_DECLARATION, Arena *arena, const char *name, const TemplateTextValue *self, PtrSet *visited) { + char *result = arena_alloc(arena, MEM_KiB); + STRUCT_TO_DEBUG_STR(arena, result, TemplateTextValue, name, self, visited, 1, + string_to_debug_str__(POSITION_INFO, arena, "content", self->content) + ); + return result; +} - if (node->error.code != TEMPLATE_ERROR_NONE) { - APPEND(",\"error\":{\"code\":\"%s\",\"message\":\"%s\"}", template_error_code_to_string(node->error.code), node->error.message); - } +char *template_value_to_debug_str__(POSITION_INFO_DECLARATION, Arena *arena, const char *name, const TemplateValue *self, PtrSet *visited) { + char *result = arena_alloc(arena, MEM_KiB); - if (node->children) { - APPEND(",\"children\":["); - char *child_str = template_node_to_debug_str__(POSITION_INFO, arena, node->children, depth + 1); - if (child_str) { - APPEND(",%s", child_str); - } - APPEND("]"); - } + STRUCT_TO_DEBUG_STR(arena, result, TemplateValue, name, self, visited, 5, + template_section_value_to_debug_str__(POSITION_INFO, arena, "section", &self->section, visited), + template_interpolate_value_to_debug_str__(POSITION_INFO, arena, "interpolate", &self->interpolate, visited), + template_execute_value_to_debug_str__(POSITION_INFO, arena, "execute", &self->execute, visited), + template_include_value_to_debug_str__(POSITION_INFO, arena, "include", &self->include, visited), + template_text_value_to_debug_str__(POSITION_INFO, arena, "text", &self->text, visited) + ); + return result; +} - APPEND("}"); - if (node->next) { - char *next_str = template_node_to_debug_str__(POSITION_INFO, arena, node->next, depth + 1); - if (next_str) { - APPEND(",%s", next_str); - } - } +//struct TemplateNode { +// TemplateNodeType type; +// TemplateValue value; +// TemplateNode *children; // child nodes +// TemplateNode *next; // sibling nodes +//}; - if (depth == 0) { - APPEND("]"); - } - - // Copy the final string to arena-allocated memory - char *result = arena_strncpy__(POSITION_INFO, arena, temp_buf, len); +char *template_node_to_debug_str__(POSITION_INFO_DECLARATION, Arena *arena, const char *name, const TemplateNode *self, PtrSet *visited) { + char *result = arena_alloc(arena, MEM_KiB); + STRUCT_TO_DEBUG_STR(arena, result, TemplateNode, name, self, visited, 4, + string_to_debug_str__(POSITION_INFO, arena, "type", template_node_type_to_string(self->type)), + template_value_to_debug_str__(POSITION_INFO, arena, "value", &self->value, visited), + template_node_to_debug_str__(POSITION_INFO, arena, "children", self->children, visited), + template_node_to_debug_str__(POSITION_INFO, arena, "next", self->next, visited) + ); return result; } diff --git a/package/c/hectic/hectic.h b/package/c/hectic/hectic.h index d10833e..7f9afd3 100644 --- a/package/c/hectic/hectic.h +++ b/package/c/hectic/hectic.h @@ -60,15 +60,28 @@ typedef enum { RESULT_SOME, } ResultType; -#define RESULT(name, error_type, result_type) \ +#define RESULT(name, result_type, error_type) \ typedef struct { \ ResultType type; \ union { \ - error_type error; \ - result_type some; \ + struct { \ + error_type code; \ + char *message; \ + } Error; \ + result_type some; \ } Result; \ } name##Result +#define IS_RESULT_ERROR(result) (result->type == RESULT_ERROR) +#define IS_RESULT_SOME(result) (result->type == RESULT_SOME) + +#define TRY(result) if (IS_RESULT_ERROR(result)) { return result; } + +#define RESULT_ERROR_CODE(result) (result->Result.error.code) +#define RESULT_ERROR_MESSAGE(result) (result->Result.error.message) + +#define RESULT_SOME_VALUE(result) (result->Result.some) + // ------------ // -- Errors -- // ------------ @@ -88,54 +101,54 @@ typedef enum { // -- Logger -- // ------------ -/** +/* * Log levels following a consistent severity-based hierarchy. * Each level includes specific guidance on when it should be used. */ typedef enum { - /** + /* * TRACE: Most detailed information for in-depth debugging * Use for: Deep diagnostic details, function entry/exit, variable dumps * Visibility: Development environments only, rarely used in production */ LOG_LEVEL_TRACE, - /** + /* * DEBUG: Detailed information useful during development * Use for: Development-time debugging, showing variable states, internal flows * Visibility: Development and debugging environments, rarely in production */ LOG_LEVEL_DEBUG, - /** + /* * LOG: General operational events * Use for: Runtime events worth logging but not requiring attention * Visibility: Always written to logs, useful for auditing/diagnostics */ LOG_LEVEL_LOG, - /** + /* * INFO: Informational messages highlighting progress * Use for: Normal but noteworthy events, state changes, startup/shutdown events * Visibility: Visible to client applications if configured */ LOG_LEVEL_INFO, - /** + /* * NOTICE: More important events than INFO, but not warnings * Use for: Important state changes, significant operations, configuration changes * Visibility: Displayed to client by default, meant to be seen */ LOG_LEVEL_NOTICE, - /** + /* * WARN: Potential problems that don't prevent normal operation * Use for: Unexpected behaviors, deprecated feature usage, recoverable errors * Visibility: Alerts both client and server logs, needs attention */ LOG_LEVEL_WARN, - /** + /* * EXCEPTION: Serious errors requiring immediate attention * Use for: Critical failures, data loss risks, business rule violations * Visibility: Highest priority, often leads to operation termination @@ -143,7 +156,7 @@ typedef enum { LOG_LEVEL_EXCEPTION } LogLevel; -/** +/* * Structure for complex log level rule * Allows specifying log levels per file, function, and line range */ @@ -164,7 +177,13 @@ void logger_level(LogLevel level); LogLevel log_level_from_string(const char *level_str); -/** +typedef enum { + PLACEHOLDER_ERROR, +} LogRuleParseError; + +RESULT(LogParse, LogRule, LogRuleParseError); + +/* * Set complex logging rules from a string * Format: DEFAULT_LEVEL,@=LEVEL,@:=LEVEL,... * Example: "INFO,main.c@main=DEBUG,helper.c@10:50=TRACE" @@ -174,7 +193,7 @@ LogLevel log_level_from_string(const char *level_str); */ int logger_parse_rules(const char *rules_str); -/** +/* * Set complex logging rule programmatically * * @param level Log level for this rule @@ -187,7 +206,7 @@ int logger_parse_rules(const char *rules_str); int logger_add_rule(LogLevel level, const char *file_pattern, const char *function_pattern, int line_start, int line_end); -/** +/* * Get the effective log level for a message based on complex rules * * @param file Source file where log was generated @@ -361,7 +380,7 @@ static Arena disposable_arena __attribute__((unused)) = {0}; * Used to detect cycles in debug strings */ typedef struct PtrSet { - void **data; + void const **data; size_t size; size_t capacity; } PtrSet; @@ -369,20 +388,20 @@ typedef struct PtrSet { PtrSet *ptrset_init__(const char *file, const char *func, int line, Arena *arena); #define ptrset_init(arena) ptrset_init__(__FILE__, __func__, __LINE__, arena) -bool debug_ptrset_contains__(PtrSet *set, void *ptr); -void debug_ptrset_add__(const char *file, const char *func, int line, Arena *arena, PtrSet *set, void *ptr); +bool debug_ptrset_contains__(PtrSet *set, const void *ptr); +void debug_ptrset_add__(const char *file, const char *func, int line, Arena *arena, PtrSet *set, const void *ptr); #define DEBUGSTR(arena, type, value) DEBUGSTR_##type(arena, value) #define DEBUGSTR_Slice(arena, value) slice_to_debug_str(arena, value) #define DEBUGSTR_Json(arena, value) json_to_debug_str(arena, value) -/** +/* * Print all current logging rules to stderr for debugging */ void logger_print_rules(); -/** +/* * Dump all active logging rules into a string * * @param arena Memory arena to allocate the string in @@ -402,7 +421,7 @@ char *ptr_to_debug_str__(const char *file, const char *func, int line, Arena *ar char *char_to_debug_str__(const char *file, const char *func, int line, Arena *arena, const char *name, char c); -char *struct_to_debug_str__(const char *file, const char *func, int line, Arena *arena, const char *type, const char *name, void *ptr, int count, ...); +char *struct_to_debug_str__(const char *file, const char *func, int line, Arena *arena, const char *type, const char *name, const void *ptr, int count, ...); #define STRING_TO_DEBUG_STR(arena, name, string) \ string_to_debug_str__(__FILE__, __func__, __LINE__, arena, name, string) @@ -617,31 +636,26 @@ typedef enum { TEMPLATE_ERROR_NESTED_EXECUTE, } TemplateErrorCode; -typedef struct { - TemplateErrorCode code; - char *message; -} TemplateError; - struct TemplateNode { - TemplateError error; TemplateNodeType type; TemplateValue value; TemplateNode *children; // child nodes TemplateNode *next; // sibling nodes }; -RESULT(Template, TemplateError, TemplateNode); +RESULT(Template, TemplateNode, TemplateErrorCode); TemplateResult *template_parse__(const char *file, const char *func, int line, Arena *arena, const char **s, const TemplateConfig *config); -char *template_node_to_debug_str__(const char *file, const char *func, int line, Arena *arena, const TemplateNode *node, int depth); - TemplateConfig template_default_config__(const char *file, const char *func, int line); +char *template_node_to_debug_str__(const char *file, const char *func, int line, Arena *arena, const char *name, const TemplateNode *self, PtrSet *visited); + #define template_parse(arena, s, config) template_parse__(__FILE__, __func__, __LINE__, arena, s, config) -#define template_node_to_debug_str(arena, node) template_node_to_debug_str__(__FILE__, __func__, __LINE__, arena, node, 0) - #define template_default_config() template_default_config__(__FILE__, __func__, __LINE__) +#define TEMPLATE_NODE_TO_DEBUG_STR(arena, name, node) \ + template_node_to_debug_str__(__FILE__, __func__, __LINE__, arena, name, node, ptrset_init(arena)) + #endif // EPRINTF_H \ No newline at end of file diff --git a/package/c/hectic/make.sh b/package/c/hectic/make.sh index 8fd1586..b0e0f57 100644 --- a/package/c/hectic/make.sh +++ b/package/c/hectic/make.sh @@ -84,7 +84,7 @@ while [ $# -gt 0 ]; do done MODE="${1:-build}" -shift +shift > /dev/null if [ -n "$COLOR_FLAG" ]; then CFLAGS="$CFLAGS $COLOR_FLAG" @@ -118,16 +118,13 @@ case "$MODE" in esac done - # If no specific tests provided, run all - if [ ${#TESTS_TO_RUN[@]} -eq 0 ]; then - TESTS_TO_RUN=("all") - fi - + echo "TESTS_TO_RUN: ${TESTS_TO_RUN[@]}" for test_file in test/*.c; do test_name=$(basename "${test_file%.c}") # Skip if specific tests are requested and this isn't one of them - if [ "${TESTS_TO_RUN[0]}" != "all" ] && ! [[ " ${TESTS_TO_RUN[*]} " =~ " ${test_name} " ]]; then + # TODO: error on unknown test file + if [ ${#TESTS_TO_RUN[@]} -ne 0 ] && ! [[ " ${TESTS_TO_RUN[*]} " =~ " ${test_name} " ]]; then continue fi diff --git a/package/c/hectic/test/06-templater.c b/package/c/hectic/test/06-templater.c index cb0f512..2984584 100755 --- a/package/c/hectic/test/06-templater.c +++ b/package/c/hectic/test/06-templater.c @@ -30,7 +30,7 @@ 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); + char *debug_str = TEMPLATE_NODE_TO_DEBUG_STR(arena, "root", root); raise_notice("debug_str: %s", debug_str); //assert(strcmp(