feat: hectic C: template node debug, but union issue in debug string constructor
This commit is contained in:
@@ -206,7 +206,7 @@ PtrSet *ptrset_init__(POSITION_INFO_DECLARATION, Arena *arena) {
|
|||||||
return set;
|
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++) {
|
for (size_t i = 0; i < set->size; i++) {
|
||||||
if (set->data[i] == ptr)
|
if (set->data[i] == ptr)
|
||||||
return true;
|
return true;
|
||||||
@@ -214,7 +214,7 @@ bool debug_ptrset_contains__(PtrSet *set, void *ptr) {
|
|||||||
return false;
|
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) {
|
if (set->size == set->capacity) {
|
||||||
set->capacity = set->capacity ? set->capacity * 2 : 4;
|
set->capacity = set->capacity ? set->capacity * 2 : 4;
|
||||||
set->data = arena_realloc__(CTX(arena), set->data, set->capacity, set->capacity * sizeof(void*));
|
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;
|
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);
|
raise_message(LOG_LEVEL_TRACE, POSITION_INFO, "DEBUG STR: type: %s, name: %s, ptr: %p, count: %d", type, name, ptr, count);
|
||||||
|
|
||||||
va_list args;
|
va_list args;
|
||||||
@@ -1809,8 +1809,8 @@ bool template_validate_config__(POSITION_INFO_DECLARATION, const TemplateConfig
|
|||||||
if (strncmp(*s, pattern, strlen(pattern))) { \
|
if (strncmp(*s, pattern, strlen(pattern))) { \
|
||||||
raise_message(LOG_LEVEL_EXCEPTION, POSITION_INFO, "PARSE: " message_arg); \
|
raise_message(LOG_LEVEL_EXCEPTION, POSITION_INFO, "PARSE: " message_arg); \
|
||||||
result->type = RESULT_ERROR; \
|
result->type = RESULT_ERROR; \
|
||||||
result->Result.error.code = code_arg; \
|
result->Result.Error.code = code_arg; \
|
||||||
result->Result.error.message = message_arg; \
|
result->Result.Error.message = message_arg; \
|
||||||
return result; \
|
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));
|
TemplateResult *error_result = arena_alloc__(POSITION_INFO, arena, sizeof(TemplateResult));
|
||||||
|
|
||||||
error_result->type = RESULT_ERROR;
|
error_result->type = RESULT_ERROR;
|
||||||
error_result->Result.error.code = TEMPLATE_ERROR_UNKNOWN_TAG;
|
error_result->Result.Error.code = TEMPLATE_ERROR_UNKNOWN_TAG;
|
||||||
error_result->Result.error.message = "Unknown tag prefix";
|
error_result->Result.Error.message = "Unknown tag prefix";
|
||||||
|
|
||||||
return error_result;
|
return error_result;
|
||||||
}
|
}
|
||||||
@@ -2059,7 +2059,7 @@ TemplateResult *template_parse__(POSITION_INFO_DECLARATION, Arena *arena, const
|
|||||||
|
|
||||||
#define TEMPLATE_NODE_MAX_DEBUG_DEPTH 20
|
#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) {
|
switch (code) {
|
||||||
case TEMPLATE_ERROR_NONE: return "NONE";
|
case TEMPLATE_ERROR_NONE: return "NONE";
|
||||||
case TEMPLATE_ERROR_UNKNOWN_TAG: return "UNKNOWN_TAG";
|
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) {
|
switch (type) {
|
||||||
case TEMPLATE_NODE_SECTION: return "SECTION";
|
case TEMPLATE_NODE_SECTION: return "SECTION";
|
||||||
case TEMPLATE_NODE_INTERPOLATE: return "INTERPOLATE";
|
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) {
|
//char *log_rules_to_debug_str__(CTX_DECLARATION, char *name, LogRule *self, PtrSet *visited) {
|
||||||
if (!node) return arena_strncpy__(POSITION_INFO, arena, "", 0);
|
// 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) {
|
char *template_section_value_to_debug_str__(POSITION_INFO_DECLARATION, Arena *arena, const char *name, const TemplateSectionValue *self, PtrSet *visited) {
|
||||||
return arena_strncpy__(POSITION_INFO, arena, "...", 3);
|
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 *template_interpolate_value_to_debug_str__(POSITION_INFO_DECLARATION, Arena *arena, const char *name, const TemplateInterpolateValue *self, PtrSet *visited) {
|
||||||
char temp_buf[MEM_MiB];
|
char *result = arena_alloc(arena, MEM_KiB);
|
||||||
size_t len = 0;
|
STRUCT_TO_DEBUG_STR(arena, result, TemplateInterpolateValue, name, self, visited, 1,
|
||||||
|
string_to_debug_str__(POSITION_INFO, arena, "key", self->key)
|
||||||
|
);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
#define APPEND(...) do { \
|
char *template_execute_value_to_debug_str__(POSITION_INFO_DECLARATION, Arena *arena, const char *name, const TemplateExecuteValue *self, PtrSet *visited) {
|
||||||
int written = snprintf(temp_buf + len, sizeof(temp_buf) - len, ##__VA_ARGS__); \
|
char *result = arena_alloc(arena, MEM_KiB);
|
||||||
if (written < 0) return NULL; \
|
STRUCT_TO_DEBUG_STR(arena, result, TemplateExecuteValue, name, self, visited, 1,
|
||||||
len += written; \
|
string_to_debug_str__(POSITION_INFO, arena, "code", self->code)
|
||||||
} while (0)
|
);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
if (depth == 0) {
|
char *template_include_value_to_debug_str__(POSITION_INFO_DECLARATION, Arena *arena, const char *name, const TemplateIncludeValue *self, PtrSet *visited) {
|
||||||
APPEND("[");
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
APPEND("{\"type\":\"%s\",", template_node_type_to_string(node->type));
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
switch (node->type) {
|
char *template_value_to_debug_str__(POSITION_INFO_DECLARATION, Arena *arena, const char *name, const TemplateValue *self, PtrSet *visited) {
|
||||||
case TEMPLATE_NODE_SECTION:
|
char *result = arena_alloc(arena, MEM_KiB);
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (node->error.code != TEMPLATE_ERROR_NONE) {
|
STRUCT_TO_DEBUG_STR(arena, result, TemplateValue, name, self, visited, 5,
|
||||||
APPEND(",\"error\":{\"code\":\"%s\",\"message\":\"%s\"}", template_error_code_to_string(node->error.code), node->error.message);
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
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("]");
|
|
||||||
}
|
|
||||||
|
|
||||||
APPEND("}");
|
//struct TemplateNode {
|
||||||
|
// TemplateNodeType type;
|
||||||
|
// TemplateValue value;
|
||||||
|
// TemplateNode *children; // child nodes
|
||||||
|
// TemplateNode *next; // sibling nodes
|
||||||
|
//};
|
||||||
|
|
||||||
if (node->next) {
|
char *template_node_to_debug_str__(POSITION_INFO_DECLARATION, Arena *arena, const char *name, const TemplateNode *self, PtrSet *visited) {
|
||||||
char *next_str = template_node_to_debug_str__(POSITION_INFO, arena, node->next, depth + 1);
|
char *result = arena_alloc(arena, MEM_KiB);
|
||||||
if (next_str) {
|
STRUCT_TO_DEBUG_STR(arena, result, TemplateNode, name, self, visited, 4,
|
||||||
APPEND(",%s", next_str);
|
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)
|
||||||
if (depth == 0) {
|
);
|
||||||
APPEND("]");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy the final string to arena-allocated memory
|
|
||||||
char *result = arena_strncpy__(POSITION_INFO, arena, temp_buf, len);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -60,15 +60,28 @@ typedef enum {
|
|||||||
RESULT_SOME,
|
RESULT_SOME,
|
||||||
} ResultType;
|
} ResultType;
|
||||||
|
|
||||||
#define RESULT(name, error_type, result_type) \
|
#define RESULT(name, result_type, error_type) \
|
||||||
typedef struct { \
|
typedef struct { \
|
||||||
ResultType type; \
|
ResultType type; \
|
||||||
union { \
|
union { \
|
||||||
error_type error; \
|
struct { \
|
||||||
result_type some; \
|
error_type code; \
|
||||||
|
char *message; \
|
||||||
|
} Error; \
|
||||||
|
result_type some; \
|
||||||
} Result; \
|
} Result; \
|
||||||
} name##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 --
|
// -- Errors --
|
||||||
// ------------
|
// ------------
|
||||||
@@ -88,54 +101,54 @@ typedef enum {
|
|||||||
// -- Logger --
|
// -- Logger --
|
||||||
// ------------
|
// ------------
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* Log levels following a consistent severity-based hierarchy.
|
* Log levels following a consistent severity-based hierarchy.
|
||||||
* Each level includes specific guidance on when it should be used.
|
* Each level includes specific guidance on when it should be used.
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
/**
|
/*
|
||||||
* TRACE: Most detailed information for in-depth debugging
|
* TRACE: Most detailed information for in-depth debugging
|
||||||
* Use for: Deep diagnostic details, function entry/exit, variable dumps
|
* Use for: Deep diagnostic details, function entry/exit, variable dumps
|
||||||
* Visibility: Development environments only, rarely used in production
|
* Visibility: Development environments only, rarely used in production
|
||||||
*/
|
*/
|
||||||
LOG_LEVEL_TRACE,
|
LOG_LEVEL_TRACE,
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* DEBUG: Detailed information useful during development
|
* DEBUG: Detailed information useful during development
|
||||||
* Use for: Development-time debugging, showing variable states, internal flows
|
* Use for: Development-time debugging, showing variable states, internal flows
|
||||||
* Visibility: Development and debugging environments, rarely in production
|
* Visibility: Development and debugging environments, rarely in production
|
||||||
*/
|
*/
|
||||||
LOG_LEVEL_DEBUG,
|
LOG_LEVEL_DEBUG,
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* LOG: General operational events
|
* LOG: General operational events
|
||||||
* Use for: Runtime events worth logging but not requiring attention
|
* Use for: Runtime events worth logging but not requiring attention
|
||||||
* Visibility: Always written to logs, useful for auditing/diagnostics
|
* Visibility: Always written to logs, useful for auditing/diagnostics
|
||||||
*/
|
*/
|
||||||
LOG_LEVEL_LOG,
|
LOG_LEVEL_LOG,
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* INFO: Informational messages highlighting progress
|
* INFO: Informational messages highlighting progress
|
||||||
* Use for: Normal but noteworthy events, state changes, startup/shutdown events
|
* Use for: Normal but noteworthy events, state changes, startup/shutdown events
|
||||||
* Visibility: Visible to client applications if configured
|
* Visibility: Visible to client applications if configured
|
||||||
*/
|
*/
|
||||||
LOG_LEVEL_INFO,
|
LOG_LEVEL_INFO,
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* NOTICE: More important events than INFO, but not warnings
|
* NOTICE: More important events than INFO, but not warnings
|
||||||
* Use for: Important state changes, significant operations, configuration changes
|
* Use for: Important state changes, significant operations, configuration changes
|
||||||
* Visibility: Displayed to client by default, meant to be seen
|
* Visibility: Displayed to client by default, meant to be seen
|
||||||
*/
|
*/
|
||||||
LOG_LEVEL_NOTICE,
|
LOG_LEVEL_NOTICE,
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* WARN: Potential problems that don't prevent normal operation
|
* WARN: Potential problems that don't prevent normal operation
|
||||||
* Use for: Unexpected behaviors, deprecated feature usage, recoverable errors
|
* Use for: Unexpected behaviors, deprecated feature usage, recoverable errors
|
||||||
* Visibility: Alerts both client and server logs, needs attention
|
* Visibility: Alerts both client and server logs, needs attention
|
||||||
*/
|
*/
|
||||||
LOG_LEVEL_WARN,
|
LOG_LEVEL_WARN,
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* EXCEPTION: Serious errors requiring immediate attention
|
* EXCEPTION: Serious errors requiring immediate attention
|
||||||
* Use for: Critical failures, data loss risks, business rule violations
|
* Use for: Critical failures, data loss risks, business rule violations
|
||||||
* Visibility: Highest priority, often leads to operation termination
|
* Visibility: Highest priority, often leads to operation termination
|
||||||
@@ -143,7 +156,7 @@ typedef enum {
|
|||||||
LOG_LEVEL_EXCEPTION
|
LOG_LEVEL_EXCEPTION
|
||||||
} LogLevel;
|
} LogLevel;
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* Structure for complex log level rule
|
* Structure for complex log level rule
|
||||||
* Allows specifying log levels per file, function, and line range
|
* 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);
|
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
|
* Set complex logging rules from a string
|
||||||
* Format: DEFAULT_LEVEL,<file>@<function>=LEVEL,<file>@<line_start>:<line_end>=LEVEL,...
|
* Format: DEFAULT_LEVEL,<file>@<function>=LEVEL,<file>@<line_start>:<line_end>=LEVEL,...
|
||||||
* Example: "INFO,main.c@main=DEBUG,helper.c@10:50=TRACE"
|
* 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);
|
int logger_parse_rules(const char *rules_str);
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* Set complex logging rule programmatically
|
* Set complex logging rule programmatically
|
||||||
*
|
*
|
||||||
* @param level Log level for this rule
|
* @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 logger_add_rule(LogLevel level, const char *file_pattern, const char *function_pattern,
|
||||||
int line_start, int line_end);
|
int line_start, int line_end);
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* Get the effective log level for a message based on complex rules
|
* Get the effective log level for a message based on complex rules
|
||||||
*
|
*
|
||||||
* @param file Source file where log was generated
|
* @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
|
* Used to detect cycles in debug strings
|
||||||
*/
|
*/
|
||||||
typedef struct PtrSet {
|
typedef struct PtrSet {
|
||||||
void **data;
|
void const **data;
|
||||||
size_t size;
|
size_t size;
|
||||||
size_t capacity;
|
size_t capacity;
|
||||||
} PtrSet;
|
} PtrSet;
|
||||||
@@ -369,20 +388,20 @@ typedef struct PtrSet {
|
|||||||
PtrSet *ptrset_init__(const char *file, const char *func, int line, Arena *arena);
|
PtrSet *ptrset_init__(const char *file, const char *func, int line, Arena *arena);
|
||||||
#define ptrset_init(arena) ptrset_init__(__FILE__, __func__, __LINE__, arena)
|
#define ptrset_init(arena) ptrset_init__(__FILE__, __func__, __LINE__, arena)
|
||||||
|
|
||||||
bool debug_ptrset_contains__(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, 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(arena, type, value) DEBUGSTR_##type(arena, value)
|
||||||
|
|
||||||
#define DEBUGSTR_Slice(arena, value) slice_to_debug_str(arena, value)
|
#define DEBUGSTR_Slice(arena, value) slice_to_debug_str(arena, value)
|
||||||
#define DEBUGSTR_Json(arena, value) json_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
|
* Print all current logging rules to stderr for debugging
|
||||||
*/
|
*/
|
||||||
void logger_print_rules();
|
void logger_print_rules();
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* Dump all active logging rules into a string
|
* Dump all active logging rules into a string
|
||||||
*
|
*
|
||||||
* @param arena Memory arena to allocate the string in
|
* @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 *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) \
|
#define STRING_TO_DEBUG_STR(arena, name, string) \
|
||||||
string_to_debug_str__(__FILE__, __func__, __LINE__, arena, name, string)
|
string_to_debug_str__(__FILE__, __func__, __LINE__, arena, name, string)
|
||||||
@@ -617,31 +636,26 @@ typedef enum {
|
|||||||
TEMPLATE_ERROR_NESTED_EXECUTE,
|
TEMPLATE_ERROR_NESTED_EXECUTE,
|
||||||
} TemplateErrorCode;
|
} TemplateErrorCode;
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
TemplateErrorCode code;
|
|
||||||
char *message;
|
|
||||||
} TemplateError;
|
|
||||||
|
|
||||||
struct TemplateNode {
|
struct TemplateNode {
|
||||||
TemplateError error;
|
|
||||||
TemplateNodeType type;
|
TemplateNodeType type;
|
||||||
TemplateValue value;
|
TemplateValue value;
|
||||||
TemplateNode *children; // child nodes
|
TemplateNode *children; // child nodes
|
||||||
TemplateNode *next; // sibling 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);
|
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);
|
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_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_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
|
#endif // EPRINTF_H
|
||||||
@@ -84,7 +84,7 @@ while [ $# -gt 0 ]; do
|
|||||||
done
|
done
|
||||||
|
|
||||||
MODE="${1:-build}"
|
MODE="${1:-build}"
|
||||||
shift
|
shift > /dev/null
|
||||||
|
|
||||||
if [ -n "$COLOR_FLAG" ]; then
|
if [ -n "$COLOR_FLAG" ]; then
|
||||||
CFLAGS="$CFLAGS $COLOR_FLAG"
|
CFLAGS="$CFLAGS $COLOR_FLAG"
|
||||||
@@ -118,16 +118,13 @@ case "$MODE" in
|
|||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
# If no specific tests provided, run all
|
echo "TESTS_TO_RUN: ${TESTS_TO_RUN[@]}"
|
||||||
if [ ${#TESTS_TO_RUN[@]} -eq 0 ]; then
|
|
||||||
TESTS_TO_RUN=("all")
|
|
||||||
fi
|
|
||||||
|
|
||||||
for test_file in test/*.c; do
|
for test_file in test/*.c; do
|
||||||
test_name=$(basename "${test_file%.c}")
|
test_name=$(basename "${test_file%.c}")
|
||||||
|
|
||||||
# Skip if specific tests are requested and this isn't one of them
|
# 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
|
continue
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ static void test_template_node_to_debug_str(Arena *arena) {
|
|||||||
root->next->next->type = TEMPLATE_NODE_TEXT;
|
root->next->next->type = TEMPLATE_NODE_TEXT;
|
||||||
root->next->next->value.text.content = arena_strncpy(arena, "!", 1);
|
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);
|
raise_notice("debug_str: %s", debug_str);
|
||||||
//assert(strcmp(
|
//assert(strcmp(
|
||||||
|
|||||||
Reference in New Issue
Block a user