mirror of
https://github.com/Ed94/metadesk.git
synced 2026-08-08 16:48:15 +00:00
re-order md_impl; keep everything in same order as header file
This commit is contained in:
+8
-3
@@ -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_String8 MD_S8FromS32(MD_String32 str);
|
||||||
MD_FUNCTION MD_String32 MD_S32FromS8(MD_String8 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_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_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);
|
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_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);
|
MD_FUNCTION MD_b32 MD_PtrMap_Insert(MD_Map *map, MD_MapCollisionRule collision_rule, void *key, void *value);
|
||||||
|
|
||||||
//~ Parsing
|
//~ Parsing
|
||||||
|
|
||||||
MD_FUNCTION MD_b32 MD_TokenKindIsWhitespace(MD_TokenKind kind);
|
MD_FUNCTION MD_b32 MD_TokenKindIsWhitespace(MD_TokenKind kind);
|
||||||
MD_FUNCTION MD_b32 MD_TokenKindIsComment(MD_TokenKind kind);
|
MD_FUNCTION MD_b32 MD_TokenKindIsComment(MD_TokenKind kind);
|
||||||
MD_FUNCTION MD_b32 MD_TokenKindIsRegular(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_Bump(MD_ParseCtx *ctx, MD_Token token);
|
||||||
MD_FUNCTION void MD_Parse_BumpNext(MD_ParseCtx *ctx);
|
MD_FUNCTION void MD_Parse_BumpNext(MD_ParseCtx *ctx);
|
||||||
MD_FUNCTION MD_Token MD_Parse_LexNext(MD_ParseCtx *ctx);
|
MD_FUNCTION MD_Token MD_Parse_LexNext(MD_ParseCtx *ctx);
|
||||||
|
|||||||
+389
-399
@@ -68,6 +68,8 @@ _MD_AllocZero(MD_u64 size)
|
|||||||
|
|
||||||
#define _MD_PushArray(type, count) (type *)_MD_AllocZero(sizeof(type)*(count))
|
#define _MD_PushArray(type, count) (type *)_MD_AllocZero(sizeof(type)*(count))
|
||||||
|
|
||||||
|
//~ Basic Utilities
|
||||||
|
|
||||||
MD_FUNCTION_IMPL MD_b32
|
MD_FUNCTION_IMPL MD_b32
|
||||||
MD_CharIsAlpha(MD_u8 c)
|
MD_CharIsAlpha(MD_u8 c)
|
||||||
{
|
{
|
||||||
@@ -135,6 +137,8 @@ MD_CorrectSlash(MD_u8 c)
|
|||||||
return (c == '\\' ? '/' : c);
|
return (c == '\\' ? '/' : c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//~ Strings
|
||||||
|
|
||||||
MD_FUNCTION_IMPL MD_String8
|
MD_FUNCTION_IMPL MD_String8
|
||||||
MD_S8(MD_u8 *str, MD_u64 size)
|
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;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//~ Enum/Flag Strings
|
||||||
|
|
||||||
MD_FUNCTION_IMPL MD_String8
|
MD_FUNCTION_IMPL MD_String8
|
||||||
MD_StringFromNodeKind(MD_NodeKind kind)
|
MD_StringFromNodeKind(MD_NodeKind kind)
|
||||||
{
|
{
|
||||||
@@ -689,10 +695,9 @@ MD_StringListFromNodeFlags(MD_NodeFlags flags)
|
|||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////
|
//~ Unicode Conversions
|
||||||
// NOTE(allen): Unicode
|
|
||||||
|
|
||||||
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,
|
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_UnicodeConsume result = {~((MD_u32)0), 1};
|
||||||
MD_u8 byte = str[0];
|
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)
|
switch (byte_class)
|
||||||
{
|
{
|
||||||
case 1:
|
case 1:
|
||||||
@@ -725,7 +730,7 @@ MD_CodepointFromUtf8(MD_u8 *str, MD_u64 max)
|
|||||||
if (2 <= max)
|
if (2 <= max)
|
||||||
{
|
{
|
||||||
MD_u8 cont_byte = str[1];
|
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 = (byte & MD_bitmask5) << 6;
|
||||||
result.codepoint |= (cont_byte & MD_bitmask6);
|
result.codepoint |= (cont_byte & MD_bitmask6);
|
||||||
@@ -739,8 +744,8 @@ MD_CodepointFromUtf8(MD_u8 *str, MD_u64 max)
|
|||||||
if (3 <= max)
|
if (3 <= max)
|
||||||
{
|
{
|
||||||
MD_u8 cont_byte[2] = {str[1], str[2]};
|
MD_u8 cont_byte[2] = {str[1], str[2]};
|
||||||
if (dd_utf8_class[cont_byte[0] >> 3] == 0 &&
|
if (md_utf8_class[cont_byte[0] >> 3] == 0 &&
|
||||||
dd_utf8_class[cont_byte[1] >> 3] == 0)
|
md_utf8_class[cont_byte[1] >> 3] == 0)
|
||||||
{
|
{
|
||||||
result.codepoint = (byte & MD_bitmask4) << 12;
|
result.codepoint = (byte & MD_bitmask4) << 12;
|
||||||
result.codepoint |= ((cont_byte[0] & MD_bitmask6) << 6);
|
result.codepoint |= ((cont_byte[0] & MD_bitmask6) << 6);
|
||||||
@@ -755,9 +760,9 @@ MD_CodepointFromUtf8(MD_u8 *str, MD_u64 max)
|
|||||||
if (4 <= max)
|
if (4 <= max)
|
||||||
{
|
{
|
||||||
MD_u8 cont_byte[3] = {str[1], str[2], str[3]};
|
MD_u8 cont_byte[3] = {str[1], str[2], str[3]};
|
||||||
if (dd_utf8_class[cont_byte[0] >> 3] == 0 &&
|
if (md_utf8_class[cont_byte[0] >> 3] == 0 &&
|
||||||
dd_utf8_class[cont_byte[1] >> 3] == 0 &&
|
md_utf8_class[cont_byte[1] >> 3] == 0 &&
|
||||||
dd_utf8_class[cont_byte[2] >> 3] == 0)
|
md_utf8_class[cont_byte[2] >> 3] == 0)
|
||||||
{
|
{
|
||||||
result.codepoint = (byte & MD_bitmask3) << 18;
|
result.codepoint = (byte & MD_bitmask3) << 18;
|
||||||
result.codepoint |= ((cont_byte[0] & MD_bitmask6) << 12);
|
result.codepoint |= ((cont_byte[0] & MD_bitmask6) << 12);
|
||||||
@@ -924,8 +929,8 @@ MD_S32FromS8(MD_String8 in)
|
|||||||
return(result);
|
return(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////
|
//~ Map Table Data Structure
|
||||||
//~ String-To-Ptr and Ptr-To-Ptr tables
|
|
||||||
MD_PRIVATE_FUNCTION_IMPL void
|
MD_PRIVATE_FUNCTION_IMPL void
|
||||||
_MD_Map_Initialize(MD_Map *map)
|
_MD_Map_Initialize(MD_Map *map)
|
||||||
{
|
{
|
||||||
@@ -936,13 +941,24 @@ _MD_Map_Initialize(MD_Map *map)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////
|
// NOTE(mal): Generic 64-bit hash function (https://nullprogram.com/blog/2018/07/31/)
|
||||||
//~ NOTE(mal): MD_StringMap
|
// 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_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_Map_Initialize(map);
|
||||||
|
|
||||||
MD_MapSlot *slot = 0;
|
MD_MapSlot *slot = 0;
|
||||||
MD_u64 hash = MD_HashString(string);
|
MD_u64 hash = MD_HashString(string);
|
||||||
MD_u64 index = hash % map->table_size;
|
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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return slot;
|
return slot;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1030,20 +1045,7 @@ MD_StringMap_Next(MD_MapSlot *slot, MD_String8 key)
|
|||||||
return next;
|
return next;
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////
|
//- Pointer-To-Pointer Table
|
||||||
//~ 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
MD_FUNCTION_IMPL MD_MapSlot *
|
MD_FUNCTION_IMPL MD_MapSlot *
|
||||||
MD_PtrMap_Lookup(MD_Map *map, void *key)
|
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;
|
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_FUNCTION_IMPL MD_b32
|
||||||
MD_TokenKindIsWhitespace(MD_TokenKind kind)
|
MD_TokenKindIsWhitespace(MD_TokenKind kind)
|
||||||
{
|
{
|
||||||
@@ -1488,125 +1638,136 @@ MD_Parse_RequireKind(MD_ParseCtx *ctx, MD_TokenKind kind, MD_Token *out_token)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
MD_PRIVATE_FUNCTION_IMPL void
|
MD_FUNCTION_IMPL void
|
||||||
_MD_Error(MD_ParseCtx *ctx, MD_Node *node, MD_MessageKind kind, char *fmt, ...)
|
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.
|
MD_b32 brace = 0;
|
||||||
// The alternative is to drop a prev pointer into MD_Error and search backwards
|
MD_b32 paren = 0;
|
||||||
MD_Error *prev_error = 0;
|
MD_b32 bracket = 0;
|
||||||
for(MD_Error *e = ctx->first_error; e; e = e->next)
|
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))
|
||||||
{
|
{
|
||||||
prev_error = e;
|
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
|
else
|
||||||
{
|
{
|
||||||
break;
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE(mal): Ignore errors after first catastrophic error
|
MD_ParseResult parse = MD_ParseOneNodeFromCtx(ctx);
|
||||||
if(ctx->error_level < MD_MessageKind_CatastrophicError || !prev_error || prev_error->next)
|
MD_Node *child = parse.node;
|
||||||
|
child->flags |= next_child_flags;
|
||||||
|
next_child_flags = 0;
|
||||||
|
if(MD_NodeIsNil(child))
|
||||||
{
|
{
|
||||||
MD_Error *error = _MD_PushArray(MD_Error, 1);
|
if(brace || paren || bracket)
|
||||||
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;
|
char delimiter_char = 0;
|
||||||
prev_error->next = error;
|
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
|
else
|
||||||
{
|
{
|
||||||
error->next = ctx->first_error;
|
MD_PushSibling(&parent->first_child, &parent->last_child, child);
|
||||||
ctx->first_error = error;
|
child->parent = parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!ctx->last_error || ctx->last_error == prev_error)
|
// NOTE(rjf): Separators.
|
||||||
{
|
{
|
||||||
ctx->last_error = error;
|
MD_b32 result = 0;
|
||||||
}
|
if(terminate_with_separator)
|
||||||
|
|
||||||
if(kind > ctx->error_level)
|
|
||||||
{
|
{
|
||||||
ctx->error_level = kind;
|
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))
|
||||||
#define _MD_TokenError(ctx, token, kind, fmt, ...) \
|
{
|
||||||
_MD_Error(ctx, _MD_MakeNodeFromToken_Ctx(ctx, MD_NodeKind_ErrorMarker, token), kind, fmt, __VA_ARGS__)
|
child->flags |= MD_NodeFlag_BeforeComma;
|
||||||
|
next_child_flags |= MD_NodeFlag_AfterComma;
|
||||||
MD_FUNCTION_IMPL MD_Node *
|
}
|
||||||
MD_MakeNode(MD_NodeKind kind, MD_String8 string,
|
else if(MD_Parse_Require(ctx, MD_S8Lit(";"), MD_TokenKind_Symbol))
|
||||||
MD_String8 whole_string, MD_String8 filename,
|
{
|
||||||
MD_u8 *file_contents, MD_u8 *at)
|
child->flags |= MD_NodeFlag_BeforeSemicolon;
|
||||||
{
|
next_child_flags |= MD_NodeFlag_AfterSemicolon;
|
||||||
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
|
if(result)
|
||||||
_MD_StringLiteralIsBalanced(MD_Token token)
|
{
|
||||||
{
|
goto end_parse;
|
||||||
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
|
end_parse:;
|
||||||
_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_FUNCTION_IMPL MD_ParseResult
|
MD_FUNCTION_IMPL MD_ParseResult
|
||||||
@@ -1806,182 +1967,6 @@ MD_ParseOneNodeFromCtx(MD_ParseCtx *ctx)
|
|||||||
return result;
|
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_FUNCTION_IMPL MD_ParseResult
|
||||||
MD_ParseOneNode(MD_String8 filename, MD_String8 contents)
|
MD_ParseOneNode(MD_String8 filename, MD_String8 contents)
|
||||||
{
|
{
|
||||||
@@ -1989,16 +1974,6 @@ MD_ParseOneNode(MD_String8 filename, MD_String8 contents)
|
|||||||
return MD_ParseOneNodeFromCtx(&ctx);
|
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_FUNCTION_IMPL MD_ParseResult
|
||||||
MD_ParseWholeString(MD_String8 filename, MD_String8 contents)
|
MD_ParseWholeString(MD_String8 filename, MD_String8 contents)
|
||||||
{
|
{
|
||||||
@@ -2103,6 +2078,8 @@ MD_ParseWholeFile(MD_String8 filename)
|
|||||||
return parse;
|
return parse;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//~ Location Conversions
|
||||||
|
|
||||||
MD_PRIVATE_FUNCTION_IMPL MD_CodeLoc
|
MD_PRIVATE_FUNCTION_IMPL MD_CodeLoc
|
||||||
MD_CodeLocFromFileOffset(MD_String8 filename, MD_u8 *base, MD_u8 *at)
|
MD_CodeLocFromFileOffset(MD_String8 filename, MD_u8 *base, MD_u8 *at)
|
||||||
{
|
{
|
||||||
@@ -2132,6 +2109,7 @@ MD_CodeLocFromNode(MD_Node *node)
|
|||||||
return loc;
|
return loc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//~ Tree/List Building
|
||||||
|
|
||||||
MD_FUNCTION_IMPL MD_b32
|
MD_FUNCTION_IMPL MD_b32
|
||||||
MD_NodeIsNil(MD_Node *node)
|
MD_NodeIsNil(MD_Node *node)
|
||||||
@@ -2142,6 +2120,24 @@ MD_NodeIsNil(MD_Node *node)
|
|||||||
MD_FUNCTION_IMPL MD_Node *
|
MD_FUNCTION_IMPL MD_Node *
|
||||||
MD_NilNode(void) { return &_md_nil_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_FUNCTION_IMPL MD_Node *
|
||||||
MD_MakeNodeFromToken(MD_NodeKind kind, MD_String8 filename, MD_u8 *file, MD_u8 *at, MD_Token token)
|
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;
|
tag->parent = node;
|
||||||
}
|
}
|
||||||
|
|
||||||
MD_FUNCTION_IMPL MD_b32
|
MD_FUNCTION_IMPL void
|
||||||
MD_NodeMatch(MD_Node *a, MD_Node *b, MD_MatchFlags flags)
|
MD_InsertToNamespace(MD_Node *ns, MD_Node *node)
|
||||||
{
|
{
|
||||||
MD_b32 result = 0;
|
MD_Node *ref = MD_MakeNode(MD_NodeKind_Reference, node->string,
|
||||||
if(a->kind == b->kind && MD_StringMatch(a->string, b->string, flags))
|
node->whole_string, node->filename,
|
||||||
{
|
node->file_contents, node->at);
|
||||||
result = 1;
|
ref->ref_target = node;
|
||||||
if(a->kind != MD_NodeKind_Tag && (flags & MD_MatchFlag_Tags))
|
MD_PushChild(ns, ref);
|
||||||
{
|
|
||||||
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
|
//~ Introspection Helpers
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
MD_FUNCTION_IMPL MD_Node *
|
MD_FUNCTION_IMPL MD_Node *
|
||||||
MD_NodeFromString(MD_Node *first, MD_Node *last, MD_String8 string)
|
MD_NodeFromString(MD_Node *first, MD_Node *last, MD_String8 string)
|
||||||
@@ -2392,34 +2338,6 @@ MD_TagCountFromNode(MD_Node *node)
|
|||||||
return result;
|
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_FUNCTION_IMPL MD_Node *
|
||||||
MD_Deref(MD_Node *node)
|
MD_Deref(MD_Node *node)
|
||||||
{
|
{
|
||||||
@@ -2446,6 +2364,8 @@ MD_SeekNodeWithFlags(MD_Node *start, MD_NodeFlags one_past_last_flags)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//~ Error/Warning Helpers
|
||||||
|
|
||||||
MD_FUNCTION_IMPL void
|
MD_FUNCTION_IMPL void
|
||||||
MD_NodeMessage(MD_Node *node, MD_MessageKind kind, MD_String8 str)
|
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);
|
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_FUNCTION_IMPL void
|
||||||
MD_OutputTree(FILE *file, MD_Node *node)
|
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_FUNCTION MD_String8List
|
||||||
MD_StringListFromArgCV(int argument_count, char **arguments)
|
MD_StringListFromArgCV(int argument_count, char **arguments)
|
||||||
{
|
{
|
||||||
@@ -2669,6 +2657,8 @@ MD_CommandLineOptionI64(MD_CommandLine cmdln, MD_String8 name)
|
|||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//~ File System
|
||||||
|
|
||||||
MD_FUNCTION_IMPL MD_String8
|
MD_FUNCTION_IMPL MD_String8
|
||||||
MD_LoadEntireFile(MD_String8 filename)
|
MD_LoadEntireFile(MD_String8 filename)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user