feat: hectic C: debug to json parser

This commit is contained in:
2025-04-14 19:43:57 +00:00
parent 1dcb165abf
commit d45307336a
4 changed files with 319 additions and 60 deletions

View File

@@ -325,7 +325,7 @@ char *string_to_debug_str__(CTX_DECLARATION, const char *name, const char *strin
// Check if the pointer is readable.
if (!is_readable(string))
return arena_strdup_fmt__(CTX(arena), "%s = unreadable", name);
return arena_strdup_fmt__(CTX(arena), "%s = <memory unreadable>", name);
return arena_strdup_fmt__(CTX(arena), "%s = %s%p%s \"%s\"",
name, DEBUG_COLOR(COLOR_CYAN), string,
@@ -385,14 +385,14 @@ char *union_to_debug_str__(POSITION_INFO_DECLARATION, Arena *arena, const char *
if (!variant_exists) {
return arena_strdup_fmt__(file, func, line, arena,
"%sunion%s %s %s = {invalid variant %d} %s%p%s",
"%sunion%s %s %s = <invalid variant %d> %s%p%s",
DEBUG_COLOR(COLOR_GREEN), DEBUG_COLOR(COLOR_RESET),
type, name, active_variant, DEBUG_COLOR(COLOR_CYAN), ptr, DEBUG_COLOR(COLOR_RESET));
}
if (!value) {
return arena_strdup_fmt__(file, func, line, arena,
"%sunion%s %s %s = {unknown variant} %s%p%s",
"%sunion%s %s %s = <unknown variant> %s%p%s",
DEBUG_COLOR(COLOR_GREEN), DEBUG_COLOR(COLOR_RESET),
type, name, DEBUG_COLOR(COLOR_CYAN), ptr, DEBUG_COLOR(COLOR_RESET));
}
@@ -1473,12 +1473,254 @@ char* json_to_debug_str__(POSITION_INFO_DECLARATION, Arena *arena, Json json) {
return result;
}
JsonResult debug_str_to_json__(POSITION_INFO_DECLARATION, Arena *arena, const char **s) {
raise_message(LOG_LEVEL_TRACE, POSITION_INFO, "DEBUG STR TO JSON: debug_str: %s", *s);
// Remove the unused 'start' variable
Json *json = arena_alloc__(POSITION_INFO, arena, sizeof(Json));
memset(json, 0, sizeof(Json));
// Extract the name/key
const char *equal_sign = strstr(*s, "=");
if (!equal_sign) {
raise_message(LOG_LEVEL_EXCEPTION, POSITION_INFO, "DEBUG STR TO JSON: no equal sign found");
return RESULT_ERROR(JsonResult, DEBUG_TO_JSON_PARSE_NO_EQUAL_SIGN_ERROR, "No equal sign found");
}
Slice full_name = slice_create__(POSITION_INFO, 1, *s, strlen(*s), 0, equal_sign - *s);
if (full_name.len == 0) {
raise_message(LOG_LEVEL_EXCEPTION, POSITION_INFO, "DEBUG STR TO JSON: no name found");
return RESULT_ERROR(JsonResult, DEBUG_TO_JSON_PARSE_LEFT_OPERAND_ERROR, "No left operand found");
}
// Move past the equal sign
*s = skip_whitespace(equal_sign + 1);
// Check for struct, union, enum, or other types
const char *name_str = full_name.data;
name_str = skip_whitespace(name_str);
if (strncmp(name_str, "struct ", 7) == 0) {
// Handle struct
json->type = JSON_OBJECT;
// Extract struct type and name
name_str += 7; // Skip "struct "
const char *space = strchr(name_str, ' ');
if (!space) {
raise_message(LOG_LEVEL_EXCEPTION, POSITION_INFO, "DEBUG STR TO JSON: missing struct name");
return RESULT_ERROR(JsonResult, DEBUG_TO_JSON_PARSE_NO_STRUCT_NAME_ERROR, "Struct without name");
}
// Extract type (between "struct " and space)
// Extract name (after space, before any other character)
name_str = skip_whitespace(space + 1);
const char *name_end = name_str;
while (*name_end && !isspace(*name_end) && *name_end != '{') name_end++;
if (name_end == name_str) {
raise_message(LOG_LEVEL_EXCEPTION, POSITION_INFO, "DEBUG STR TO JSON: missing struct variable name");
return RESULT_ERROR(JsonResult, DEBUG_TO_JSON_PARSE_NO_STRUCT_NAME_ERROR, "Struct without variable name");
}
size_t name_len = name_end - name_str;
json->key = arena_strncpy__(POSITION_INFO, arena, name_str, name_len);
// Find struct body
const char *body_start = strchr(name_end, '{');
if (!body_start) {
raise_message(LOG_LEVEL_EXCEPTION, POSITION_INFO, "DEBUG STR TO JSON: no start found for struct");
return RESULT_ERROR(JsonResult, DEBUG_TO_JSON_PARSE_NO_START_ERROR, "Struct without start");
}
const char *body_end = strrchr(body_start, '}');
if (!body_end) {
raise_message(LOG_LEVEL_EXCEPTION, POSITION_INFO, "DEBUG STR TO JSON: no end found for struct");
return RESULT_ERROR(JsonResult, DEBUG_TO_JSON_PARSE_NO_END_ERROR, "Struct without end");
}
// Move pointer past the struct
*s = body_end + 1;
// TODO: Parse struct fields
// For now, we're just creating an empty object
}
else if (strncmp(name_str, "union ", 6) == 0) {
// Handle union
json->type = JSON_OBJECT;
// Extract union name
name_str += 6; // Skip "union "
const char *space = strchr(name_str, ' ');
if (!space) {
raise_message(LOG_LEVEL_EXCEPTION, POSITION_INFO, "DEBUG STR TO JSON: missing union name");
return RESULT_ERROR(JsonResult, DEBUG_TO_JSON_PARSE_NO_STRUCT_NAME_ERROR, "Union without name");
}
// Extract type (between "union " and space)
// Extract name (after space, before any other character)
name_str = skip_whitespace(space + 1);
const char *name_end = name_str;
while (*name_end && !isspace(*name_end) && *name_end != '{') name_end++;
size_t name_len = name_end - name_str;
json->key = arena_strncpy__(POSITION_INFO, arena, name_str, name_len);
// Find body
const char *body_start = strchr(name_end, '{');
if (!body_start) {
raise_message(LOG_LEVEL_EXCEPTION, POSITION_INFO, "DEBUG STR TO JSON: no start found for union");
return RESULT_ERROR(JsonResult, DEBUG_TO_JSON_PARSE_NO_START_ERROR, "Union without start");
}
const char *body_end = strrchr(body_start, '}');
if (!body_end) {
raise_message(LOG_LEVEL_EXCEPTION, POSITION_INFO, "DEBUG STR TO JSON: no end found for union");
return RESULT_ERROR(JsonResult, DEBUG_TO_JSON_PARSE_NO_END_ERROR, "Union without end");
}
// Move pointer past the union
*s = body_end + 1;
// TODO: Parse union variant
// For now, we're just creating an empty object
}
else if (strncmp(name_str, "enum ", 5) == 0) {
// Handle enum
json->type = JSON_STRING;
// Find enum value (typically at the end)
const char *value_start = strrchr(*s, ' ');
if (!value_start) {
raise_message(LOG_LEVEL_EXCEPTION, POSITION_INFO, "DEBUG STR TO JSON: missing enum value");
return RESULT_ERROR(JsonResult, DEBUG_TO_JSON_PARSE_LEFT_OPERAND_ERROR, "Invalid enum format");
}
// Extract name
name_str += 5; // Skip "enum "
const char *space = strchr(name_str, ' ');
if (space) {
size_t name_len = space - name_str;
json->key = arena_strncpy__(POSITION_INFO, arena, name_str, name_len);
}
// Extract value as string
value_start = skip_whitespace(value_start + 1);
json->JsonValue.string = arena_strdup__(POSITION_INFO, arena, value_start);
// Move pointer to the end
*s += strlen(*s);
}
else if (strchr(name_str, '[') && strchr(name_str, ']')) {
// Handle array
json->type = JSON_ARRAY;
// Extract array name
const char *bracket = strchr(name_str, '[');
if (bracket > name_str) {
const char *name_end = bracket;
while (name_end > name_str && isspace(*(name_end-1))) name_end--;
size_t name_len = name_end - name_str;
json->key = arena_strncpy__(POSITION_INFO, arena, name_str, name_len);
}
// Find array body
const char *body_start = strchr(*s, '[');
if (!body_start) {
raise_message(LOG_LEVEL_EXCEPTION, POSITION_INFO, "DEBUG STR TO JSON: no start found for array");
return RESULT_ERROR(JsonResult, DEBUG_TO_JSON_PARSE_NO_START_ERROR, "Array without start");
}
const char *body_end = strrchr(body_start, ']');
if (!body_end) {
raise_message(LOG_LEVEL_EXCEPTION, POSITION_INFO, "DEBUG STR TO JSON: no end found for array");
return RESULT_ERROR(JsonResult, DEBUG_TO_JSON_PARSE_NO_END_ERROR, "Array without end");
}
// Move pointer past the array
*s = body_end + 1;
// TODO: Parse array elements
// For now, we're just creating an empty array
}
else {
// Try to determine value type (string, number, bool, null)
const char *value = *s;
if (strncmp(value, "NULL", 4) == 0 || strncmp(value, "null", 4) == 0) {
json->type = JSON_NULL;
*s += 4;
}
else if (strncmp(value, "true", 4) == 0) {
json->type = JSON_BOOL;
json->JsonValue.boolean = true;
*s += 4;
}
else if (strncmp(value, "false", 5) == 0) {
json->type = JSON_BOOL;
json->JsonValue.boolean = false;
*s += 5;
}
else if (*value == '"') {
// String value
json->type = JSON_STRING;
value++; // Skip opening quote
const char *end_quote = strchr(value, '"');
if (!end_quote) {
raise_message(LOG_LEVEL_EXCEPTION, POSITION_INFO, "DEBUG STR TO JSON: unterminated string");
return RESULT_ERROR(JsonResult, DEBUG_TO_JSON_PARSE_LEFT_OPERAND_ERROR, "Unterminated string");
}
size_t str_len = end_quote - value;
json->JsonValue.string = arena_strncpy__(POSITION_INFO, arena, value, str_len);
*s = end_quote + 1;
}
else if (isdigit(*value) || *value == '-' || *value == '+') {
// Numeric value
json->type = JSON_NUMBER;
// Use strtod to parse the number
char *end;
json->JsonValue.number = strtod(value, &end);
*s = end;
}
else {
// Default to string for unknown types
json->type = JSON_STRING;
// Find the end of the value (space, comma, etc.)
const char *end = value;
while (*end && !isspace(*end) && *end != ',' && *end != '}' && *end != ']') end++;
size_t str_len = end - value;
json->JsonValue.string = arena_strncpy__(POSITION_INFO, arena, value, str_len);
*s = end;
}
// Extract name for simple types
const char *name_end = name_str;
while (*name_end && !isspace(*name_end) && *name_end != '=') name_end++;
size_t name_len = name_end - name_str;
json->key = arena_strncpy__(POSITION_INFO, arena, name_str, name_len);
}
return RESULT_SOME(JsonResult, *json);
}
// -----------
// -- slice --
// -----------
// Create a slice from an array with boundary check.
Slice slice_create__(POSITION_INFO_DECLARATION, size_t isize, void *array, size_t array_len, size_t start, size_t len) {
Slice slice_create__(POSITION_INFO_DECLARATION, size_t isize, const void *array, size_t array_len, size_t start, size_t len) {
// Function entry logging
raise_message(LOG_LEVEL_TRACE, POSITION_INFO,
"SLICE: Creating slice (source: %p, array_length: %zu, start: %zu, length: %zu, item_size: %zu)",