feat: hectic C: debug to json parser
This commit is contained in:
@@ -325,7 +325,7 @@ char *string_to_debug_str__(CTX_DECLARATION, const char *name, const char *strin
|
|||||||
|
|
||||||
// Check if the pointer is readable.
|
// Check if the pointer is readable.
|
||||||
if (!is_readable(string))
|
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\"",
|
return arena_strdup_fmt__(CTX(arena), "%s = %s%p%s \"%s\"",
|
||||||
name, DEBUG_COLOR(COLOR_CYAN), string,
|
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) {
|
if (!variant_exists) {
|
||||||
return arena_strdup_fmt__(file, func, line, arena,
|
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),
|
DEBUG_COLOR(COLOR_GREEN), DEBUG_COLOR(COLOR_RESET),
|
||||||
type, name, active_variant, DEBUG_COLOR(COLOR_CYAN), ptr, DEBUG_COLOR(COLOR_RESET));
|
type, name, active_variant, DEBUG_COLOR(COLOR_CYAN), ptr, DEBUG_COLOR(COLOR_RESET));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!value) {
|
if (!value) {
|
||||||
return arena_strdup_fmt__(file, func, line, arena,
|
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),
|
DEBUG_COLOR(COLOR_GREEN), DEBUG_COLOR(COLOR_RESET),
|
||||||
type, name, DEBUG_COLOR(COLOR_CYAN), ptr, 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;
|
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 --
|
// -- slice --
|
||||||
// -----------
|
// -----------
|
||||||
|
|
||||||
// Create a slice from an array with boundary check.
|
// 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
|
// Function entry logging
|
||||||
raise_message(LOG_LEVEL_TRACE, POSITION_INFO,
|
raise_message(LOG_LEVEL_TRACE, POSITION_INFO,
|
||||||
"SLICE: Creating slice (source: %p, array_length: %zu, start: %zu, length: %zu, item_size: %zu)",
|
"SLICE: Creating slice (source: %p, array_length: %zu, start: %zu, length: %zu, item_size: %zu)",
|
||||||
|
|||||||
@@ -85,6 +85,11 @@ typedef enum {
|
|||||||
TEMPLATE_ERROR_OUT_OF_MEMORY = 985575,
|
TEMPLATE_ERROR_OUT_OF_MEMORY = 985575,
|
||||||
LOGGER_ERROR_INVALID_RULES_STRING = 985576,
|
LOGGER_ERROR_INVALID_RULES_STRING = 985576,
|
||||||
LOGGER_ERROR_OUT_OF_MEMORY = 985577,
|
LOGGER_ERROR_OUT_OF_MEMORY = 985577,
|
||||||
|
DEBUG_TO_JSON_PARSE_NO_EQUAL_SIGN_ERROR = 985578,
|
||||||
|
DEBUG_TO_JSON_PARSE_NO_STRUCT_NAME_ERROR = 985579,
|
||||||
|
DEBUG_TO_JSON_PARSE_LEFT_OPERAND_ERROR = 985580,
|
||||||
|
DEBUG_TO_JSON_PARSE_NO_START_ERROR = 985581,
|
||||||
|
DEBUG_TO_JSON_PARSE_NO_END_ERROR = 985582,
|
||||||
} HecticErrorCode;
|
} HecticErrorCode;
|
||||||
|
|
||||||
// Define color macros based on output type
|
// Define color macros based on output type
|
||||||
@@ -464,7 +469,7 @@ bool debug_ptrset_contains(PtrSet *set, void *ptr);
|
|||||||
name = "$1"; \
|
name = "$1"; \
|
||||||
\
|
\
|
||||||
if (debug_ptrset_contains__(visited, ptr, #type, name)) \
|
if (debug_ptrset_contains__(visited, ptr, #type, name)) \
|
||||||
return arena_strdup_fmt__(__FILE__, __func__, __LINE__, arena, "%sunion%s %s %s = {cycle detected} %s%p%s", DEBUG_COLOR(COLOR_GREEN), DEBUG_COLOR(COLOR_RESET), #type, name, DEBUG_COLOR(COLOR_CYAN), ptr, DEBUG_COLOR(COLOR_RESET)); \
|
return arena_strdup_fmt__(__FILE__, __func__, __LINE__, arena, "%sunion%s %s %s = <cycle detected> %s%p%s", DEBUG_COLOR(COLOR_GREEN), DEBUG_COLOR(COLOR_RESET), #type, name, DEBUG_COLOR(COLOR_CYAN), ptr, DEBUG_COLOR(COLOR_RESET)); \
|
||||||
\
|
\
|
||||||
if (!ptr) \
|
if (!ptr) \
|
||||||
return arena_strdup_fmt__(__FILE__, __func__, __LINE__, arena, "%sunion%s %s %s = NULL", DEBUG_COLOR(COLOR_GREEN), DEBUG_COLOR(COLOR_RESET), #type, name); \
|
return arena_strdup_fmt__(__FILE__, __func__, __LINE__, arena, "%sunion%s %s %s = NULL", DEBUG_COLOR(COLOR_GREEN), DEBUG_COLOR(COLOR_RESET), #type, name); \
|
||||||
@@ -504,7 +509,7 @@ bool debug_ptrset_contains(PtrSet *set, void *ptr);
|
|||||||
name = "$1"; \
|
name = "$1"; \
|
||||||
\
|
\
|
||||||
if (debug_ptrset_contains__(visited, ptr, #type, name)) \
|
if (debug_ptrset_contains__(visited, ptr, #type, name)) \
|
||||||
return arena_strdup_fmt__(__FILE__, __func__, __LINE__, arena, "%sstruct%s %s %s = {cycle detected} %s%p%s", DEBUG_COLOR(COLOR_GREEN), DEBUG_COLOR(COLOR_RESET), #type, name, DEBUG_COLOR(COLOR_CYAN), ptr, DEBUG_COLOR(COLOR_RESET)); \
|
return arena_strdup_fmt__(__FILE__, __func__, __LINE__, arena, "%sstruct%s %s %s = <cycle detected> %s%p%s", DEBUG_COLOR(COLOR_GREEN), DEBUG_COLOR(COLOR_RESET), #type, name, DEBUG_COLOR(COLOR_CYAN), ptr, DEBUG_COLOR(COLOR_RESET)); \
|
||||||
\
|
\
|
||||||
if (!ptr) \
|
if (!ptr) \
|
||||||
return arena_strdup_fmt__(__FILE__, __func__, __LINE__, arena, "%sstruct%s %s %s = NULL", DEBUG_COLOR(COLOR_GREEN), DEBUG_COLOR(COLOR_RESET), #type, name); \
|
return arena_strdup_fmt__(__FILE__, __func__, __LINE__, arena, "%sstruct%s %s %s = NULL", DEBUG_COLOR(COLOR_GREEN), DEBUG_COLOR(COLOR_RESET), #type, name); \
|
||||||
@@ -588,6 +593,8 @@ typedef struct Json {
|
|||||||
} JsonValue;
|
} JsonValue;
|
||||||
} Json;
|
} Json;
|
||||||
|
|
||||||
|
RESULT(Json, Json);
|
||||||
|
|
||||||
#define json_parse(arena, s) json_parse__(__FILE__, __func__, __LINE__, arena, s)
|
#define json_parse(arena, s) json_parse__(__FILE__, __func__, __LINE__, arena, s)
|
||||||
Json *json_parse__(const char* file, const char* func, int line, Arena *arena, const char **s);
|
Json *json_parse__(const char* file, const char* func, int line, Arena *arena, const char **s);
|
||||||
|
|
||||||
@@ -608,8 +615,12 @@ 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);
|
char *json_to_pretty_str__(const char* file, const char* func, int line, Arena *arena, const Json * const item, int indent_level);
|
||||||
|
|
||||||
|
JsonResult debug_str_to_json__(const char* file, const char* func, int line, Arena *arena, const char **s);
|
||||||
|
|
||||||
#define json_to_pretty_str(arena, json) json_to_pretty_str__(__FILE__, __func__, __LINE__, arena, json, 0)
|
#define json_to_pretty_str(arena, json) json_to_pretty_str__(__FILE__, __func__, __LINE__, arena, json, 0)
|
||||||
|
|
||||||
|
#define DEBUG_STR_TO_JSON(arena, debug_ptr) debug_str_to_json__(__FILE__, __func__, __LINE__, arena, debug_ptr)
|
||||||
|
|
||||||
// -----------
|
// -----------
|
||||||
// -- Slice --
|
// -- Slice --
|
||||||
// -----------
|
// -----------
|
||||||
@@ -625,7 +636,7 @@ typedef struct {
|
|||||||
// printf("Content: %d\n", SLICE_ARGS(slice, int));
|
// printf("Content: %d\n", SLICE_ARGS(slice, int));
|
||||||
#define SLICE_ARGS(slice, type) ((int)((slice).len / sizeof(type))), ((type*)((slice).data))
|
#define SLICE_ARGS(slice, type) ((int)((slice).len / sizeof(type))), ((type*)((slice).data))
|
||||||
|
|
||||||
Slice slice_create__(const char *file, const char *func, int line, size_t isize, void *array, size_t array_len, size_t start, size_t len);
|
Slice slice_create__(const char *file, const char *func, int line, size_t isize, const void *array, size_t array_len, size_t start, size_t len);
|
||||||
|
|
||||||
Slice slice_subslice__(const char *file, const char *func, int line, Slice s, size_t start, size_t len);
|
Slice slice_subslice__(const char *file, const char *func, int line, Slice s, size_t start, size_t len);
|
||||||
|
|
||||||
|
|||||||
@@ -8,91 +8,76 @@
|
|||||||
#define ARENA_SIZE 1024 * 1024
|
#define ARENA_SIZE 1024 * 1024
|
||||||
|
|
||||||
// Test 1: Parse JSON object with a string value.
|
// Test 1: Parse JSON object with a string value.
|
||||||
static void test_parse_json_object(void) {
|
static void test_parse_json_object(Arena *arena) {
|
||||||
Arena arena = arena_init(ARENA_SIZE);
|
|
||||||
const char *json = "{\"key\":\"value\"}";
|
const char *json = "{\"key\":\"value\"}";
|
||||||
Json *root = json_parse(&arena, &json);
|
Json *root = json_parse(arena, &json);
|
||||||
assert(root->type == JSON_OBJECT);
|
assert(root->type == JSON_OBJECT);
|
||||||
Json *child = root->child;
|
Json *child = root->child;
|
||||||
assert(child && strcmp(child->key, "key") == 0);
|
assert(child && strcmp(child->key, "key") == 0);
|
||||||
assert(child->type == JSON_STRING);
|
assert(child->type == JSON_STRING);
|
||||||
assert(strcmp(child->JsonValue.string, "value") == 0);
|
assert(strcmp(child->JsonValue.string, "value") == 0);
|
||||||
arena_free(&arena);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test 2: Parse JSON number.
|
// Test 2: Parse JSON number.
|
||||||
static void test_parse_json_number(void) {
|
static void test_parse_json_number(Arena *arena) {
|
||||||
Arena arena = arena_init(ARENA_SIZE);
|
|
||||||
const char *json = "42";
|
const char *json = "42";
|
||||||
Json *root = json_parse(&arena, &json);
|
Json *root = json_parse(arena, &json);
|
||||||
assert(root->type == JSON_NUMBER);
|
assert(root->type == JSON_NUMBER);
|
||||||
assert(root->JsonValue.number == 42);
|
assert(root->JsonValue.number == 42);
|
||||||
arena_free(&arena);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test 3: Parse JSON string.
|
// Test 3: Parse JSON string.
|
||||||
static void test_parse_json_string(void) {
|
static void test_parse_json_string(Arena *arena) {
|
||||||
Arena arena = {0};
|
|
||||||
const char *json = "\"hello\"";
|
const char *json = "\"hello\"";
|
||||||
Json *root = json_parse(&arena, &json);
|
Json *root = json_parse(arena, &json);
|
||||||
assert(root->type == JSON_STRING);
|
assert(root->type == JSON_STRING);
|
||||||
assert(strcmp(root->JsonValue.string, "hello") == 0);
|
assert(strcmp(root->JsonValue.string, "hello") == 0);
|
||||||
arena_free(&arena);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test 4: Get object items by key.
|
// Test 4: Get object items by key.
|
||||||
static void test_get_object_items(void) {
|
static void test_get_object_items(Arena *arena) {
|
||||||
Arena arena = arena_init(ARENA_SIZE);
|
|
||||||
const char *json = "{\"a\":\"1\", \"b\":2}";
|
const char *json = "{\"a\":\"1\", \"b\":2}";
|
||||||
Json *root = json_parse(&arena, &json);
|
Json *root = json_parse(arena, &json);
|
||||||
Json *item_a = json_get_object_item(root, "a");
|
Json *item_a = json_get_object_item(root, "a");
|
||||||
assert(item_a && item_a->type == JSON_STRING);
|
assert(item_a && item_a->type == JSON_STRING);
|
||||||
assert(strcmp(item_a->JsonValue.string, "1") == 0);
|
assert(strcmp(item_a->JsonValue.string, "1") == 0);
|
||||||
Json *item_b = json_get_object_item(root, "b");
|
Json *item_b = json_get_object_item(root, "b");
|
||||||
assert(item_b && item_b->type == JSON_NUMBER);
|
assert(item_b && item_b->type == JSON_NUMBER);
|
||||||
assert(item_b->JsonValue.number == 2);
|
assert(item_b->JsonValue.number == 2);
|
||||||
arena_free(&arena);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test 5: Print JSON object.
|
// Test 5: Print JSON object.
|
||||||
static void test_print_json_object(void) {
|
static void test_print_json_object(Arena *arena) {
|
||||||
Arena arena = arena_init(ARENA_SIZE);
|
|
||||||
const char *json = "{\"key\":\"value\", \"num\":3.14}";
|
const char *json = "{\"key\":\"value\", \"num\":3.14}";
|
||||||
Json *root = json_parse(&arena, &json);
|
Json *root = json_parse(arena, &json);
|
||||||
char *printed = json_to_string(&arena, root);
|
char *printed = json_to_string(arena, root);
|
||||||
assert(strstr(printed, "\"key\":") != NULL);
|
assert(strstr(printed, "\"key\":") != NULL);
|
||||||
assert(strstr(printed, "\"value\"") != NULL);
|
assert(strstr(printed, "\"value\"") != NULL);
|
||||||
assert(strstr(printed, "\"num\":") != NULL);
|
assert(strstr(printed, "\"num\":") != NULL);
|
||||||
assert(strstr(printed, "3.14") != NULL);
|
assert(strstr(printed, "3.14") != NULL);
|
||||||
arena_free(&arena);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test 6: Print JSON number.
|
// Test 6: Print JSON number.
|
||||||
static void test_print_json_number(void) {
|
static void test_print_json_number(Arena *arena) {
|
||||||
Arena arena = arena_init(ARENA_SIZE);
|
|
||||||
const char *json = "123.456";
|
const char *json = "123.456";
|
||||||
Json *root = json_parse(&arena, &json);
|
Json *root = json_parse(arena, &json);
|
||||||
char *printed = json_to_string(&arena, root);
|
char *printed = json_to_string(arena, root);
|
||||||
double val = atof(printed);
|
double val = atof(printed);
|
||||||
assert(val == 123.456);
|
assert(val == 123.456);
|
||||||
arena_free(&arena);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test 7: Print JSON string.
|
// Test 7: Print JSON string.
|
||||||
static void test_print_json_string(void) {
|
static void test_print_json_string(Arena *arena) {
|
||||||
Arena arena = arena_init(ARENA_SIZE);
|
|
||||||
const char *json = "\"test string\"";
|
const char *json = "\"test string\"";
|
||||||
Json *root = json_parse(&arena, &json);
|
Json *root = json_parse(arena, &json);
|
||||||
char *printed = json_to_string(&arena, root);
|
char *printed = json_to_string(arena, root);
|
||||||
assert(strcmp(printed, "\"test string\"") == 0);
|
assert(strcmp(printed, "\"test string\"") == 0);
|
||||||
arena_free(&arena);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test 8: Nested JSON object.
|
// Test 8: Nested JSON object.
|
||||||
static void test_nested_json_object(void) {
|
static void test_nested_json_object(Arena *arena) {
|
||||||
Arena arena = arena_init(1024 * 1024);
|
|
||||||
const char *json = "{\"outer\":{\"inner\":100}}";
|
const char *json = "{\"outer\":{\"inner\":100}}";
|
||||||
Json *root = json_parse(&arena, &json);
|
Json *root = json_parse(arena, &json);
|
||||||
assert(root != NULL);
|
assert(root != NULL);
|
||||||
assert(root->type == JSON_OBJECT);
|
assert(root->type == JSON_OBJECT);
|
||||||
|
|
||||||
@@ -105,38 +90,59 @@ static void test_nested_json_object(void) {
|
|||||||
assert(inner->type == JSON_NUMBER);
|
assert(inner->type == JSON_NUMBER);
|
||||||
assert(inner->JsonValue.number == 100);
|
assert(inner->JsonValue.number == 100);
|
||||||
|
|
||||||
arena_free(&arena);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test 9: Arena reset and reuse.
|
// Test 9: Arena reset and reuse.
|
||||||
static void test_arena_reset_reuse(void) {
|
static void test_arena_reset_reuse(Arena *arena) {
|
||||||
Arena arena = arena_init(ARENA_SIZE);
|
|
||||||
const char *json1 = "{\"key\":\"value\"}";
|
const char *json1 = "{\"key\":\"value\"}";
|
||||||
Json *root1 = json_parse(&arena, &json1);
|
Json *root1 = json_parse(arena, &json1);
|
||||||
char *printed1 = json_to_string(&arena, root1);
|
char *printed1 = json_to_string(arena, root1);
|
||||||
assert(strcmp(printed1, "{\"key\":\"value\"}") == 0);
|
assert(strcmp(printed1, "{\"key\":\"value\"}") == 0);
|
||||||
arena_reset(&arena);
|
arena_reset(arena);
|
||||||
const char *json2 = "\"another test\"";
|
const char *json2 = "\"another test\"";
|
||||||
Json *root2 = json_parse(&arena, &json2);
|
Json *root2 = json_parse(arena, &json2);
|
||||||
char *printed2 = json_to_string(&arena, root2);
|
char *printed2 = json_to_string(arena, root2);
|
||||||
assert(strcmp(printed2, "\"another test\"") == 0);
|
assert(strcmp(printed2, "\"another test\"") == 0);
|
||||||
arena_free(&arena);
|
}
|
||||||
|
|
||||||
|
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_string(arena, &RESULT_SOME_VALUE(result)));
|
||||||
|
assert(RESULT_SOME_VALUE(result).type == JSON_OBJECT);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
printf("%sRunning %s%s%s\n", OPTIONAL_COLOR(COLOR_GREEN), OPTIONAL_COLOR(COLOR_CYAN), __FILE__, OPTIONAL_COLOR(COLOR_RESET));
|
printf("%sRunning %s%s%s\n", OPTIONAL_COLOR(COLOR_GREEN), OPTIONAL_COLOR(COLOR_CYAN), __FILE__, OPTIONAL_COLOR(COLOR_RESET));
|
||||||
logger_init();
|
logger_init();
|
||||||
|
|
||||||
test_parse_json_object();
|
Arena arena = arena_init(ARENA_SIZE);
|
||||||
test_parse_json_number();
|
|
||||||
test_parse_json_string();
|
|
||||||
test_get_object_items();
|
|
||||||
test_print_json_object();
|
|
||||||
test_print_json_number();
|
|
||||||
test_print_json_string();
|
|
||||||
test_nested_json_object();
|
|
||||||
test_arena_reset_reuse();
|
|
||||||
|
|
||||||
|
test_parse_json_object(&arena);
|
||||||
|
arena_reset(&arena);
|
||||||
|
test_parse_json_number(&arena);
|
||||||
|
arena_reset(&arena);
|
||||||
|
test_parse_json_string(&arena);
|
||||||
|
arena_reset(&arena);
|
||||||
|
test_get_object_items(&arena);
|
||||||
|
arena_reset(&arena);
|
||||||
|
test_print_json_object(&arena);
|
||||||
|
arena_reset(&arena);
|
||||||
|
test_print_json_number(&arena);
|
||||||
|
arena_reset(&arena);
|
||||||
|
test_print_json_string(&arena);
|
||||||
|
arena_reset(&arena);
|
||||||
|
test_nested_json_object(&arena);
|
||||||
|
arena_reset(&arena);
|
||||||
|
test_arena_reset_reuse(&arena);
|
||||||
|
arena_reset(&arena);
|
||||||
|
test_debug_str_to_json(&arena);
|
||||||
|
|
||||||
|
arena_free(&arena);
|
||||||
logger_free();
|
logger_free();
|
||||||
printf("%sall tests passed.%s%s%s\n", OPTIONAL_COLOR(COLOR_GREEN), OPTIONAL_COLOR(COLOR_CYAN), __FILE__, OPTIONAL_COLOR(COLOR_RESET));
|
printf("%sall tests passed.%s%s%s\n", OPTIONAL_COLOR(COLOR_GREEN), OPTIONAL_COLOR(COLOR_CYAN), __FILE__, OPTIONAL_COLOR(COLOR_RESET));
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -89,6 +89,6 @@ int main(void) {
|
|||||||
|
|
||||||
logger_free();
|
logger_free();
|
||||||
arena_free(&arena);
|
arena_free(&arena);
|
||||||
printf("%sall tests passed.%s%s%s\n", OPTIONAL_COLOR(COLOR_GREEN), OPTIONAL_COLOR(COLOR_CYAN), __FILE__, OPTIONAL_COLOR(COLOR_RESET));
|
printf("%sall tests passed %s%s%s\n", OPTIONAL_COLOR(COLOR_GREEN), OPTIONAL_COLOR(COLOR_CYAN), __FILE__, OPTIONAL_COLOR(COLOR_RESET));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user