From 5f3528bea55a4b2e39a51af1bd8a68fc98b871e3 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Sat, 24 Apr 2021 16:20:31 -0600 Subject: [PATCH] re-order md_impl; keep everything in same order as header file --- source/md.h | 11 +- source/md_impl.c | 822 +++++++++++++++++++++++------------------------ 2 files changed, 414 insertions(+), 419 deletions(-) diff --git a/source/md.h b/source/md.h index 869607e..ae1d6b4 100644 --- a/source/md.h +++ b/source/md.h @@ -629,21 +629,26 @@ MD_FUNCTION MD_String16 MD_S16FromS8(MD_String8 str); MD_FUNCTION MD_String8 MD_S8FromS32(MD_String32 str); MD_FUNCTION MD_String32 MD_S32FromS8(MD_String8 str); -//~ String-To-Pointer Table +//~ Map Table Data Structure + +MD_FUNCTION MD_u64 MD_HashPointer(void *p); + +//- String-To-Pointer Table MD_FUNCTION MD_MapSlot * MD_StringMap_Lookup(MD_Map *table, MD_String8 string); MD_FUNCTION MD_b32 MD_StringMap_Insert(MD_Map *table, MD_MapCollisionRule collision_rule, MD_String8 string, void *value); MD_FUNCTION MD_MapSlot * MD_StringMap_Next(MD_MapSlot *slot, MD_String8 key); -//~ Pointer-To-Pointer Table +//- Pointer-To-Pointer Table MD_FUNCTION MD_MapSlot *MD_PtrMap_Lookup(MD_Map *map, void *key); MD_FUNCTION MD_b32 MD_PtrMap_Insert(MD_Map *map, MD_MapCollisionRule collision_rule, void *key, void *value); //~ Parsing + MD_FUNCTION MD_b32 MD_TokenKindIsWhitespace(MD_TokenKind kind); MD_FUNCTION MD_b32 MD_TokenKindIsComment(MD_TokenKind kind); MD_FUNCTION MD_b32 MD_TokenKindIsRegular(MD_TokenKind kind); -MD_FUNCTION MD_ParseCtx MD_Parse_InitializeCtx(MD_String8 filename, MD_String8 contents); +MD_FUNCTION MD_ParseCtx MD_Parse_InitializeCtx(MD_String8 filename, MD_String8 contents); MD_FUNCTION void MD_Parse_Bump(MD_ParseCtx *ctx, MD_Token token); MD_FUNCTION void MD_Parse_BumpNext(MD_ParseCtx *ctx); MD_FUNCTION MD_Token MD_Parse_LexNext(MD_ParseCtx *ctx); diff --git a/source/md_impl.c b/source/md_impl.c index 96f0a70..cc00a94 100644 --- a/source/md_impl.c +++ b/source/md_impl.c @@ -68,6 +68,8 @@ _MD_AllocZero(MD_u64 size) #define _MD_PushArray(type, count) (type *)_MD_AllocZero(sizeof(type)*(count)) +//~ Basic Utilities + MD_FUNCTION_IMPL MD_b32 MD_CharIsAlpha(MD_u8 c) { @@ -135,6 +137,8 @@ MD_CorrectSlash(MD_u8 c) return (c == '\\' ? '/' : c); } +//~ Strings + MD_FUNCTION_IMPL MD_String8 MD_S8(MD_u8 *str, MD_u64 size) { @@ -635,6 +639,8 @@ MD_StyledStringFromString(MD_String8 string, MD_WordStyle word_style, MD_String8 return result; } +//~ Enum/Flag Strings + MD_FUNCTION_IMPL MD_String8 MD_StringFromNodeKind(MD_NodeKind kind) { @@ -689,10 +695,9 @@ MD_StringListFromNodeFlags(MD_NodeFlags flags) return list; } -//////////////////////////////// -// NOTE(allen): Unicode +//~ Unicode Conversions -MD_GLOBAL MD_u8 dd_utf8_class[32] = { +MD_GLOBAL MD_u8 md_utf8_class[32] = { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,2,2,2,2,3,3,4,5, }; @@ -712,7 +717,7 @@ MD_CodepointFromUtf8(MD_u8 *str, MD_u64 max) MD_UnicodeConsume result = {~((MD_u32)0), 1}; MD_u8 byte = str[0]; - MD_u8 byte_class = dd_utf8_class[byte >> 3]; + MD_u8 byte_class = md_utf8_class[byte >> 3]; switch (byte_class) { case 1: @@ -725,7 +730,7 @@ MD_CodepointFromUtf8(MD_u8 *str, MD_u64 max) if (2 <= max) { MD_u8 cont_byte = str[1]; - if (dd_utf8_class[cont_byte >> 3] == 0) + if (md_utf8_class[cont_byte >> 3] == 0) { result.codepoint = (byte & MD_bitmask5) << 6; result.codepoint |= (cont_byte & MD_bitmask6); @@ -739,8 +744,8 @@ MD_CodepointFromUtf8(MD_u8 *str, MD_u64 max) if (3 <= max) { MD_u8 cont_byte[2] = {str[1], str[2]}; - if (dd_utf8_class[cont_byte[0] >> 3] == 0 && - dd_utf8_class[cont_byte[1] >> 3] == 0) + if (md_utf8_class[cont_byte[0] >> 3] == 0 && + md_utf8_class[cont_byte[1] >> 3] == 0) { result.codepoint = (byte & MD_bitmask4) << 12; result.codepoint |= ((cont_byte[0] & MD_bitmask6) << 6); @@ -755,9 +760,9 @@ MD_CodepointFromUtf8(MD_u8 *str, MD_u64 max) if (4 <= max) { MD_u8 cont_byte[3] = {str[1], str[2], str[3]}; - if (dd_utf8_class[cont_byte[0] >> 3] == 0 && - dd_utf8_class[cont_byte[1] >> 3] == 0 && - dd_utf8_class[cont_byte[2] >> 3] == 0) + if (md_utf8_class[cont_byte[0] >> 3] == 0 && + md_utf8_class[cont_byte[1] >> 3] == 0 && + md_utf8_class[cont_byte[2] >> 3] == 0) { result.codepoint = (byte & MD_bitmask3) << 18; result.codepoint |= ((cont_byte[0] & MD_bitmask6) << 12); @@ -924,8 +929,8 @@ MD_S32FromS8(MD_String8 in) return(result); } -///////////////////////////////////////////// -//~ String-To-Ptr and Ptr-To-Ptr tables +//~ Map Table Data Structure + MD_PRIVATE_FUNCTION_IMPL void _MD_Map_Initialize(MD_Map *map) { @@ -936,13 +941,24 @@ _MD_Map_Initialize(MD_Map *map) } } -///////////////////////////////////////////// -//~ NOTE(mal): MD_StringMap +// NOTE(mal): Generic 64-bit hash function (https://nullprogram.com/blog/2018/07/31/) +// Reversible, so no collisions. Assumes all bits of the pointer matter. +MD_FUNCTION_IMPL MD_u64 +MD_HashPointer(void *p) +{ + MD_u64 h = (MD_u64)p; + h = (h ^ (h >> 30)) * UINT64_C(0xbf58476d1ce4e5b9); + h = (h ^ (h >> 27)) * UINT64_C(0x94d049bb133111eb); + h = h ^ (h >> 31); + return h; +} + +//- String-To-Pointer Table + MD_FUNCTION_IMPL MD_MapSlot * -MD_StringMap_Lookup(MD_Map *map, MD_String8 string) // NOTE(mal): Or MD_PtrFromString +MD_StringMap_Lookup(MD_Map *map, MD_String8 string) { _MD_Map_Initialize(map); - MD_MapSlot *slot = 0; MD_u64 hash = MD_HashString(string); MD_u64 index = hash % map->table_size; @@ -954,7 +970,6 @@ MD_StringMap_Lookup(MD_Map *map, MD_String8 string) // NOTE(mal): Or MD_Pt break; } } - return slot; } @@ -1030,20 +1045,7 @@ MD_StringMap_Next(MD_MapSlot *slot, MD_String8 key) return next; } -///////////////////////////////////////////// -//~ NOTE(mal): MD_PtrMap - -// NOTE(mal): Generic 64-bit hash function (https://nullprogram.com/blog/2018/07/31/) -// Reversible, so no collisions. Assumes all bits of the pointer matter. -MD_FUNCTION_IMPL MD_u64 -MD_HashPointer(void *p) -{ - MD_u64 h = (MD_u64)p; - h = (h ^ (h >> 30)) * UINT64_C(0xbf58476d1ce4e5b9); - h = (h ^ (h >> 27)) * UINT64_C(0x94d049bb133111eb); - h = h ^ (h >> 31); - return h; -} +//- Pointer-To-Pointer Table MD_FUNCTION_IMPL MD_MapSlot * MD_PtrMap_Lookup(MD_Map *map, void *key) @@ -1117,6 +1119,154 @@ MD_PtrMap_Insert(MD_Map *map, MD_MapCollisionRule collision_rule, void *key, voi return !!slot; } +//~ Parsing + +MD_PRIVATE_FUNCTION_IMPL void +_MD_Error(MD_ParseCtx *ctx, MD_Node *node, MD_MessageKind kind, char *fmt, ...) +{ + // NOTE(mal): Sort errors. Traverse the whole list assuming it will be short. + // The alternative is to drop a prev pointer into MD_Error and search backwards + MD_Error *prev_error = 0; + for(MD_Error *e = ctx->first_error; e; e = e->next) + { + if(e->node->at < node->at) + { + prev_error = e; + } + else + { + break; + } + } + + // NOTE(mal): Ignore errors after first catastrophic error + if(ctx->error_level < MD_MessageKind_CatastrophicError || !prev_error || prev_error->next) + { + MD_Error *error = _MD_PushArray(MD_Error, 1); + error->node = node; + error->kind = kind; + va_list args; + va_start(args, fmt); + error->string = MD_PushStringFV(fmt, args); + va_end(args); + + if(prev_error) + { + error->next = prev_error->next; + prev_error->next = error; + } + else + { + error->next = ctx->first_error; + ctx->first_error = error; + } + + if(!ctx->last_error || ctx->last_error == prev_error) + { + ctx->last_error = error; + } + + if(kind > ctx->error_level) + { + ctx->error_level = kind; + } + } +} +#define _MD_TokenError(ctx, token, kind, fmt, ...) \ +_MD_Error(ctx, _MD_MakeNodeFromToken_Ctx(ctx, MD_NodeKind_ErrorMarker, token), kind, fmt, __VA_ARGS__) + +MD_PRIVATE_FUNCTION_IMPL MD_Node * +_MD_MakeNodeFromToken_Ctx(MD_ParseCtx *ctx, MD_NodeKind kind, MD_Token token) +{ + return MD_MakeNode(kind, token.string, token.outer_string, ctx->filename, + ctx->file_contents.str, + token.outer_string.str); +} + +MD_PRIVATE_FUNCTION_IMPL MD_Node * +_MD_MakeNodeFromString_Ctx(MD_ParseCtx *ctx, MD_NodeKind kind, MD_String8 string, MD_u8 *at) +{ + return MD_MakeNode(kind, string, string, ctx->filename, ctx->file_contents.str, at); +} + +MD_PRIVATE_FUNCTION_IMPL void _MD_ParseTagList(MD_ParseCtx *ctx, MD_Node **first_out, MD_Node **last_out); + +MD_PRIVATE_FUNCTION_IMPL MD_NodeFlags +_MD_NodeFlagsFromTokenKind(MD_TokenKind kind) +{ + MD_NodeFlags result = 0; + switch (kind){ + case MD_TokenKind_Identifier: result = MD_NodeFlag_Identifier; break; + case MD_TokenKind_NumericLiteral: result = MD_NodeFlag_Numeric; break; + case MD_TokenKind_StringLiteral: result = MD_NodeFlag_StringLiteral; break; + case MD_TokenKind_CharLiteral: result = MD_NodeFlag_CharLiteral; break; + } + return(result); +} + +MD_PRIVATE_FUNCTION_IMPL MD_b32 +_MD_StringLiteralIsBalanced(MD_Token token) +{ + MD_u64 front_len = token.string.str - token.outer_string.str; + MD_u64 back_len = (token.outer_string.str + token.outer_string.size) - (token.string.str + token.string.size); + MD_b32 result = (front_len == back_len); + return result; +} + +MD_PRIVATE_FUNCTION_IMPL MD_b32 +_MD_CommentIsSyntacticallyCorrect(MD_Token comment_token) +{ + MD_String8 inner = comment_token.string; + MD_String8 outer = comment_token.outer_string; + MD_b32 incorrect = (MD_StringMatch(MD_StringPrefix(outer, 2), MD_S8Lit("/*"), 0) && // C-style comment + (inner.str != outer.str + 2 || inner.str + inner.size != outer.str + outer.size - 2)); // Internally unbalanced + MD_b32 result = !incorrect; + return result; +} +MD_PRIVATE_FUNCTION_IMPL void +_MD_ParseTagList(MD_ParseCtx *ctx, MD_Node **first_out, MD_Node **last_out) +{ + MD_Node *first = MD_NilNode(); + MD_Node *last = MD_NilNode(); + + for(;;) + { + MD_Token next_token = MD_Parse_PeekSkipSome(ctx, MD_TokenGroup_Comment | MD_TokenGroup_Whitespace); + if(MD_StringMatch(next_token.string, MD_S8Lit("@"), 0) && + next_token.kind == MD_TokenKind_Symbol) + { + MD_Parse_Bump(ctx, next_token); + + MD_Token name = MD_ZERO_STRUCT; + if(MD_Parse_RequireKind(ctx, MD_TokenKind_Identifier, &name)) + { + MD_Node *tag = _MD_MakeNodeFromToken_Ctx(ctx, MD_NodeKind_Tag, name); + MD_Token token = MD_Parse_PeekSkipSome(ctx, 0); + if(MD_StringMatch(token.string, MD_S8Lit("("), 0)) + { + MD_Parse_Set(ctx, tag, MD_ParseSetFlag_Paren); + } + MD_PushSibling(&first, &last, tag); + } + else + { + MD_Token token = MD_Parse_PeekSkipSome(ctx, 0); + _MD_TokenError(ctx, token, MD_MessageKind_Error, "\"%.*s\" is not a proper tag identifier", + MD_StringExpand(token.outer_string)); + // NOTE(mal): There are reasons to consume the non-tag token, but also to leave it. + break; + } + } + else + { + break; + } + } + + *first_out = first; + *last_out = last; +} + MD_FUNCTION_IMPL MD_b32 MD_TokenKindIsWhitespace(MD_TokenKind kind) { @@ -1488,125 +1638,136 @@ MD_Parse_RequireKind(MD_ParseCtx *ctx, MD_TokenKind kind, MD_Token *out_token) return result; } -MD_PRIVATE_FUNCTION_IMPL void -_MD_Error(MD_ParseCtx *ctx, MD_Node *node, MD_MessageKind kind, char *fmt, ...) +MD_FUNCTION_IMPL void +MD_Parse_Set(MD_ParseCtx *ctx, MD_Node *parent, MD_ParseSetFlags flags) { - // NOTE(mal): Sort errors. Traverse the whole list assuming it will be short. - // The alternative is to drop a prev pointer into MD_Error and search backwards - MD_Error *prev_error = 0; - for(MD_Error *e = ctx->first_error; e; e = e->next) + MD_b32 brace = 0; + MD_b32 paren = 0; + MD_b32 bracket = 0; + MD_b32 terminate_with_separator = (!!(flags & MD_ParseSetFlag_Implicit)); + + MD_Token initial_token = MD_Parse_PeekSkipSome(ctx, MD_TokenGroup_Comment|MD_TokenGroup_Whitespace); + + if((flags & MD_ParseSetFlag_Brace) && + MD_Parse_Require(ctx, MD_S8Lit("{"), MD_TokenKind_Symbol)) { - if(e->node->at < node->at) + parent->flags |= MD_NodeFlag_BraceLeft; + brace = 1; + terminate_with_separator = 0; + } + else if((flags & MD_ParseSetFlag_Paren) && + MD_Parse_Require(ctx, MD_S8Lit("("), MD_TokenKind_Symbol)) + { + parent->flags |= MD_NodeFlag_ParenLeft; + paren = 1; + terminate_with_separator = 0; + } + else if((flags & MD_ParseSetFlag_Bracket) && + MD_Parse_Require(ctx, MD_S8Lit("["), MD_TokenKind_Symbol)) + { + parent->flags |= MD_NodeFlag_BracketLeft; + bracket = 1; + terminate_with_separator = 0; + } + + // NOTE(rjf): Parse children. + if(brace || paren || bracket || terminate_with_separator) + { + MD_u8 *at_before_children = ctx->at; + MD_NodeFlags next_child_flags = 0; + for(MD_u64 child_idx = 0;; child_idx += 1) { - prev_error = e; - } - else - { - break; + if(brace) + { + if(MD_Parse_Require(ctx, MD_S8Lit("}"), MD_TokenKind_Symbol)) + { + parent->flags |= MD_NodeFlag_BraceRight; + goto end_parse; + } + } + else if(paren || bracket) + { + if((flags & MD_ParseSetFlag_Paren) && + MD_Parse_Require(ctx, MD_S8Lit(")"), MD_TokenKind_Symbol)) + { + parent->flags |= MD_NodeFlag_ParenRight; + goto end_parse; + } + else if((flags & MD_ParseSetFlag_Bracket) && + MD_Parse_Require(ctx, MD_S8Lit("]"), MD_TokenKind_Symbol)) + { + parent->flags |= MD_NodeFlag_BracketRight; + goto end_parse; + } + } + else + { + MD_Token peek = MD_Parse_PeekSkipSome(ctx, MD_TokenGroup_Whitespace | MD_TokenGroup_Comment); + if(peek.kind == MD_TokenKind_Symbol && + (MD_Parse_TokenMatch(peek, MD_S8Lit("}"), 0) || + MD_Parse_TokenMatch(peek, MD_S8Lit(")"), 0) || + MD_Parse_TokenMatch(peek, MD_S8Lit("]"), 0))) + { + goto end_parse; + } + } + + MD_ParseResult parse = MD_ParseOneNodeFromCtx(ctx); + MD_Node *child = parse.node; + child->flags |= next_child_flags; + next_child_flags = 0; + if(MD_NodeIsNil(child)) + { + if(brace || paren || bracket) + { + char delimiter_char = 0; + if(brace) delimiter_char = '{'; + else if(paren) delimiter_char = '('; + else if(bracket) delimiter_char = '['; + _MD_TokenError(ctx, initial_token, MD_MessageKind_CatastrophicError, "Unbalanced \"%c\"", delimiter_char); + } + goto end_parse; + } + else + { + MD_PushSibling(&parent->first_child, &parent->last_child, child); + child->parent = parent; + } + + // NOTE(rjf): Separators. + { + MD_b32 result = 0; + if(terminate_with_separator) + { + MD_Token next_token = MD_Parse_PeekSkipSome(ctx, 0); + if(next_token.kind == MD_TokenKind_Newline || + (next_token.kind == MD_TokenKind_Symbol && + (MD_StringMatch(next_token.string, MD_S8Lit(","), 0) || + MD_StringMatch(next_token.string, MD_S8Lit(";"), 0)))) + { + result = 1; + } + } + else if(MD_Parse_Require(ctx, MD_S8Lit(","), MD_TokenKind_Symbol)) + { + child->flags |= MD_NodeFlag_BeforeComma; + next_child_flags |= MD_NodeFlag_AfterComma; + } + else if(MD_Parse_Require(ctx, MD_S8Lit(";"), MD_TokenKind_Symbol)) + { + child->flags |= MD_NodeFlag_BeforeSemicolon; + next_child_flags |= MD_NodeFlag_AfterSemicolon; + } + + if(result) + { + goto end_parse; + } + } } } - // NOTE(mal): Ignore errors after first catastrophic error - if(ctx->error_level < MD_MessageKind_CatastrophicError || !prev_error || prev_error->next) - { - MD_Error *error = _MD_PushArray(MD_Error, 1); - error->node = node; - error->kind = kind; - va_list args; - va_start(args, fmt); - error->string = MD_PushStringFV(fmt, args); - va_end(args); - - if(prev_error) - { - error->next = prev_error->next; - prev_error->next = error; - } - else - { - error->next = ctx->first_error; - ctx->first_error = error; - } - - if(!ctx->last_error || ctx->last_error == prev_error) - { - ctx->last_error = error; - } - - if(kind > ctx->error_level) - { - ctx->error_level = kind; - } - } -} -#define _MD_TokenError(ctx, token, kind, fmt, ...) \ -_MD_Error(ctx, _MD_MakeNodeFromToken_Ctx(ctx, MD_NodeKind_ErrorMarker, token), kind, fmt, __VA_ARGS__) - -MD_FUNCTION_IMPL MD_Node * -MD_MakeNode(MD_NodeKind kind, MD_String8 string, - MD_String8 whole_string, MD_String8 filename, - MD_u8 *file_contents, MD_u8 *at) -{ - MD_Node *node = _MD_PushArray(MD_Node, 1); - node->kind = kind; - node->string = string; - node->whole_string = whole_string; - node->next = node->prev = node->parent = - node->first_child = node->last_child = - node->first_tag = node->last_tag = node->ref_target = MD_NilNode(); - node->filename = filename; - node->file_contents = file_contents; - node->at = at; - return node; -} - -MD_PRIVATE_FUNCTION_IMPL MD_Node * -_MD_MakeNodeFromToken_Ctx(MD_ParseCtx *ctx, MD_NodeKind kind, MD_Token token) -{ - return MD_MakeNode(kind, token.string, token.outer_string, ctx->filename, - ctx->file_contents.str, - token.outer_string.str); -} - -MD_PRIVATE_FUNCTION_IMPL MD_Node * -_MD_MakeNodeFromString_Ctx(MD_ParseCtx *ctx, MD_NodeKind kind, MD_String8 string, MD_u8 *at) -{ - return MD_MakeNode(kind, string, string, ctx->filename, ctx->file_contents.str, at); -} - -MD_PRIVATE_FUNCTION_IMPL void _MD_ParseTagList(MD_ParseCtx *ctx, MD_Node **first_out, MD_Node **last_out); - -MD_PRIVATE_FUNCTION_IMPL MD_NodeFlags -_MD_NodeFlagsFromTokenKind(MD_TokenKind kind) -{ - MD_NodeFlags result = 0; - switch (kind){ - case MD_TokenKind_Identifier: result = MD_NodeFlag_Identifier; break; - case MD_TokenKind_NumericLiteral: result = MD_NodeFlag_Numeric; break; - case MD_TokenKind_StringLiteral: result = MD_NodeFlag_StringLiteral; break; - case MD_TokenKind_CharLiteral: result = MD_NodeFlag_CharLiteral; break; - } - return(result); -} - -MD_PRIVATE_FUNCTION_IMPL MD_b32 -_MD_StringLiteralIsBalanced(MD_Token token) -{ - MD_u64 front_len = token.string.str - token.outer_string.str; - MD_u64 back_len = (token.outer_string.str + token.outer_string.size) - (token.string.str + token.string.size); - MD_b32 result = (front_len == back_len); - return result; -} - -MD_PRIVATE_FUNCTION_IMPL MD_b32 -_MD_CommentIsSyntacticallyCorrect(MD_Token comment_token) -{ - MD_String8 inner = comment_token.string; - MD_String8 outer = comment_token.outer_string; - MD_b32 incorrect = (MD_StringMatch(MD_StringPrefix(outer, 2), MD_S8Lit("/*"), 0) && // C-style comment - (inner.str != outer.str + 2 || inner.str + inner.size != outer.str + outer.size - 2)); // Internally unbalanced - MD_b32 result = !incorrect; - return result; + end_parse:; } MD_FUNCTION_IMPL MD_ParseResult @@ -1806,182 +1967,6 @@ MD_ParseOneNodeFromCtx(MD_ParseCtx *ctx) return result; } -MD_FUNCTION_IMPL void -MD_Parse_Set(MD_ParseCtx *ctx, MD_Node *parent, MD_ParseSetFlags flags) -{ - MD_b32 brace = 0; - MD_b32 paren = 0; - MD_b32 bracket = 0; - MD_b32 terminate_with_separator = (!!(flags & MD_ParseSetFlag_Implicit)); - - MD_Token initial_token = MD_Parse_PeekSkipSome(ctx, MD_TokenGroup_Comment|MD_TokenGroup_Whitespace); - - if((flags & MD_ParseSetFlag_Brace) && - MD_Parse_Require(ctx, MD_S8Lit("{"), MD_TokenKind_Symbol)) - { - parent->flags |= MD_NodeFlag_BraceLeft; - brace = 1; - terminate_with_separator = 0; - } - else if((flags & MD_ParseSetFlag_Paren) && - MD_Parse_Require(ctx, MD_S8Lit("("), MD_TokenKind_Symbol)) - { - parent->flags |= MD_NodeFlag_ParenLeft; - paren = 1; - terminate_with_separator = 0; - } - else if((flags & MD_ParseSetFlag_Bracket) && - MD_Parse_Require(ctx, MD_S8Lit("["), MD_TokenKind_Symbol)) - { - parent->flags |= MD_NodeFlag_BracketLeft; - bracket = 1; - terminate_with_separator = 0; - } - - // NOTE(rjf): Parse children. - if(brace || paren || bracket || terminate_with_separator) - { - MD_u8 *at_before_children = ctx->at; - MD_NodeFlags next_child_flags = 0; - for(MD_u64 child_idx = 0;; child_idx += 1) - { - if(brace) - { - if(MD_Parse_Require(ctx, MD_S8Lit("}"), MD_TokenKind_Symbol)) - { - parent->flags |= MD_NodeFlag_BraceRight; - goto end_parse; - } - } - else if(paren || bracket) - { - if((flags & MD_ParseSetFlag_Paren) && - MD_Parse_Require(ctx, MD_S8Lit(")"), MD_TokenKind_Symbol)) - { - parent->flags |= MD_NodeFlag_ParenRight; - goto end_parse; - } - else if((flags & MD_ParseSetFlag_Bracket) && - MD_Parse_Require(ctx, MD_S8Lit("]"), MD_TokenKind_Symbol)) - { - parent->flags |= MD_NodeFlag_BracketRight; - goto end_parse; - } - } - else - { - MD_Token peek = MD_Parse_PeekSkipSome(ctx, MD_TokenGroup_Whitespace | MD_TokenGroup_Comment); - if(peek.kind == MD_TokenKind_Symbol && - (MD_Parse_TokenMatch(peek, MD_S8Lit("}"), 0) || - MD_Parse_TokenMatch(peek, MD_S8Lit(")"), 0) || - MD_Parse_TokenMatch(peek, MD_S8Lit("]"), 0))) - { - goto end_parse; - } - } - - MD_ParseResult parse = MD_ParseOneNodeFromCtx(ctx); - MD_Node *child = parse.node; - child->flags |= next_child_flags; - next_child_flags = 0; - if(MD_NodeIsNil(child)) - { - if(brace || paren || bracket) - { - char delimiter_char = 0; - if(brace) delimiter_char = '{'; - else if(paren) delimiter_char = '('; - else if(bracket) delimiter_char = '['; - _MD_TokenError(ctx, initial_token, MD_MessageKind_CatastrophicError, "Unbalanced \"%c\"", delimiter_char); - } - goto end_parse; - } - else - { - MD_PushSibling(&parent->first_child, &parent->last_child, child); - child->parent = parent; - } - - // NOTE(rjf): Separators. - { - MD_b32 result = 0; - if(terminate_with_separator) - { - MD_Token next_token = MD_Parse_PeekSkipSome(ctx, 0); - if(next_token.kind == MD_TokenKind_Newline || - (next_token.kind == MD_TokenKind_Symbol && - (MD_StringMatch(next_token.string, MD_S8Lit(","), 0) || - MD_StringMatch(next_token.string, MD_S8Lit(";"), 0)))) - { - result = 1; - } - } - else if(MD_Parse_Require(ctx, MD_S8Lit(","), MD_TokenKind_Symbol)) - { - child->flags |= MD_NodeFlag_BeforeComma; - next_child_flags |= MD_NodeFlag_AfterComma; - } - else if(MD_Parse_Require(ctx, MD_S8Lit(";"), MD_TokenKind_Symbol)) - { - child->flags |= MD_NodeFlag_BeforeSemicolon; - next_child_flags |= MD_NodeFlag_AfterSemicolon; - } - - if(result) - { - goto end_parse; - } - } - } - } - - end_parse:; -} - -MD_PRIVATE_FUNCTION_IMPL void -_MD_ParseTagList(MD_ParseCtx *ctx, MD_Node **first_out, MD_Node **last_out) -{ - MD_Node *first = MD_NilNode(); - MD_Node *last = MD_NilNode(); - - for(;;) - { - MD_Token next_token = MD_Parse_PeekSkipSome(ctx, MD_TokenGroup_Comment | MD_TokenGroup_Whitespace); - if(MD_StringMatch(next_token.string, MD_S8Lit("@"), 0) && - next_token.kind == MD_TokenKind_Symbol) - { - MD_Parse_Bump(ctx, next_token); - - MD_Token name = MD_ZERO_STRUCT; - if(MD_Parse_RequireKind(ctx, MD_TokenKind_Identifier, &name)) - { - MD_Node *tag = _MD_MakeNodeFromToken_Ctx(ctx, MD_NodeKind_Tag, name); - MD_Token token = MD_Parse_PeekSkipSome(ctx, 0); - if(MD_StringMatch(token.string, MD_S8Lit("("), 0)) - { - MD_Parse_Set(ctx, tag, MD_ParseSetFlag_Paren); - } - MD_PushSibling(&first, &last, tag); - } - else - { - MD_Token token = MD_Parse_PeekSkipSome(ctx, 0); - _MD_TokenError(ctx, token, MD_MessageKind_Error, "\"%.*s\" is not a proper tag identifier", - MD_StringExpand(token.outer_string)); - // NOTE(mal): There are reasons to consume the non-tag token, but also to leave it. - break; - } - } - else - { - break; - } - } - - *first_out = first; - *last_out = last; -} - MD_FUNCTION_IMPL MD_ParseResult MD_ParseOneNode(MD_String8 filename, MD_String8 contents) { @@ -1989,16 +1974,6 @@ MD_ParseOneNode(MD_String8 filename, MD_String8 contents) return MD_ParseOneNodeFromCtx(&ctx); } -MD_FUNCTION_IMPL void -MD_InsertToNamespace(MD_Node *ns, MD_Node *node) -{ - MD_Node *ref = MD_MakeNode(MD_NodeKind_Reference, node->string, - node->whole_string, node->filename, - node->file_contents, node->at); - ref->ref_target = node; - MD_PushChild(ns, ref); -} - MD_FUNCTION_IMPL MD_ParseResult MD_ParseWholeString(MD_String8 filename, MD_String8 contents) { @@ -2103,6 +2078,8 @@ MD_ParseWholeFile(MD_String8 filename) return parse; } +//~ Location Conversions + MD_PRIVATE_FUNCTION_IMPL MD_CodeLoc MD_CodeLocFromFileOffset(MD_String8 filename, MD_u8 *base, MD_u8 *at) { @@ -2132,6 +2109,7 @@ MD_CodeLocFromNode(MD_Node *node) return loc; } +//~ Tree/List Building MD_FUNCTION_IMPL MD_b32 MD_NodeIsNil(MD_Node *node) @@ -2142,6 +2120,24 @@ MD_NodeIsNil(MD_Node *node) MD_FUNCTION_IMPL MD_Node * MD_NilNode(void) { return &_md_nil_node; } +MD_FUNCTION_IMPL MD_Node * +MD_MakeNode(MD_NodeKind kind, MD_String8 string, + MD_String8 whole_string, MD_String8 filename, + MD_u8 *file_contents, MD_u8 *at) +{ + MD_Node *node = _MD_PushArray(MD_Node, 1); + node->kind = kind; + node->string = string; + node->whole_string = whole_string; + node->next = node->prev = node->parent = + node->first_child = node->last_child = + node->first_tag = node->last_tag = node->ref_target = MD_NilNode(); + node->filename = filename; + node->file_contents = file_contents; + node->at = at; + return node; +} + MD_FUNCTION_IMPL MD_Node * MD_MakeNodeFromToken(MD_NodeKind kind, MD_String8 filename, MD_u8 *file, MD_u8 *at, MD_Token token) { @@ -2200,67 +2196,17 @@ MD_PushTag(MD_Node *node, MD_Node *tag) tag->parent = node; } -MD_FUNCTION_IMPL MD_b32 -MD_NodeMatch(MD_Node *a, MD_Node *b, MD_MatchFlags flags) +MD_FUNCTION_IMPL void +MD_InsertToNamespace(MD_Node *ns, MD_Node *node) { - MD_b32 result = 0; - if(a->kind == b->kind && MD_StringMatch(a->string, b->string, flags)) - { - result = 1; - if(a->kind != MD_NodeKind_Tag && (flags & MD_MatchFlag_Tags)) - { - for(MD_Node *a_tag = a->first_tag, *b_tag = b->first_tag; - !MD_NodeIsNil(a_tag) || !MD_NodeIsNil(b_tag); - a_tag = a_tag->next, b_tag = b_tag->next) - { - if(MD_NodeMatch(a_tag, b_tag, flags)) - { - if(flags & MD_MatchFlag_TagArguments) - { - for(MD_Node *a_tag_arg = a_tag->first_child, *b_tag_arg = b_tag->first_child; - !MD_NodeIsNil(a_tag_arg) || !MD_NodeIsNil(b_tag_arg); - a_tag_arg = a_tag_arg->next, b_tag_arg = b_tag_arg->next) - { - if(!MD_NodeDeepMatch(a_tag_arg, b_tag_arg, flags)) - { - result = 0; - goto end; - } - } - } - } - else - { - result = 0; - goto end; - } - } - } - } - end:; - return result; + MD_Node *ref = MD_MakeNode(MD_NodeKind_Reference, node->string, + node->whole_string, node->filename, + node->file_contents, node->at); + ref->ref_target = node; + MD_PushChild(ns, ref); } -MD_FUNCTION_IMPL MD_b32 -MD_NodeDeepMatch(MD_Node *a, MD_Node *b, MD_MatchFlags flags) -{ - MD_b32 result = MD_NodeMatch(a, b, flags); - if(result) - { - for(MD_Node *a_child = a->first_child, *b_child = b->first_child; - !MD_NodeIsNil(a_child) || !MD_NodeIsNil(b_child); - a_child = a_child->next, b_child = b_child->next) - { - if(!MD_NodeDeepMatch(a_child, b_child, flags)) - { - result = 0; - goto end; - } - } - } - end:; - return result; -} +//~ Introspection Helpers MD_FUNCTION_IMPL MD_Node * MD_NodeFromString(MD_Node *first, MD_Node *last, MD_String8 string) @@ -2392,34 +2338,6 @@ MD_TagCountFromNode(MD_Node *node) return result; } -MD_FUNCTION_IMPL MD_i64 -MD_ChildCountFromNodeAndString(MD_Node *node, MD_String8 string, MD_MatchFlags flags) -{ - MD_i64 result = 0; - for(MD_EachNode(child, node->first_child)) - { - if(MD_StringMatch(child->string, string, flags)) - { - result += 1; - } - } - return result; -} - -MD_FUNCTION_IMPL MD_i64 -MD_TagCountFromNodeAndString(MD_Node *node, MD_String8 string, MD_MatchFlags flags) -{ - MD_i64 result = 0; - for(MD_EachNode(tag, node->first_tag)) - { - if(MD_StringMatch(tag->string, string, flags)) - { - result += 1; - } - } - return result; -} - MD_FUNCTION_IMPL MD_Node * MD_Deref(MD_Node *node) { @@ -2446,6 +2364,8 @@ MD_SeekNodeWithFlags(MD_Node *start, MD_NodeFlags one_past_last_flags) return result; } +//~ Error/Warning Helpers + MD_FUNCTION_IMPL void MD_NodeMessage(MD_Node *node, MD_MessageKind kind, MD_String8 str) { @@ -2467,6 +2387,72 @@ MD_NodeMessageF(MD_Node *node, MD_MessageKind kind, char *fmt, ...) va_end(args); } +//~ Tree Comparison/Verification + +MD_FUNCTION_IMPL MD_b32 +MD_NodeMatch(MD_Node *a, MD_Node *b, MD_MatchFlags flags) +{ + MD_b32 result = 0; + if(a->kind == b->kind && MD_StringMatch(a->string, b->string, flags)) + { + result = 1; + if(a->kind != MD_NodeKind_Tag && (flags & MD_MatchFlag_Tags)) + { + for(MD_Node *a_tag = a->first_tag, *b_tag = b->first_tag; + !MD_NodeIsNil(a_tag) || !MD_NodeIsNil(b_tag); + a_tag = a_tag->next, b_tag = b_tag->next) + { + if(MD_NodeMatch(a_tag, b_tag, flags)) + { + if(flags & MD_MatchFlag_TagArguments) + { + for(MD_Node *a_tag_arg = a_tag->first_child, *b_tag_arg = b_tag->first_child; + !MD_NodeIsNil(a_tag_arg) || !MD_NodeIsNil(b_tag_arg); + a_tag_arg = a_tag_arg->next, b_tag_arg = b_tag_arg->next) + { + if(!MD_NodeDeepMatch(a_tag_arg, b_tag_arg, flags)) + { + result = 0; + goto end; + } + } + } + } + else + { + result = 0; + goto end; + } + } + } + } + end:; + return result; +} + +MD_FUNCTION_IMPL MD_b32 +MD_NodeDeepMatch(MD_Node *a, MD_Node *b, MD_MatchFlags flags) +{ + MD_b32 result = MD_NodeMatch(a, b, flags); + if(result) + { + for(MD_Node *a_child = a->first_child, *b_child = b->first_child; + !MD_NodeIsNil(a_child) || !MD_NodeIsNil(b_child); + a_child = a_child->next, b_child = b_child->next) + { + if(!MD_NodeDeepMatch(a_child, b_child, flags)) + { + result = 0; + goto end; + } + } + } + end:; + return result; +} + +//~ Generation + MD_FUNCTION_IMPL void MD_OutputTree(FILE *file, MD_Node *node) { @@ -2506,6 +2492,8 @@ MD_OutputTree(FILE *file, MD_Node *node) } } +//~ Command Line Argument Helper + MD_FUNCTION MD_String8List MD_StringListFromArgCV(int argument_count, char **arguments) { @@ -2669,6 +2657,8 @@ MD_CommandLineOptionI64(MD_CommandLine cmdln, MD_String8 name) return v; } +//~ File System + MD_FUNCTION_IMPL MD_String8 MD_LoadEntireFile(MD_String8 filename) {