mirror of
https://github.com/Ed94/metadesk.git
synced 2026-06-13 07:52:22 -07:00
512 lines
14 KiB
C
512 lines
14 KiB
C
#if INTELLISENSE_DIRECTIVES
|
|
# pragma once
|
|
# include "base/base.h"
|
|
# include "os/os.h"
|
|
#endif
|
|
|
|
// Copyright (c) 2024 Epic Games Tools
|
|
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
|
|
|
////////////////////////////////
|
|
//~ rjf: Messages
|
|
|
|
typedef enum MsgKind
|
|
{
|
|
MsgKind_Null,
|
|
MsgKind_Note,
|
|
MsgKind_Warning,
|
|
MsgKind_Error,
|
|
MsgKind_FatalError,
|
|
}
|
|
MsgKind;
|
|
|
|
typedef struct Node Node;
|
|
typedef struct Msg Msg;
|
|
struct Msg
|
|
{
|
|
Msg* next;
|
|
Node* node;
|
|
MsgKind kind;
|
|
String8 string;
|
|
};
|
|
|
|
typedef struct MsgList MsgList;
|
|
struct MsgList
|
|
{
|
|
Msg* first;
|
|
Msg* last;
|
|
U64 count;
|
|
MsgKind worst_message_kind;
|
|
};
|
|
|
|
////////////////////////////////
|
|
//~ rjf: Token Types
|
|
|
|
typedef U32 TokenFlags;
|
|
enum
|
|
{
|
|
// rjf: base kind info
|
|
TokenFlag_Identifier = (1<<0),
|
|
TokenFlag_Numeric = (1<<1),
|
|
TokenFlag_StringLiteral = (1<<2),
|
|
TokenFlag_Symbol = (1<<3),
|
|
TokenFlag_Reserved = (1<<4),
|
|
TokenFlag_Comment = (1<<5),
|
|
TokenFlag_Whitespace = (1<<6),
|
|
TokenFlag_Newline = (1<<7),
|
|
|
|
// rjf: decoration info
|
|
TokenFlag_StringSingleQuote = (1<<8),
|
|
TokenFlag_StringDoubleQuote = (1<<9),
|
|
TokenFlag_StringTick = (1<<10),
|
|
TokenFlag_StringTriplet = (1<<11),
|
|
|
|
// rjf: error info
|
|
TokenFlag_BrokenComment = (1<<12),
|
|
TokenFlag_BrokenStringLiteral = (1<<13),
|
|
TokenFlag_BadCharacter = (1<<14),
|
|
};
|
|
|
|
typedef U32 TokenGroups;
|
|
enum
|
|
{
|
|
TokenGroup_Comment = TokenFlag_Comment,
|
|
TokenGroup_Whitespace = (TokenFlag_Whitespace| TokenFlag_Newline),
|
|
TokenGroup_Irregular = (TokenGroup_Comment | TokenGroup_Whitespace),
|
|
TokenGroup_Regular = ~TokenGroup_Irregular,
|
|
TokenGroup_Label = (TokenFlag_Identifier | TokenFlag_Numeric | TokenFlag_StringLiteral | TokenFlag_Symbol),
|
|
TokenGroup_Error = (TokenFlag_BrokenComment | TokenFlag_BrokenStringLiteral | TokenFlag_BadCharacter),
|
|
};
|
|
|
|
typedef struct Token Token;
|
|
struct Token
|
|
{
|
|
Rng1U64 range;
|
|
TokenFlags flags;
|
|
};
|
|
|
|
typedef struct TokenChunkNode TokenChunkNode;
|
|
struct TokenChunkNode
|
|
{
|
|
TokenChunkNode* next;
|
|
Token* v;
|
|
U64 count;
|
|
U64 cap;
|
|
};
|
|
|
|
typedef struct TokenChunkList TokenChunkList;
|
|
struct TokenChunkList
|
|
{
|
|
TokenChunkNode* first;
|
|
TokenChunkNode* last;
|
|
U64 chunk_count;
|
|
U64 total_token_count;
|
|
};
|
|
|
|
typedef struct TokenArray TokenArray;
|
|
struct TokenArray
|
|
{
|
|
Token* v;
|
|
U64 count;
|
|
};
|
|
|
|
////////////////////////////////
|
|
//~ rjf: Node Types
|
|
|
|
typedef enum NodeKind
|
|
{
|
|
NodeKind_Nil,
|
|
NodeKind_File,
|
|
NodeKind_ErrorMarker,
|
|
NodeKind_Main,
|
|
NodeKind_Tag,
|
|
NodeKind_List,
|
|
NodeKind_Reference,
|
|
NodeKind_COUNT
|
|
}
|
|
NodeKind;
|
|
|
|
typedef U32 NodeFlags;
|
|
enum
|
|
{
|
|
NodeFlag_MaskSetDelimiters = (0x3F<<0),
|
|
NodeFlag_HasParenLeft = (1<<0),
|
|
NodeFlag_HasParenRight = (1<<1),
|
|
NodeFlag_HasBracketLeft = (1<<2),
|
|
NodeFlag_HasBracketRight = (1<<3),
|
|
NodeFlag_HasBraceLeft = (1<<4),
|
|
NodeFlag_HasBraceRight = (1<<5),
|
|
|
|
NodeFlag_MaskSeparators = (0xF<<6),
|
|
NodeFlag_IsBeforeSemicolon = (1<<6),
|
|
NodeFlag_IsAfterSemicolon = (1<<7),
|
|
NodeFlag_IsBeforeComma = (1<<8),
|
|
NodeFlag_IsAfterComma = (1<<9),
|
|
|
|
NodeFlag_MaskStringDelimiters = (0xF<<10),
|
|
NodeFlag_StringSingleQuote = (1<<10),
|
|
NodeFlag_StringDoubleQuote = (1<<11),
|
|
NodeFlag_StringTick = (1<<12),
|
|
NodeFlag_StringTriplet = (1<<13),
|
|
|
|
NodeFlag_MaskLabelKind = (0xF<<14),
|
|
NodeFlag_Numeric = (1<<14),
|
|
NodeFlag_Identifier = (1<<15),
|
|
NodeFlag_StringLiteral = (1<<16),
|
|
NodeFlag_Symbol = (1<<17),
|
|
};
|
|
#define NodeFlag_AfterFromBefore(f) ((f) << 1)
|
|
|
|
typedef struct Node Node;
|
|
struct Node
|
|
{
|
|
// rjf: tree links
|
|
Node* next;
|
|
Node* prev;
|
|
Node* parent;
|
|
Node* first;
|
|
Node* last;
|
|
|
|
// rjf: tag links
|
|
Node* first_tag;
|
|
Node* last_tag;
|
|
|
|
// rjf: node info
|
|
NodeKind kind;
|
|
NodeFlags flags;
|
|
String8 string;
|
|
String8 raw_string;
|
|
|
|
// rjf: source code info
|
|
U64 src_offset;
|
|
|
|
// rjf: user-controlled generation number
|
|
//
|
|
// (unused by mdesk layer, but can be used by usage code to use Node trees
|
|
// in a "retained mode" way, where stable generational handles can be formed
|
|
// to nodes)
|
|
U64 user_gen;
|
|
|
|
// rjf: extra padding to 128 bytes
|
|
U64 _unused_[2];
|
|
};
|
|
|
|
typedef struct NodeRec NodeRec;
|
|
struct NodeRec
|
|
{
|
|
Node* next;
|
|
S32 push_count;
|
|
S32 pop_count;
|
|
};
|
|
|
|
////////////////////////////////
|
|
//~ rjf: Text -> Tokens Types
|
|
|
|
typedef struct TokenizeResult TokenizeResult;
|
|
struct TokenizeResult
|
|
{
|
|
TokenArray tokens;
|
|
MsgList msgs;
|
|
};
|
|
|
|
////////////////////////////////
|
|
//~ rjf: Tokens -> Tree Types
|
|
|
|
typedef struct ParseResult ParseResult;
|
|
struct ParseResult
|
|
{
|
|
Node* root;
|
|
MsgList msgs;
|
|
};
|
|
|
|
////////////////////////////////
|
|
//~ rjf: Globals
|
|
|
|
inline Node*
|
|
nil_node()
|
|
{
|
|
read_only thread_local local_persist
|
|
nil = {
|
|
&nil,
|
|
&nil,
|
|
&nil,
|
|
&nil,
|
|
&nil,
|
|
&nil,
|
|
&nil,
|
|
};
|
|
return &nil;
|
|
}
|
|
|
|
////////////////////////////////
|
|
//~ rjf: Message Type Functions
|
|
|
|
MD_API void msg_list_push (Arena* arena, MsgList* msgs, Node* node, MsgKind kind, String8 string);
|
|
void msg_list_pushf(Arena* arena, MsgList* msgs, Node* node, MsgKind kind, char *fmt, ...);
|
|
|
|
MD_API void msg_list_concat_in_place(MsgList* dst, MsgList* to_push);
|
|
|
|
inline void
|
|
msg_list_pushf(Arena* arena, MsgList* msgs, Node* node, MsgKind kind, char* fmt, ...) {
|
|
va_list args;
|
|
va_start(args, fmt);
|
|
String8 string = push_str8fv(arena, fmt, args);
|
|
msg_list_push(arena, msgs, node, kind, string);
|
|
va_end(args);
|
|
}
|
|
|
|
////////////////////////////////
|
|
//~ rjf: Token Type Functions
|
|
|
|
Token token_make (Rng1U64 range, TokenFlags flags);
|
|
B32 token_match(Token a, Token b);
|
|
|
|
MD_API String8 content_string_from_token_flags_str8(TokenFlags flags, String8 string);
|
|
|
|
MD_API String8List string_list_from_token_flags(Arena* arena, TokenFlags flags);
|
|
MD_API void token_chunk_list_push (Arena* arena, TokenChunkList* list, U64 cap, Token token);
|
|
MD_API TokenArray token_array_from_chunk_list (Arena* arena, TokenChunkList* chunks);
|
|
|
|
inline Token
|
|
token_make(Rng1U64 range, TokenFlags flags) {
|
|
Token token = { range, flags };
|
|
return token;
|
|
}
|
|
|
|
inline B32
|
|
token_match(Token a, Token b) {
|
|
return (a.range.min == b.range.min &&
|
|
a.range.max == b.range.max &&
|
|
a.flags == b.flags );
|
|
}
|
|
|
|
////////////////////////////////
|
|
//~ rjf: Node Type Functions
|
|
|
|
//- rjf: flag conversions
|
|
|
|
inline NodeFlags
|
|
node_flags_from_token_flags(TokenFlags flags)
|
|
{
|
|
NodeFlags result = 0;
|
|
result |= NodeFlag_Identifier *!!(flags & TokenFlag_Identifier );
|
|
result |= NodeFlag_Numeric *!!(flags & TokenFlag_Numeric );
|
|
result |= NodeFlag_StringLiteral *!!(flags & TokenFlag_StringLiteral );
|
|
result |= NodeFlag_Symbol *!!(flags & TokenFlag_Symbol );
|
|
result |= NodeFlag_StringSingleQuote *!!(flags & TokenFlag_StringSingleQuote);
|
|
result |= NodeFlag_StringDoubleQuote *!!(flags & TokenFlag_StringDoubleQuote);
|
|
result |= NodeFlag_StringTick *!!(flags & TokenFlag_StringTick );
|
|
result |= NodeFlag_StringTriplet *!!(flags & TokenFlag_StringTriplet );
|
|
return result;
|
|
}
|
|
|
|
//- rjf: nil
|
|
|
|
B32 node_is_nil(Node* node) { return (node == 0 || node == nil_node() || node->kind == NodeKind_Nil); }
|
|
|
|
//- rjf: iteration
|
|
|
|
#define each_node(it, first) (Node* it = first; !node_is_nil(it); it = it->next)
|
|
|
|
MD_API NodeRec node_rec_depth_first(Node* node, Node* subtree_root, U64 child_off, U64 sib_off);
|
|
|
|
#define node_rec_depth_first_pre(node, subtree_root) node_rec_depth_first((node), (subtree_root), offset_of(Node, first), offset_of(Node, next))
|
|
#define node_rec_depth_first_pre_rev(node, subtree_root) node_rec_depth_first((node), (subtree_root), offset_of(Node, last), offset_of(Node, prev))
|
|
|
|
//- rjf: tree building
|
|
|
|
Node* push_node (Arena* arena, NodeKind kind, NodeFlags flags, String8 string, String8 raw_string, U64 src_offset);
|
|
Node* alloc_node(AllocatorInfo ainfo, NodeKind kind, NodeFlags flags, String8 string, String8 raw_string, U64 src_offset);
|
|
|
|
void node_insert_tag (Node* parent, Node* prev_child, Node* node);
|
|
void node_insert_child(Node* parent, Node* prev_child, Node* node);
|
|
void node_push_child (Node* parent, Node* node);
|
|
void node_push_tag (Node* parent, Node* node);
|
|
void unhook (Node* node);
|
|
|
|
inline Node*
|
|
push_node(Arena* arena, NodeKind kind, NodeFlags flags, String8 string, String8 raw_string, U64 src_offset) {
|
|
Node* node = push_array(arena, Node, 1);
|
|
node->first = node->last = node->parent = node->next = node->prev = node->first_tag = node->last_tag = nil_node();
|
|
node->kind = kind;
|
|
node->flags = flags;
|
|
node->string = string;
|
|
node->raw_string = raw_string;
|
|
node->src_offset = src_offset;
|
|
return node;
|
|
}
|
|
|
|
inline void
|
|
node_insert_child(Node* parent, Node* prev_child, Node* node) {
|
|
node->parent = parent;
|
|
dll_insert_npz(nil_node(), parent->first, parent->last, prev_child, node, next, prev);
|
|
}
|
|
|
|
inline void
|
|
node_insert_tag(Node* parent, Node* prev_child, Node* node) {
|
|
node->kind = NodeKind_Tag;
|
|
node->parent = parent;
|
|
dll_insert_npz(nil_node(), parent->first_tag, parent->last_tag, prev_child, node, next, prev);
|
|
}
|
|
|
|
inline void
|
|
node_push_child(Node* parent, Node* node) {
|
|
node->parent = parent;
|
|
dll_push_back_npz(nil_node(), parent->first, parent->last, node, next, prev);
|
|
}
|
|
|
|
inline void
|
|
node_push_tag(Node* parent, Node* node) {
|
|
node->kind = NodeKind_Tag;
|
|
node->parent = parent;
|
|
dll_push_back_npz(nil_node(), parent->first_tag, parent->last_tag, node, next, prev);
|
|
}
|
|
|
|
//- rjf: tree introspection
|
|
|
|
Node* node_from_chain_string(Node* first, Node* opl, String8 string, StringMatchFlags flags);
|
|
Node* node_from_chain_index (Node* first, Node* opl, U64 index);
|
|
Node* node_from_chain_flags (Node* first, Node* opl, NodeFlags flags);
|
|
U64 index_from_node (Node* node);
|
|
Node* root_from_node (Node* node);
|
|
Node* child_from_string (Node* node, String8 child_string, StringMatchFlags flags);
|
|
Node* tag_from_string (Node* node, String8 tag_string, StringMatchFlags flags);
|
|
Node* child_from_index (Node* node, U64 index);
|
|
Node* tag_from_index (Node* node, U64 index);
|
|
Node* tag_arg_from_index (Node* node, String8 tag_string, StringMatchFlags flags, U64 index);
|
|
Node* tag_arg_from_string (Node* node, String8 tag_string, StringMatchFlags tag_str_flags, String8 arg_string, StringMatchFlags arg_str_flags);
|
|
B32 node_has_child (Node* node, String8 string, StringMatchFlags flags);
|
|
B32 node_has_tag (Node* node, String8 string, StringMatchFlags flags);
|
|
U64 child_count_from_node (Node* node);
|
|
U64 tag_count_from_node (Node* node);
|
|
|
|
MD_API String8 string_from_children(Arena* arena, Node* root);
|
|
|
|
inline Node*
|
|
node_from_chain_string(Node* first, Node* opl, String8 string, StringMatchFlags flags)
|
|
{
|
|
Node* result = nil_node();
|
|
for (Node* n = first; !node_is_nil(n) && n != opl; n = n->next)
|
|
{
|
|
if (str8_match(n->string, string, flags)) {
|
|
result = n;
|
|
break;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
inline Node*
|
|
node_from_chain_index(Node* first, Node* opl, U64 index) {
|
|
Node* result = nil_node();
|
|
S64 idx = 0;
|
|
for (Node* n = first; !node_is_nil(n) && n != opl; n = n->next, idx += 1)
|
|
{
|
|
if (index == idx) {
|
|
result = n;
|
|
break;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
inline Node*
|
|
node_from_chain_flags(Node* first, Node* opl, NodeFlags flags) {
|
|
Node* result = nil_node();
|
|
for (Node* n = first; !node_is_nil(n) && n != opl; n = n->next)
|
|
{
|
|
if (n->flags & flags) {
|
|
result = n;
|
|
break;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
inline U64
|
|
index_from_node(Node* node) {
|
|
U64 index = 0;
|
|
for (Node* n = node->prev; !node_is_nil(n); n = n->prev) {
|
|
index += 1;
|
|
}
|
|
return index;
|
|
}
|
|
|
|
inline Node*
|
|
root_from_node(Node* node) {
|
|
Node* result = node;
|
|
for (Node* p = node->parent; (p->kind == NodeKind_Main || p->kind == NodeKind_Tag) && !node_is_nil(p); p = p->parent) {
|
|
result = p;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
inline Node* child_from_string(Node* node, String8 child_string, StringMatchFlags flags) { return node_from_chain_string(node->first, nil_node(), child_string, flags); }
|
|
inline Node* tag_from_string (Node* node, String8 tag_string, StringMatchFlags flags) { return node_from_chain_string(node->first_tag, nil_node(), tag_string, flags); }
|
|
inline Node* child_from_index (Node* node, U64 index) { return node_from_chain_index (node->first, nil_node(), index); }
|
|
inline Node* tag_from_index (Node* node, U64 index) { return node_from_chain_index (node->first_tag, nil_node(), index); }
|
|
|
|
inline Node*
|
|
tag_arg_from_index(Node* node, String8 tag_string, StringMatchFlags flags, U64 index) {
|
|
Node* tag = tag_from_string(node, tag_string, flags);
|
|
return child_from_index(tag, index);
|
|
}
|
|
|
|
inline Node*
|
|
tag_arg_from_string(Node* node, String8 tag_string, StringMatchFlags tag_str_flags, String8 arg_string, StringMatchFlags arg_str_flags) {
|
|
Node* tag = tag_from_string (node, tag_string, tag_str_flags);
|
|
Node* arg = child_from_string(tag, arg_string, arg_str_flags);
|
|
return arg;
|
|
}
|
|
|
|
inline B32 node_has_child(Node* node, String8 string, StringMatchFlags flags) { return !node_is_nil(child_from_string(node, string, flags)); }
|
|
inline B32 node_has_tag (Node* node, String8 string, StringMatchFlags flags) { return !node_is_nil(tag_from_string (node, string, flags)); }
|
|
|
|
inline U64
|
|
child_count_from_node(Node *node) {
|
|
U64 result = 0;
|
|
for (Node* child = node->first; !node_is_nil(child); child = child->next) {
|
|
result += 1;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
inline U64
|
|
tag_count_from_node(Node* node) {
|
|
U64 result = 0;
|
|
for (Node* child = node->first_tag; !node_is_nil(child); child = child->next) {
|
|
result += 1;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
//- rjf: tree comparison
|
|
|
|
MD_API B32 tree_match(Node* a, Node* b, StringMatchFlags flags);
|
|
MD_API B32 node_match(Node* a, Node* b, StringMatchFlags flags);
|
|
|
|
//- rjf: tree duplication
|
|
|
|
MD_API Node* tree_copy(Arena* arena, Node* src_root);
|
|
|
|
////////////////////////////////
|
|
//~ rjf: Text -> Tokens Functions
|
|
|
|
MD_API TokenizeResult tokenize_from_text(Arena* arena, String8 text);
|
|
|
|
////////////////////////////////
|
|
//~ rjf: Tokens -> Tree Functions
|
|
|
|
MD_API ParseResult parse_from_text_tokens(Arena* arena, String8 filename, String8 text, TokenArray tokens);
|
|
|
|
////////////////////////////////
|
|
//~ rjf: Bundled Text -> Tree Functions
|
|
|
|
ParseResult parse_from_text(Arena* arena, String8 filename, String8 text);
|
|
#define tree_from_string(arena, string) (parse_from_text((arena), str8_zero(), (string)).root)
|
|
|
|
////////////////////////////////
|
|
//~ rjf: Tree -> Text Functions
|
|
|
|
String8List debug_string_list_from_tree(Arena* arena, Node* root);
|