From 9e353dd1c9ed16b535333d7c1d909fa16d2ec013 Mon Sep 17 00:00:00 2001 From: jacob Date: Wed, 30 Jul 2025 18:28:23 -0500 Subject: [PATCH] json layer refactor --- src/gp/gp_core_dx12.c | 2 +- src/inc/inc_core.c | 4 +- src/inc/inc_core.h | 4 +- src/json/json_core.c | 713 +++++++++++++++++++---------------- src/json/json_core.h | 140 ++++++- src/platform/platform_log.c | 32 -- src/platform/platform_log.h | 33 +- src/resource/resource_core.c | 2 +- src/settings/settings_core.c | 16 +- 9 files changed, 570 insertions(+), 376 deletions(-) diff --git a/src/gp/gp_core_dx12.c b/src/gp/gp_core_dx12.c index 246019c8..f379918a 100644 --- a/src/gp/gp_core_dx12.c +++ b/src/gp/gp_core_dx12.c @@ -409,7 +409,7 @@ void gp_startup(void) G.fenced_releases_arena = AllocArena(Gibi(64)); /* Initialize embedded shader archive */ - String embedded_data = inc_dxc_tar(); + String embedded_data = INC_GetDxcTar(); if (embedded_data.len <= 0) { P_Panic(Lit("No embedded shaders found")); } diff --git a/src/inc/inc_core.c b/src/inc/inc_core.c index cf7b5410..d00aac13 100644 --- a/src/inc/inc_core.c +++ b/src/inc/inc_core.c @@ -5,7 +5,7 @@ #if RESOURCES_EMBEDDED IncbinInclude(res_tar, IncbinDir "res.tar"); -String inc_res_tar(void) +String INC_GetResTar(void) { return IncbinGet(res_tar); } @@ -13,7 +13,7 @@ String inc_res_tar(void) IncbinInclude(dxc_tar, IncbinDir "dxc.tar"); -String inc_dxc_tar(void) +String INC_GetDxcTar(void) { return IncbinGet(dxc_tar); } diff --git a/src/inc/inc_core.h b/src/inc/inc_core.h index 48433707..f6035ff3 100644 --- a/src/inc/inc_core.h +++ b/src/inc/inc_core.h @@ -1,5 +1,5 @@ #if RESOURCES_EMBEDDED -String inc_res_tar(void); +String INC_GetResTar(void); #endif -String inc_dxc_tar(void); +String INC_GetDxcTar(void); diff --git a/src/json/json_core.c b/src/json/json_core.c index 57f2c643..81ceebd4 100644 --- a/src/json/json_core.c +++ b/src/json/json_core.c @@ -3,189 +3,151 @@ * - Don't allow leading 0s in numbers */ -/* ========================== * - * Lex - * ========================== */ +//////////////////////////////// +//~ Lex -#define CASE_NEWLINE \ - case 0x0A: /* Line feed or New line */ \ - case 0x0D /* Carriage return */ - -#define CASE_SPACE \ - case 0x20: /* Space */ \ - case 0x09 /* Horizontal tab */ - -#define CASE_DIGIT_0_TO_9 \ - case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9' - -#define CASE_DIGIT_1_TO_9 \ - case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9' - -#define CASE_SYMBOL \ - case ',': case ':': case '[': case ']': case '{': case '}' - -enum token_type { - TOKEN_TYPE_UNKNOWN, - - TOKEN_TYPE_NUMBER, - TOKEN_TYPE_STRING, - - TOKEN_TYPE_KEYWORD_TRUE, - TOKEN_TYPE_KEYWORD_FALSE, - TOKEN_TYPE_KEYWORD_NULL, - - TOKEN_TYPE_COMMA, - TOKEN_TYPE_COLON, - TOKEN_TYPE_SQUARE_BRACE_OPEN, - TOKEN_TYPE_SQUARE_BRACE_CLOSE, - TOKEN_TYPE_CURLY_BRACE_OPEN, - TOKEN_TYPE_CURLY_BRACE_CLOSE, - - TOKEN_TYPE_BOF, - TOKEN_TYPE_EOF -}; - -struct token { - enum token_type type; - u64 start; - u64 end; - struct token *next; -}; - -struct token_list { - struct token *token_first; - struct token *token_last; -}; - -enum lex_number_state { - LEX_NUMBER_STATE_WHOLE, - LEX_NUMBER_STATE_FRACTION, - LEX_NUMBER_STATE_EXPONENT -}; - -Global Readonly String g_keyword_strings[] = { - ['t'] = LitNoCast("true"), - ['f'] = LitNoCast("false"), - ['n'] = LitNoCast("null") -}; - -Global Readonly enum token_type g_keyword_types[] = { - ['t'] = TOKEN_TYPE_KEYWORD_TRUE, - ['f'] = TOKEN_TYPE_KEYWORD_FALSE, - ['n'] = TOKEN_TYPE_KEYWORD_NULL -}; - -internal struct token *push_token(Arena *arena, struct token_list *list) +JSON_Token *JSON_PushToken(Arena *arena, JSON_TokenList *list) { - struct token *t = PushStruct(arena, struct token); - if (!list->token_first) { + JSON_Token *t = PushStruct(arena, JSON_Token); + if (!list->token_first) + { list->token_first = t; - } else { + } + else + { list->token_last->next = t; } list->token_last = t; return t; } -internal struct token_list lex(Arena *arena, String src) +JSON_TokenList JSON_TokensFromString(Arena *arena, String src) { - struct token_list result = ZI; + JSON_TokenList result = ZI; - struct token *bof = push_token(arena, &result); - bof->type = TOKEN_TYPE_BOF; + JSON_Token *bof = JSON_PushToken(arena, &result); + bof->kind = JSON_TokenKind_Bof; u64 pos = 0; b32 lexing_done = 0; - while (!lexing_done) { + while (!lexing_done) + { /* Skip whitespace */ b32 whitespace_done = 0; - while (!whitespace_done && pos < src.len) { - switch (src.text[pos]) { - CASE_NEWLINE: - CASE_SPACE: { + while (!whitespace_done && pos < src.len) + { + switch (src.text[pos]) + { + JSON_Case_Newline: + JSON_Case_Space: + { ++pos; } break; - default: { + default: + { whitespace_done = 1; } break; } } /* Create token */ - struct token *t = push_token(arena, &result); + JSON_Token *t = JSON_PushToken(arena, &result); t->start = pos; - if (pos >= src.len) { - t->type = TOKEN_TYPE_EOF; + if (pos >= src.len) + { + t->kind = JSON_TokenKind_Eof; t->next = t; /* Self reference */ lexing_done = 1; - } else { - /* Lex known token types */ - switch (src.text[pos]) { + } + else + { + /* Lex known token kinds */ + switch (src.text[pos]) + { /* Symbols */ - case ',': { - t->type = TOKEN_TYPE_COMMA; + case ',': + { + t->kind = JSON_TokenKind_Comma; ++pos; } break; - case ':': { - t->type = TOKEN_TYPE_COLON; + case ':': + { + t->kind = JSON_TokenKind_Colon; ++pos; } break; - case '[': { - t->type = TOKEN_TYPE_SQUARE_BRACE_OPEN; + case '[': + { + t->kind = JSON_TokenKind_SquareBraceOpen; ++pos; } break; - case ']': { - t->type = TOKEN_TYPE_SQUARE_BRACE_CLOSE; + case ']': + { + t->kind = JSON_TokenKind_SquareBraceClose; ++pos; } break; - case '{': { - t->type = TOKEN_TYPE_CURLY_BRACE_OPEN; + case '{': + { + t->kind = JSON_TokenKind_CurlyBraceOpen; ++pos; } break; - case '}': { - t->type = TOKEN_TYPE_CURLY_BRACE_CLOSE; + case '}': + { + t->kind = JSON_TokenKind_CurlyBraceClose; ++pos; } break; /* Number */ - case '-': { + case '-': + { /* Verify '-' precedes digit */ b32 next_is_digit = 0; - if ((pos + 1) < src.len) { - switch (src.text[pos + 1]) { - CASE_DIGIT_0_TO_9: { + if ((pos + 1) < src.len) + { + switch (src.text[pos + 1]) + { + JSON_Case_Digit0Through9: + { next_is_digit = 1; } break; } } ++pos; - if (!next_is_digit) { + if (!next_is_digit) + { break; } } FALLTHROUGH; - CASE_DIGIT_0_TO_9: { - t->type = TOKEN_TYPE_NUMBER; - enum lex_number_state state = LEX_NUMBER_STATE_WHOLE; + JSON_Case_Digit0Through9: + { + t->kind = JSON_TokenKind_Number; + JSON_LexNumberState state = JSON_LexNumberState_Whole; b32 number_done = 0; - while (!number_done && pos < src.len) { - switch (src.text[pos]) { - CASE_DIGIT_0_TO_9: { + while (!number_done && pos < src.len) + { + switch (src.text[pos]) + { + JSON_Case_Digit0Through9: + { ++pos; } break; - case '.': { + case '.': + { u64 consume = 0; - if (state == LEX_NUMBER_STATE_WHOLE && (pos + 1) < src.len) { + if (state == JSON_LexNumberState_Whole && (pos + 1) < src.len) + { u8 c1 = src.text[pos + 1]; - switch (c1) { - CASE_DIGIT_0_TO_9: { + switch (c1) + { + JSON_Case_Digit0Through9: + { /* Consume '.' */ ++consume; } break; @@ -193,31 +155,42 @@ internal struct token_list lex(Arena *arena, String src) default: break; } } - if (consume) { - state = LEX_NUMBER_STATE_FRACTION; + if (consume) + { + state = JSON_LexNumberState_Fraction; pos += consume; - } else { + } + else + { number_done = 1; } } break; case 'e': - case 'E': { + case 'E': + { u64 consume = 0; - if ((state == LEX_NUMBER_STATE_WHOLE || state == LEX_NUMBER_STATE_FRACTION) && (pos + 1) < src.len) { + if ((state == JSON_LexNumberState_Whole || state == JSON_LexNumberState_Fraction) && (pos + 1) < src.len) + { u8 c1 = src.text[pos + 1]; - switch (c1) { - CASE_DIGIT_0_TO_9: { + switch (c1) + { + JSON_Case_Digit0Through9: + { /* Consume 'E'/'e' */ ++consume; } break; case '-': - case '+': { - if ((pos + 2) < src.len) { + case '+': + { + if ((pos + 2) < src.len) + { u8 c2 = src.text[pos + 2]; - switch (c2) { - CASE_DIGIT_0_TO_9: { + switch (c2) + { + JSON_Case_Digit0Through9: + { /* Consume 'E'/'e' & '+'/'-' */ consume += 2; } break; @@ -230,15 +203,19 @@ internal struct token_list lex(Arena *arena, String src) default: break; } } - if (consume) { - state = LEX_NUMBER_STATE_EXPONENT; + if (consume) + { + state = JSON_LexNumberState_Exponent; pos += consume; - } else { + } + else + { number_done = 1; } } break; - default: { + default: + { number_done = 1; } break; } @@ -246,36 +223,45 @@ internal struct token_list lex(Arena *arena, String src) } break; /* String */ - case '"': { + case '"': + { ++pos; b32 string_done = 0; b32 next_escaped = 0; - while (!string_done && pos < src.len) { + while (!string_done && pos < src.len) + { b32 escaped = next_escaped; next_escaped = 0; - switch (src.text[pos]) { - CASE_NEWLINE: { + switch (src.text[pos]) + { + JSON_Case_Newline: + { ++pos; string_done = 1; } break; - case '"': { + case '"': + { ++pos; - if (!escaped) { - t->type = TOKEN_TYPE_STRING; + if (!escaped) + { + t->kind = JSON_TokenKind_String; string_done = 1; } } break; - case '\\': { + case '\\': + { ++pos; - if (!escaped) { + if (!escaped) + { next_escaped = 1; } } break; - default: { + default: + { ++pos; } break; } @@ -285,25 +271,32 @@ internal struct token_list lex(Arena *arena, String src) /* Keywords */ case 't': case 'f': - case 'n': { - String keyword = g_keyword_strings[src.text[pos]]; + case 'n': + { + String keyword = JSON_keyword_strings[src.text[pos]]; b32 match = 1; - if ((pos + keyword.len - 1) < src.len) { - if ((pos + keyword.len) < src.len) { + if ((pos + keyword.len - 1) < src.len) + { + if ((pos + keyword.len) < src.len) + { /* Don't match if word continues past keyword */ - switch (src.text[pos + keyword.len]) { - CASE_SYMBOL: - CASE_SPACE: - CASE_NEWLINE: { + switch (src.text[pos + keyword.len]) + { + JSON_Case_Symbol: + JSON_Case_Space: + JSON_Case_Newline: + { } break; - default: { + default: + { match = 0; } break; } } - if (match) { + if (match) + { String cmp_str = { .len = keyword.len, .text = &src.text[pos] @@ -312,8 +305,9 @@ internal struct token_list lex(Arena *arena, String src) } } - if (match) { - t->type = g_keyword_types[src.text[pos]]; + if (match) + { + t->kind = JSON_keyword_types[src.text[pos]]; pos += keyword.len; } } break; @@ -323,17 +317,22 @@ internal struct token_list lex(Arena *arena, String src) } /* Lex unknown token */ - if (t->type == TOKEN_TYPE_UNKNOWN) { + if (t->kind == JSON_TokenKind_Unknown) + { b32 unknown_done = 0; - while (!unknown_done && pos < src.len) { - switch (src.text[pos]) { - CASE_SYMBOL: - CASE_SPACE: - CASE_NEWLINE: { + while (!unknown_done && pos < src.len) + { + switch (src.text[pos]) + { + JSON_Case_Symbol: + JSON_Case_Space: + JSON_Case_Newline: + { unknown_done = 1; } break; - default: { + default: + { ++pos; } break; } @@ -342,7 +341,9 @@ internal struct token_list lex(Arena *arena, String src) /* Exit early if unknown token encountered */ return result; - } else { + } + else + { t->end = pos; } } @@ -350,17 +351,10 @@ internal struct token_list lex(Arena *arena, String src) return result; } -/* ========================== * - * Interpret - * ========================== */ +//////////////////////////////// +//~ Interpret -internal void append_char(Arena *arena, String *str, u8 c) -{ - *PushStructNoZero(arena, u8) = c; - ++str->len; -} - -internal f64 interpret_number(String src) +f64 interpret_number(String src) { b32 whole_present = 0; u64 whole_left = 0; @@ -379,18 +373,25 @@ internal f64 interpret_number(String src) /* Lex number parts */ { u64 pos = 0; - if (src.len > 0 && src.text[0] == '-') { + if (src.len > 0 && src.text[0] == '-') + { whole_sign = -1; ++pos; } - enum lex_number_state state = LEX_NUMBER_STATE_WHOLE; - while (pos < src.len) { - switch (src.text[pos]) { - CASE_DIGIT_0_TO_9: { - switch (state) { - case LEX_NUMBER_STATE_WHOLE: { - if (!whole_present) { + JSON_LexNumberState state = JSON_LexNumberState_Whole; + while (pos < src.len) + { + switch (src.text[pos]) + { + JSON_Case_Digit0Through9: + { + switch (state) + { + case JSON_LexNumberState_Whole: + { + if (!whole_present) + { whole_present = 1; whole_left = pos; } @@ -398,8 +399,10 @@ internal f64 interpret_number(String src) ++pos; } break; - case LEX_NUMBER_STATE_FRACTION: { - if (!fraction_present) { + case JSON_LexNumberState_Fraction: + { + if (!fraction_present) + { fraction_present = 1; fraction_left = pos; } @@ -407,8 +410,10 @@ internal f64 interpret_number(String src) ++pos; } break; - case LEX_NUMBER_STATE_EXPONENT: { - if (!exponent_present) { + case JSON_LexNumberState_Exponent: + { + if (!exponent_present) + { exponent_present = 1; exponent_left = pos; } @@ -418,30 +423,37 @@ internal f64 interpret_number(String src) } } break; - case '.': { - state = LEX_NUMBER_STATE_FRACTION; + case '.': + { + state = JSON_LexNumberState_Fraction; ++pos; } break; case 'e': - case 'E': { - state = LEX_NUMBER_STATE_EXPONENT; + case 'E': + { + state = JSON_LexNumberState_Exponent; ++pos; } break; - case '-': { - switch (state) { - case LEX_NUMBER_STATE_WHOLE: { + case '-': + { + switch (state) + { + case JSON_LexNumberState_Whole: + { whole_sign = -1; ++pos; } break; - case LEX_NUMBER_STATE_EXPONENT: { + case JSON_LexNumberState_Exponent: + { exponent_sign = -1; ++pos; } break; - default: { + default: + { /* Unreachable */ Assert(0); ++pos; @@ -449,14 +461,18 @@ internal f64 interpret_number(String src) } } break; - case '+': { - switch (state) { - case LEX_NUMBER_STATE_EXPONENT: { + case '+': + { + switch (state) + { + case JSON_LexNumberState_Exponent: + { exponent_sign = 1; ++pos; } break; - default: { + default: + { /* Unreachable */ Assert(0); ++pos; @@ -464,7 +480,8 @@ internal f64 interpret_number(String src) } } break; - default: { + default: + { /* Unreachable */ Assert(0); ++pos; @@ -476,9 +493,11 @@ internal f64 interpret_number(String src) f64 result = 0; /* Process whole part */ - if (whole_present) { + if (whole_present) + { u64 pos = whole_left; - while (pos <= whole_right) { + while (pos <= whole_right) + { u8 digit = MinU8(src.text[pos] - 48, 9); u64 exp = whole_right - pos; result += digit * PowU64(10, exp); @@ -488,10 +507,12 @@ internal f64 interpret_number(String src) } /* Process fraction part */ - if (fraction_present) { + if (fraction_present) + { u64 frac_whole = 0; u64 pos = fraction_left; - while (pos <= fraction_right) { + while (pos <= fraction_right) + { u8 digit = MinU8(src.text[pos] - 48, 9); u64 exp = fraction_right - pos; frac_whole += digit * PowU64(10, exp); @@ -502,19 +523,24 @@ internal f64 interpret_number(String src) } /* Process exponent part */ - if (exponent_present) { + if (exponent_present) + { u64 exponent_whole = 0; u64 pos = exponent_left; - while (pos <= exponent_right) { + while (pos <= exponent_right) + { u8 digit = MinU8(src.text[pos] - 48, 9); u64 exp = exponent_right - pos; exponent_whole += digit * PowU64(10, exp); ++pos; } - if (exponent_sign >= 0) { + if (exponent_sign >= 0) + { result *= PowU64(10, exponent_whole); - } else { + } + else + { result /= PowU64(10, exponent_whole); } } @@ -522,15 +548,17 @@ internal f64 interpret_number(String src) return result; } -internal String interpret_string(Arena *arena, String src, String *error) +String interpret_string(Arena *arena, String src, String *error) { String result = { .len = 0, .text = PushDry(arena, u8) }; - if (src.len < 2) { - if (error) { + if (src.len < 2) + { + if (error) + { *error = Lit("Malformed string."); } return result; @@ -541,86 +569,113 @@ internal String interpret_string(Arena *arena, String src, String *error) b32 valid_close = 0; b32 string_done = 0; b32 next_escaped = 0; - while (!string_done && pos < src.len) { + while (!string_done && pos < src.len) + { b32 escaped = next_escaped; next_escaped = 0; - if (escaped) { - switch (src.text[pos]) { + if (escaped) + { + switch (src.text[pos]) + { case '"': case '\\': - case '/': { - append_char(arena, &result, src.text[pos]); + case '/': + { + *PushStructNoZero(arena, u8) = src.text[pos]; + ++result.len; ++pos; } break; /* Backspace */ - case 'b': { - append_char(arena, &result, '\b'); + case 'b': + { + *PushStructNoZero(arena, u8) = '\b'; + ++result.len; ++pos; } break; /* Formfeed */ - case 'f': { - append_char(arena, &result, '\f'); + case 'f': + { + *PushStructNoZero(arena, u8) = '\f'; + ++result.len; ++pos; } break; /* Linefeed */ - case 'n': { - append_char(arena, &result, '\n'); + case 'n': + { + *PushStructNoZero(arena, u8) = '\n'; + ++result.len; ++pos; } break; /* Carriage return */ - case 'r': { - append_char(arena, &result, '\r'); + case 'r': + { + *PushStructNoZero(arena, u8) = '\r'; + ++result.len; ++pos; } break; /* Horizontal tab */ - case 't': { - append_char(arena, &result, '\t'); + case 't': + { + *PushStructNoZero(arena, u8) = '\t'; + ++result.len; ++pos; } break; /* TODO: Unicode escape support */ #if 0 - case 'u': { + case 'u': + { /* TODO */ } break; #endif - default: { - if (error) { + default: + { + if (error) + { *error = Lit("Invalid escape character in string."); return result; } } break; } - } else { - switch (src.text[pos]) { - case '\\': { + } + else + { + switch (src.text[pos]) + { + case '\\': + { escaped = 1; ++pos; } break; - case '"': { + case '"': + { string_done = 1; valid_close = 1; ++pos; } break; - default: { - append_char(arena, &result, src.text[pos]); + default: + { + *PushStructNoZero(arena, u8) = src.text[pos]; + ++result.len; ++pos; } break; } } } - if (!valid_close) { - if (error) { + if (!valid_close) + { + if (error) + { *error = Lit("Expected end of string."); } } @@ -628,21 +683,10 @@ internal String interpret_string(Arena *arena, String src, String *error) return result; } -/* ========================== * - * Parse - * ========================== */ +//////////////////////////////// +//~ Parse -struct parser { - /* Input */ - String src; - struct token *at; - - /* Output */ - JSON_Blob *root; - JSON_ErrorList errors; -}; - -internal void push_error(Arena *arena, struct parser *p, struct token *t, String msg) +void JSON_PushError(Arena *arena, JSON_Parser *p, JSON_Token *t, String msg) { JSON_Error *error = PushStruct(arena, JSON_Error); error->msg = msg; @@ -650,24 +694,28 @@ internal void push_error(Arena *arena, struct parser *p, struct token *t, String error->end = t->end; JSON_ErrorList *list = &p->errors; - if (!list->first) { + if (!list->first) + { list->first = error; - } else { + } + else + { list->last->next = error; } list->last = error; ++list->count; } -internal void parse(Arena *arena, struct parser *p) +void JSON_Parse(Arena *arena, JSON_Parser *p) { TempArena scratch = BeginScratch(arena); JSON_Blob *root = PushStruct(arena, JSON_Blob); - struct token *at = p->at; + JSON_Token *at = p->at; String src = p->src; - if (at->type == TOKEN_TYPE_BOF) { + if (at->kind == JSON_TokenKind_Bof) + { at = at->next; } @@ -675,122 +723,156 @@ internal void parse(Arena *arena, struct parser *p) *PushStructNoZero(scratch.arena, JSON_Blob *) = root; u64 stack_count = 1; - while (stack_count > 0) { + while (stack_count > 0) + { JSON_Blob *json = 0; PopStruct(scratch.arena, JSON_Blob *, &json); --stack_count; JSON_Blob *parent_json = json->parent; b32 is_new_parent = 0; - if (json->type == JSON_TYPE_OBJECT || json->type == JSON_TYPE_ARRAY) { + if (json->type == JSON_Type_Object || json->type == JSON_Type_Array) + { /* No more children to parse for object/array, check for closing brace. */ - enum token_type tok_close_type = json->type == JSON_TYPE_OBJECT ? TOKEN_TYPE_CURLY_BRACE_CLOSE : TOKEN_TYPE_SQUARE_BRACE_CLOSE; - if (at->type == tok_close_type) { + JSON_TokenKind tok_close_kind = json->type == JSON_Type_Object ? JSON_TokenKind_CurlyBraceClose : JSON_TokenKind_SquareBraceClose; + if (at->kind == tok_close_kind) + { at = at->next; - } else { - push_error(arena, p, at, Lit("Expected comma.")); + } + else + { + JSON_PushError(arena, p, at, Lit("Expected comma.")); at = at->next; goto abort; } - } else { - if (parent_json) { - if (parent_json->type == JSON_TYPE_OBJECT) { + } + else + { + if (parent_json) + { + if (parent_json->type == JSON_Type_Object) + { /* Parse key */ - if (at->type == TOKEN_TYPE_STRING) { + if (at->kind == JSON_TokenKind_String) + { String t_text = (String) { .len = at->end - at->start, .text = &src.text[at->start] }; String error = ZI; String key = interpret_string(arena, t_text, &error); - if (error.len > 0) { - push_error(arena, p, at, error); + if (error.len > 0) + { + JSON_PushError(arena, p, at, error); goto abort; - } else { + } + else + { json->key = key; at = at->next; } - } else { - push_error(arena, p, at, Lit("Key expected.")); + } + else + { + JSON_PushError(arena, p, at, Lit("Key expected.")); goto abort; } /* Parse colon */ - if (at->type == TOKEN_TYPE_COLON) { + if (at->kind == JSON_TokenKind_Colon) + { at = at->next; - } else { - push_error(arena, p, at, Lit("Colon expected.")); + } + else + { + JSON_PushError(arena, p, at, Lit("Colon expected.")); goto abort; } } - if (parent_json->child_last) { + if (parent_json->child_last) + { parent_json->child_last->next = json; - } else { + } + else + { parent_json->child_first = json; } parent_json->child_last = json; } /* Parse value */ - switch (at->type) { - case TOKEN_TYPE_NUMBER: { + switch (at->kind) + { + case JSON_TokenKind_Number: + { String t_text = (String) { .len = at->end - at->start, .text = &src.text[at->start] }; f64 value = interpret_number(t_text); - json->type = JSON_TYPE_NUMBER; + json->type = JSON_Type_Number; json->value.number = value; at = at->next; } break; - case TOKEN_TYPE_STRING: { + case JSON_TokenKind_String: + { String t_text = (String) { .len = at->end - at->start, .text = &src.text[at->start] }; String error = ZI; String value = interpret_string(arena, t_text, &error); - if (error.len > 0) { - push_error(arena, p, at, error); + if (error.len > 0) + { + JSON_PushError(arena, p, at, error); goto abort; - } else { - json->type = JSON_TYPE_STRING; + } + else + { + json->type = JSON_Type_String; json->value.string = value; at = at->next; } } break; - case TOKEN_TYPE_KEYWORD_TRUE: { - json->type = JSON_TYPE_BOOL; + case JSON_TokenKind_KeywordTrue: + { + json->type = JSON_Type_Bool; json->value.boolean = 1; at = at->next; } break; - case TOKEN_TYPE_KEYWORD_FALSE: { - json->type = JSON_TYPE_BOOL; + case JSON_TokenKind_KeywordFalse: + { + json->type = JSON_Type_Bool; json->value.boolean = 0; at = at->next; } break; - case TOKEN_TYPE_KEYWORD_NULL: { - json->type = JSON_TYPE_NULL; + case JSON_TokenKind_KeywordNull: + { + json->type = JSON_Type_Null; at = at->next; } break; - case TOKEN_TYPE_CURLY_BRACE_OPEN: { - json->type = JSON_TYPE_OBJECT; + case JSON_TokenKind_CurlyBraceOpen: + { + json->type = JSON_Type_Object; at = at->next; is_new_parent = 1; } break; - case TOKEN_TYPE_SQUARE_BRACE_OPEN: { - json->type = JSON_TYPE_ARRAY; + case JSON_TokenKind_SquareBraceOpen: + { + json->type = JSON_Type_Array; at = at->next; is_new_parent = 1; } break; - default: { - push_error(arena, p, at, Lit("Value expected.")); + default: + { + JSON_PushError(arena, p, at, Lit("Value expected.")); at = at->next; goto abort; } break; } } - if (is_new_parent) { + if (is_new_parent) + { /* PushStruct self back to stack to re-check for closing brace later */ *PushStructNoZero(scratch.arena, JSON_Blob *) = json; ++stack_count; @@ -800,9 +882,12 @@ internal void parse(Arena *arena, struct parser *p) child->parent = json; *PushStructNoZero(scratch.arena, JSON_Blob *) = child; ++stack_count; - } else if (parent_json) { + } + else if (parent_json) + { /* Check for comma */ - if (at->type == TOKEN_TYPE_COMMA) { + if (at->kind == JSON_TokenKind_Comma) + { /* Create sibling & push to stack */ JSON_Blob *sibling = PushStruct(arena, JSON_Blob); sibling->parent = parent_json; @@ -813,7 +898,7 @@ internal void parse(Arena *arena, struct parser *p) } } - abort: +abort: p->at = at; p->root = root; @@ -821,32 +906,28 @@ internal void parse(Arena *arena, struct parser *p) EndScratch(scratch); } -/* ========================== * - * Interface - * ========================== */ - -JSON_Result json_from_string(Arena *arena, String src) +JSON_Result JSON_BlobFromString(Arena *arena, String src) { TempArena scratch = BeginScratch(arena); - struct token_list tl = lex(scratch.arena, src); + JSON_TokenList tl = JSON_TokensFromString(scratch.arena, src); /* Parse root */ - struct parser p = { - .src = src, - .at = tl.token_first - }; - parse(arena, &p); + JSON_Parser p = ZI; + p.src = src; + p.at = tl.token_first; + JSON_Parse(arena, &p); /* Verify end of file */ - if (p.errors.count == 0 && p.at->type != TOKEN_TYPE_EOF) { - push_error(arena, &p, p.at, Lit("Expected end of file.")); + if (p.errors.count == 0 && p.at->kind != JSON_TokenKind_Eof) + { + JSON_PushError(arena, &p, p.at, Lit("Expected end of file.")); } EndScratch(scratch); - return (JSON_Result) { - .root = p.root, - .errors = p.errors - }; + JSON_Result result = ZI; + result.root = p.root; + result.errors = p.errors; + return result; } diff --git a/src/json/json_core.h b/src/json/json_core.h index fd09d2f0..d8596384 100644 --- a/src/json/json_core.h +++ b/src/json/json_core.h @@ -1,14 +1,18 @@ +//////////////////////////////// +//~ Blob types -typedef i32 JSON_Type; enum { - JSON_TYPE_NULL, - JSON_TYPE_BOOL, - JSON_TYPE_NUMBER, - JSON_TYPE_STRING, - JSON_TYPE_ARRAY, - JSON_TYPE_OBJECT +typedef i32 JSON_Type; enum +{ + JSON_Type_Null, + JSON_Type_Bool, + JSON_Type_Number, + JSON_Type_String, + JSON_Type_Array, + JSON_Type_Object }; -Struct(JSON_Blob) { +Struct(JSON_Blob) +{ JSON_Type type; String key; @@ -17,29 +21,139 @@ Struct(JSON_Blob) { JSON_Blob *child_first; JSON_Blob *child_last; - union { + union + { String string; f64 number; b32 boolean; } value; }; -Struct(JSON_Error) { +Struct(JSON_Error) +{ String msg; u64 start; u64 end; JSON_Error *next; }; -Struct(JSON_ErrorList) { +Struct(JSON_ErrorList) +{ u64 count; JSON_Error *first; JSON_Error *last; }; -Struct(JSON_Result) { +Struct(JSON_Result) +{ JSON_Blob *root; JSON_ErrorList errors; }; -JSON_Result json_from_string(Arena *arena, String src); +//////////////////////////////// +//~ Lexer types + +#define JSON_Case_Newline \ + case 0x0A: /* Line feed or New line */ \ + case 0x0D /* Carriage return */ + +#define JSON_Case_Space \ + case 0x20: /* Space */ \ + case 0x09 /* Horizontal tab */ + +#define JSON_Case_Digit0Through9 \ + case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9' + +#define JSON_Case_Digit1Through9 \ + case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9' + +#define JSON_Case_Symbol \ + case ',': case ':': case '[': case ']': case '{': case '}' + +typedef i32 JSON_TokenKind; enum +{ + JSON_TokenKind_Unknown, + + JSON_TokenKind_Number, + JSON_TokenKind_String, + + JSON_TokenKind_KeywordTrue, + JSON_TokenKind_KeywordFalse, + JSON_TokenKind_KeywordNull, + + JSON_TokenKind_Comma, + JSON_TokenKind_Colon, + JSON_TokenKind_SquareBraceOpen, + JSON_TokenKind_SquareBraceClose, + JSON_TokenKind_CurlyBraceOpen, + JSON_TokenKind_CurlyBraceClose, + + JSON_TokenKind_Bof, + JSON_TokenKind_Eof +}; + +Struct(JSON_Token) +{ + JSON_TokenKind kind; + u64 start; + u64 end; + JSON_Token *next; +}; + +Struct(JSON_TokenList) +{ + JSON_Token *token_first; + JSON_Token *token_last; +}; + +typedef i32 JSON_LexNumberState; enum +{ + JSON_LexNumberState_Whole, + JSON_LexNumberState_Fraction, + JSON_LexNumberState_Exponent +}; + +Global Readonly String JSON_keyword_strings[] = { + ['t'] = LitNoCast("true"), + ['f'] = LitNoCast("false"), + ['n'] = LitNoCast("null") +}; + +Global Readonly JSON_TokenKind JSON_keyword_types[] = { + ['t'] = JSON_TokenKind_KeywordTrue, + ['f'] = JSON_TokenKind_KeywordFalse, + ['n'] = JSON_TokenKind_KeywordNull +}; + +//////////////////////////////// +//~ Parser types + +Struct(JSON_Parser) +{ + /* Input */ + String src; + JSON_Token *at; + + /* Output */ + JSON_Blob *root; + JSON_ErrorList errors; +}; + +//////////////////////////////// +//~ Lex + +JSON_Token *JSON_PushToken(Arena *arena, JSON_TokenList *list); +JSON_TokenList JSON_TokensFromString(Arena *arena, String src); + +//////////////////////////////// +//~ Interpret + +f64 interpret_number(String src); +String interpret_string(Arena *arena, String src, String *error); + +//////////////////////////////// +//~ Parse + +void JSON_PushError(Arena *arena, JSON_Parser *p, JSON_Token *t, String msg); +void JSON_Parse(Arena *arena, JSON_Parser *p); +JSON_Result JSON_BlobFromString(Arena *arena, String src); diff --git a/src/platform/platform_log.c b/src/platform/platform_log.c index 9de98d87..9eecb4f1 100644 --- a/src/platform/platform_log.c +++ b/src/platform/platform_log.c @@ -3,38 +3,6 @@ P_SharedLogCtx P_shared_log_ctx = ZI; -Readonly P_LogLevelSettings P_log_settings[P_LogLevel_Count] = { - [P_LogLevel_Critical] = { - LitNoCast("CRITICAL"), - ColorPurple - }, - - [P_LogLevel_Error] = { - LitNoCast("ERROR"), - ColorRed - }, - - [P_LogLevel_Warning] = { - LitNoCast("WARNING"), - ColorYellow - }, - - [P_LogLevel_Success] = { - LitNoCast("SUCCESS"), - ColorGreen - }, - - [P_LogLevel_Info] = { - LitNoCast("INFO"), - ColorWhite - }, - - [P_LogLevel_Debug] = { - LitNoCast("DEBUG"), - ColorBlue - } -}; - //////////////////////////////// //~ Startup diff --git a/src/platform/platform_log.h b/src/platform/platform_log.h index 4bffe0de..7fc2130c 100644 --- a/src/platform/platform_log.h +++ b/src/platform/platform_log.h @@ -81,7 +81,38 @@ Struct(P_LogLevelSettings) u32 color; }; -extern Readonly P_LogLevelSettings P_log_settings[P_LogLevel_Count]; +Global Readonly P_LogLevelSettings P_log_settings[P_LogLevel_Count] = { + [P_LogLevel_Critical] = { + LitNoCast("CRITICAL"), + ColorPurple + }, + + [P_LogLevel_Error] = { + LitNoCast("ERROR"), + ColorRed + }, + + [P_LogLevel_Warning] = { + LitNoCast("WARNING"), + ColorYellow + }, + + [P_LogLevel_Success] = { + LitNoCast("SUCCESS"), + ColorGreen + }, + + [P_LogLevel_Info] = { + LitNoCast("INFO"), + ColorWhite + }, + + [P_LogLevel_Debug] = { + LitNoCast("DEBUG"), + ColorBlue + } +}; + //////////////////////////////// //~ Startup diff --git a/src/resource/resource_core.c b/src/resource/resource_core.c index 05c94ce3..00b7e994 100644 --- a/src/resource/resource_core.c +++ b/src/resource/resource_core.c @@ -22,7 +22,7 @@ R_StartupReceipt resource_startup(void) G.arena = AllocArena(Gibi(64)); #if RESOURCES_EMBEDDED - String embedded_data = inc_res_tar(); + String embedded_data = INC_GetResTar(); if (embedded_data.len <= 0) { P_Panic(Lit("No embedded resources found")); } diff --git a/src/settings/settings_core.c b/src/settings/settings_core.c index 79e0f531..a1c8bfc5 100644 --- a/src/settings/settings_core.c +++ b/src/settings/settings_core.c @@ -46,7 +46,7 @@ P_WindowSettings *settings_deserialize(Arena *arena, String src, String *error_o JSON_Error json_error = ZI; P_WindowSettings *settings = PushStruct(arena, P_WindowSettings); - JSON_Result parse_result = json_from_string(scratch.arena, src); + JSON_Result parse_result = JSON_BlobFromString(scratch.arena, src); if (parse_result.errors.count > 0) { json_error = *parse_result.errors.first; @@ -60,7 +60,7 @@ P_WindowSettings *settings_deserialize(Arena *arena, String src, String *error_o } JSON_Blob *window = root->child_first; - if (!window || window->type != JSON_TYPE_OBJECT || !EqString(window->key, Lit("window"))) { + if (!window || window->type != JSON_Type_Object || !EqString(window->key, Lit("window"))) { error = Lit("\"window\" object not found"); goto abort; } @@ -75,7 +75,7 @@ P_WindowSettings *settings_deserialize(Arena *arena, String src, String *error_o String key = child->key; if (EqString(key, Lit("maximized"))) { - if (child->type != JSON_TYPE_BOOL) { + if (child->type != JSON_Type_Bool) { error = Lit("Expected boolean for \"maximized\""); goto abort; } @@ -84,7 +84,7 @@ P_WindowSettings *settings_deserialize(Arena *arena, String src, String *error_o } found_maximized = 1; } else if (EqString(key, Lit("fullscreen"))) { - if (child->type != JSON_TYPE_BOOL) { + if (child->type != JSON_Type_Bool) { error = Lit("Expected boolean for \"fulscreen\""); goto abort; } @@ -93,28 +93,28 @@ P_WindowSettings *settings_deserialize(Arena *arena, String src, String *error_o } found_fullscreen = 1; } else if (EqString(key, Lit("x"))) { - if (child->type != JSON_TYPE_NUMBER) { + if (child->type != JSON_Type_Number) { error = Lit("Expected number for \"x\""); goto abort; } settings->floating_x = RoundF32ToI32(child->value.number); found_x = 1; } else if (EqString(key, Lit("y"))) { - if (child->type != JSON_TYPE_NUMBER) { + if (child->type != JSON_Type_Number) { error = Lit("Expected number for \"y\""); goto abort; } settings->floating_y = RoundF32ToI32(child->value.number); found_y = 1; } else if (EqString(key, Lit("width"))) { - if (child->type != JSON_TYPE_NUMBER) { + if (child->type != JSON_Type_Number) { error = Lit("Expected number for \"width\""); goto abort; } settings->floating_width = RoundF32ToI32(child->value.number); found_width = 1; } else if (EqString(key, Lit("height"))) { - if (child->type != JSON_TYPE_NUMBER) { + if (child->type != JSON_Type_Number) { error = Lit("Expected number for \"height\""); goto abort; }