//~ Metadesk Library // TODO List // // - Expression/Type helper // - Parsing things as a type, getting basic type info // - Radix for MD_I64FromString // - Freeing calls, allow hooking the allocator with an arena or // something so that someone can use this for work at an application/game's // runtime // - Outputting anything to MD or C code ideally would do something // smart with auto-indentation, since some people have wanted readable // layout (if they aren't using 4coder with virtual whitespace basically) // - Building with Clang // - Split out C-related stuff into helper language layers // - Helpers for parsing NodeFlags, figuring out which nodes in a set are // separated by a semicolon, something like MD_SeekNodeWithFlags(node) -> node ? // NOTE(allen): "Plugin" functionality // // MD_b32 MD_IMPL_FileIterIncrement(MD_FileIter*, MD_String8, MD_FileInfo*) - optional // void* MD_IMPL_Alloc(void*,MD_u64) - required // void* MD_IMPL_GetCtx(void) - optional // // TODO(allen): Commentary about this system somewhere easy to discover when // you go digging. #ifndef MD_H #define MD_H // NOTE(rjf): Compiler cracking from the 4th dimension #if defined(_MSC_VER) # define MD_COMPILER_CL 1 # if defined(_WIN32) # define MD_OS_WINDOWS 1 # else # error This compiler/platform combo is not supported yet # endif # if defined(_M_AMD64) # define MD_ARCH_X64 1 # elif defined(_M_IX86) # define MD_ARCH_X86 1 # elif defined(_M_ARM64) # define MD_ARCH_ARM64 1 # elif defined(_M_ARM) # define MD_ARCH_ARM32 1 # else # error architecture not supported yet # endif #if _MSC_VER >= 1920 #define MD_COMPILER_CL_YEAR 2019 #elif _MSC_VER >= 1910 #define MD_COMPILER_CL_YEAR 2017 #elif _MSC_VER >= 1900 #define MD_COMPILER_CL_YEAR 2015 #elif _MSC_VER >= 1800 #define MD_COMPILER_CL_YEAR 2013 #elif _MSC_VER >= 1700 #define MD_COMPILER_CL_YEAR 2012 #elif _MSC_VER >= 1600 #define MD_COMPILER_CL_YEAR 2010 #elif _MSC_VER >= 1500 #define MD_COMPILER_CL_YEAR 2008 #elif _MSC_VER >= 1400 #define MD_COMPILER_CL_YEAR 2005 #else #define MD_COMPILER_CL_YEAR 0 #endif #elif defined(__clang__) # define MD_COMPILER_CLANG 1 # if defined(__APPLE__) && defined(__MACH__) # define MD_OS_MAC 1 # elif defined(__gnu_linux__) # define MD_OS_LINUX 1 # else # error This compiler/platform combo is not supported yet # endif # if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) # define MD_ARCH_X64 1 # elif defined(i386) || defined(__i386) || defined(__i386__) # define MD_ARCH_X86 1 # elif defined(__aarch64__) # define MD_ARCH_ARM64 1 # elif defined(__arm__) # define MD_ARCH_ARM32 1 # else # error architecture not supported yet # endif #elif defined(__GNUC__) || defined(__GNUG__) # define MD_COMPILER_GCC 1 # if defined(__gnu_linux__) # define MD_OS_LINUX 1 # else # error This compiler/platform combo is not supported yet # endif # if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) # define MD_ARCH_X64 1 # elif defined(i386) || defined(__i386) || defined(__i386__) # define MD_ARCH_X86 1 # elif defined(__aarch64__) # define MD_ARCH_ARM64 1 # elif defined(__arm__) # define MD_ARCH_ARM32 1 # else # error architecture not supported yet # endif #else # error This compiler is not supported yet #endif #if defined(MD_ARCH_X64) # define MD_ARCH_64BIT 1 #elif defined(MD_ARCH_X86) # define MD_ARCH_32BIT 1 #endif // NOTE(allen): Review @rjf; Building in C++ // Added language cracking. Handy for a few pesky problems that can't be solved // strictly within the intersection of C & C++ #if defined(__cplusplus) # define MD_LANG_CPP 1 #else # define MD_LANG_C 1 #endif // zeroify #if !defined(MD_ARCH_32BIT) #define MD_ARCH_32BIT 0 #endif #if !defined(MD_ARCH_64BIT) #define MD_ARCH_64BIT 0 #endif #if !defined(MD_ARCH_X64) #define MD_ARCH_X64 0 #endif #if !defined(MD_ARCH_X86) #define MD_ARCH_X86 0 #endif #if !defined(MD_ARCH_ARM64) #define MD_ARCH_ARM64 0 #endif #if !defined(MD_ARCH_ARM32) #define MD_ARCH_ARM32 0 #endif #if !defined(MD_COMPILER_CL) #define MD_COMPILER_CL 0 #endif #if !defined(MD_COMPILER_GCC) #define MD_COMPILER_GCC 0 #endif #if !defined(MD_COMPILER_CLANG) #define MD_COMPILER_CLANG 0 #endif #if !defined(MD_OS_WINDOWS) #define MD_OS_WINDOWS 0 #endif #if !defined(MD_OS_LINUX) #define MD_OS_LINUX 0 #endif #if !defined(MD_OS_MAC) #define MD_OS_MAC 0 #endif #if !defined(MD_LANG_C) #define MD_LANG_C 0 #endif #if !defined(MD_LANG_CPP) #define MD_LANG_CPP 0 #endif #define MD_FUNCTION #define MD_GLOBAL static // NOTE(allen): Review @rjf; Building in C++ // In order to link to C functions from C++ code, we need to mark them as using // C linkage. In particular I mean FindFirstFileA, FindNextFileA right now. // We don't necessarily need to apply this to the DD functions if the user is // building from source, so I haven't done that. #if MD_LANG_C # define MD_C_LINKAGE_BEGIN # define MD_C_LINKAGE_END #else # define MD_C_LINKAGE_BEGIN extern "C"{ # define MD_C_LINKAGE_END } #endif #include #include #include #include // NOTE(allen): Review @rjf; Building in C++ // In C++ compiler I have to include this to get memset and memcpy to compile #include typedef int8_t MD_i8; typedef int16_t MD_i16; typedef int32_t MD_i32; typedef int64_t MD_i64; typedef uint8_t MD_u8; typedef uint16_t MD_u16; typedef uint32_t MD_u32; typedef uint64_t MD_u64; typedef int8_t MD_b8; typedef int16_t MD_b16; typedef int32_t MD_b32; typedef int64_t MD_b64; typedef float MD_f32; typedef double MD_f64; //~ Basic UTF-8 string types. typedef struct MD_String8 MD_String8; struct MD_String8 { MD_u8 *str; MD_u64 size; }; typedef struct MD_String16 MD_String16; struct MD_String16 { MD_u16 *str; MD_u64 size; }; typedef struct MD_String32 MD_String32; struct MD_String32 { MD_u32 *str; MD_u64 size; }; typedef struct MD_String8Node MD_String8Node; struct MD_String8Node { MD_String8Node *next; MD_String8 string; }; typedef struct MD_String8List MD_String8List; struct MD_String8List { MD_u64 node_count; MD_u64 total_size; MD_String8Node *first; MD_String8Node *last; }; typedef MD_u32 MD_StringMatchFlags; enum { MD_StringMatchFlag_CaseInsensitive = (1<<0), MD_StringMatchFlag_RightSideSloppy = (1<<1), MD_StringMatchFlag_FindLast = (1<<2), MD_StringMatchFlag_SlashInsensitive = (1<<3), }; typedef struct MD_UnicodeConsume MD_UnicodeConsume; struct MD_UnicodeConsume { MD_u32 codepoint; MD_u32 advance; }; typedef enum MD_WordStyle { MD_WordStyle_UpperCamelCase, MD_WordStyle_LowerCamelCase, MD_WordStyle_UpperCase, MD_WordStyle_LowerCase, } MD_WordStyle; //~ Node types that are used to build all ASTs. typedef enum MD_NodeKind { MD_NodeKind_Nil, MD_NodeKind_File, MD_NodeKind_Label, MD_NodeKind_UnnamedSet, MD_NodeKind_Tag, MD_NodeKind_MAX, } MD_NodeKind; typedef MD_u32 MD_NodeFlags; enum { MD_NodeFlag_ParenLeft = (1<<0), MD_NodeFlag_ParenRight = (1<<1), MD_NodeFlag_BracketLeft = (1<<2), MD_NodeFlag_BracketRight = (1<<3), MD_NodeFlag_BraceLeft = (1<<4), MD_NodeFlag_BraceRight = (1<<5), MD_NodeFlag_BeforeSemicolon = (1<<6), MD_NodeFlag_BeforeComma = (1<<7), MD_NodeFlag_AfterSemicolon = (1<<8), MD_NodeFlag_AfterComma = (1<<9), MD_NodeFlag_Numeric = (1<<10), MD_NodeFlag_Identifier = (1<<11), MD_NodeFlag_StringLiteral = (1<<12), MD_NodeFlag_CharLiteral = (1<<13), }; typedef MD_u32 MD_NodeMatchFlags; enum { MD_NodeMatchFlag_Tags = (1<<0), MD_NodeMatchFlag_TagArguments = (1<<1), }; typedef struct MD_Node MD_Node; struct MD_Node { // Tree relationship data. MD_Node *next; MD_Node *prev; MD_Node *parent; MD_Node *first_child; MD_Node *last_child; // Tag list. MD_Node *first_tag; MD_Node *last_tag; // Node info. MD_NodeKind kind; MD_NodeFlags flags; MD_String8 string; MD_String8 whole_string; MD_u64 string_hash; // Source code location information. MD_String8 filename; MD_u8 *file_contents; MD_u8 *at; }; //~ Code Location Info. typedef struct MD_CodeLoc MD_CodeLoc; struct MD_CodeLoc { MD_String8 filename; int line; int column; }; //~ Warning Levels typedef enum MD_MessageKind { MD_MessageKind_Error, MD_MessageKind_Warning, } MD_MessageKind; //~ String-To-Node table typedef enum MD_NodeTableCollisionRule { MD_NodeTableCollisionRule_Chain, MD_NodeTableCollisionRule_Overwrite, } MD_NodeTableCollisionRule; typedef struct MD_NodeTableSlot MD_NodeTableSlot; struct MD_NodeTableSlot { MD_NodeTableSlot *next; MD_u64 hash; MD_Node *node; }; typedef struct MD_NodeTable MD_NodeTable; struct MD_NodeTable { MD_u64 table_size; MD_NodeTableSlot **table; }; //~ Token kinds. typedef enum MD_TokenKind { MD_TokenKind_Nil, MD_TokenKind_RegularMin, // A group of characters that begins with an underscore or alphabetic character, // and consists of numbers, alphabetic characters, or underscores after that. MD_TokenKind_Identifier, // A group of characters beginning with a numeric character or a '-', and then // consisting of only numbers, alphabetic characters, or '.'s after that. MD_TokenKind_NumericLiteral, // A group of arbitrary characters, grouped together by a " character, OR by a // """ symbol at the beginning and end of the group. String literals beginning with // " are to only be specified on a single line, but """ strings can exist across // many lines. MD_TokenKind_StringLiteral, // A group of arbitrary characters, grouped together by a ' character at the beginning, // and a ' character at the end. MD_TokenKind_CharLiteral, // A group of symbolic characters, where symbolic characters means any of the following: // ~!@#$%^&*()-+=[{]}:;<>,./?|\ // // Groups of multiple characters are only allowed in specific circumstances. Most of these // are only 1 character long, but some groups are allowed: // // "<<", ">>", "<=", ">=", "+=", "-=", "*=", "/=", "::", ":=", "==", "&=", "|=", "->" MD_TokenKind_Symbol, MD_TokenKind_RegularMax, MD_TokenKind_Comment, MD_TokenKind_WhitespaceMin, MD_TokenKind_Whitespace, MD_TokenKind_Newline, MD_TokenKind_WhitespaceMax, MD_TokenKind_MAX, } MD_TokenKind; //~ Token type. typedef struct MD_Token MD_Token; struct MD_Token { MD_TokenKind kind; MD_String8 string; MD_String8 outer_string; }; //~ Token groups. typedef MD_u32 MD_TokenGroups; enum{ MD_TokenGroup_Comment = (1 << 0), MD_TokenGroup_Whitespace = (1 << 1), MD_TokenGroup_Regular = (1 << 2) }; //~ Parsing State typedef struct MD_Error MD_Error; struct MD_Error { MD_Error *next; MD_String8 string; MD_String8 filename; MD_Node *node; }; typedef struct MD_ParseCtx MD_ParseCtx; struct MD_ParseCtx { MD_Node *first_root; MD_Node *last_root; MD_Error *first_error; MD_Error *last_error; MD_u8 *at; MD_String8 filename; MD_String8 file_contents; }; typedef struct MD_ParseResult MD_ParseResult; struct MD_ParseResult { MD_Node *node; MD_Error *first_error; MD_u64 bytes_parsed; }; //~ Expression and Type-Expression parser helper types. typedef enum MD_ExprKind { // VERY_IMPORTANT_NOTE(rjf): If this enum is ever changed, ensure that // it is kept in-sync with the MD_ExprPrecFromExprKind and the following // functions: // // MD_BinaryExprKindFromNode // MD_PreUnaryExprKindFromNode // MD_PostUnaryExprKindFromNode MD_ExprKind_Nil, // NOTE(rjf): Atom MD_ExprKind_Atom, // NOTE(rjf): Access MD_ExprKind_Dot, MD_ExprKind_Arrow, MD_ExprKind_Call, MD_ExprKind_Subscript, MD_ExprKind_Dereference, MD_ExprKind_Reference, // NOTE(rjf): Arithmetic MD_ExprKind_Add, MD_ExprKind_Subtract, MD_ExprKind_Multiply, MD_ExprKind_Divide, MD_ExprKind_Mod, // NOTE(rjf): Comparison MD_ExprKind_IsEqual, MD_ExprKind_IsNotEqual, MD_ExprKind_LessThan, MD_ExprKind_GreaterThan, MD_ExprKind_LessThanEqualTo, MD_ExprKind_GreaterThanEqualTo, // NOTE(rjf): Bools MD_ExprKind_BoolAnd, MD_ExprKind_BoolOr, MD_ExprKind_BoolNot, // NOTE(rjf): Bitwise MD_ExprKind_BitAnd, MD_ExprKind_BitOr, MD_ExprKind_BitNot, MD_ExprKind_BitXor, MD_ExprKind_LeftShift, MD_ExprKind_RightShift, // NOTE(rjf): Unary numeric MD_ExprKind_Negative, // NOTE(rjf): Type MD_ExprKind_Pointer, MD_ExprKind_Array, MD_ExprKind_MAX, } MD_ExprKind; typedef MD_i32 MD_ExprPrec; typedef struct MD_Expr MD_Expr; struct MD_Expr { MD_Node *node; MD_ExprKind kind; MD_Expr *parent; MD_Expr *sub[2]; }; //~ Command line parsing helper types. typedef struct MD_CommandLine MD_CommandLine; struct MD_CommandLine { // TODO(rjf): Linked-list vs. array? MD_String8 *arguments; int argument_count; }; //~ File system access types. typedef MD_u32 MD_FileFlags; enum { MD_FileFlag_Directory = (1<<0), }; typedef struct MD_FileInfo MD_FileInfo; struct MD_FileInfo { MD_FileFlags flags; MD_String8 filename; MD_u64 file_size; }; typedef struct MD_FileIter MD_FileIter; struct MD_FileIter { // This is opaque state to store OS-specific file-system iteration data. MD_u64 state; }; //~ Basic Utilities #define MD_Assert(c) if (!(c)) { *(volatile MD_u64 *)0 = 0; } #define MD_ArrayCount(a) (sizeof(a) / sizeof((a)[0])) MD_FUNCTION MD_b32 MD_CharIsAlpha(MD_u8 c); MD_FUNCTION MD_b32 MD_CharIsAlphaUpper(MD_u8 c); MD_FUNCTION MD_b32 MD_CharIsAlphaLower(MD_u8 c); MD_FUNCTION MD_b32 MD_CharIsDigit(MD_u8 c); MD_FUNCTION MD_b32 MD_CharIsSymbol(MD_u8 c); MD_FUNCTION MD_b32 MD_CharIsSpace(MD_u8 c); MD_FUNCTION MD_u8 MD_CharToUpper(MD_u8 c); MD_FUNCTION MD_u8 MD_CharToLower(MD_u8 c); MD_FUNCTION MD_u8 MD_CorrectSlash(MD_u8 c); //~ Strings MD_FUNCTION MD_String8 MD_S8(MD_u8 *str, MD_u64 size); #define MD_S8CString(s) MD_S8((MD_u8 *)(s), MD_CalculateCStringLength(s)) #if MD_LANG_C #define MD_S8Lit(s) (MD_String8){(MD_u8 *)(s), sizeof(s)-1} #elif MD_LANG_CPP #define MD_S8Lit(s) MD_S8((MD_u8*)(s), sizeof(s) - 1) #endif MD_FUNCTION MD_String8 MD_S8Range(MD_u8 *str, MD_u8 *opl); MD_FUNCTION MD_String8 MD_StringSubstring(MD_String8 str, MD_u64 min, MD_u64 max); MD_FUNCTION MD_String8 MD_StringSkip(MD_String8 str, MD_u64 min); MD_FUNCTION MD_String8 MD_StringChop(MD_String8 str, MD_u64 nmax); MD_FUNCTION MD_String8 MD_StringPrefix(MD_String8 str, MD_u64 size); MD_FUNCTION MD_String8 MD_StringSuffix(MD_String8 str, MD_u64 size); MD_FUNCTION MD_b32 MD_StringMatch(MD_String8 a, MD_String8 b, MD_StringMatchFlags flags); MD_FUNCTION MD_u64 MD_FindSubstring(MD_String8 str, MD_String8 substring, MD_u64 start_pos, MD_StringMatchFlags flags); MD_FUNCTION MD_u64 MD_FindLastSubstring(MD_String8 str, MD_String8 substring, MD_StringMatchFlags flags); MD_FUNCTION MD_String8 MD_TrimExtension(MD_String8 string); MD_FUNCTION MD_String8 MD_TrimFolder(MD_String8 string); MD_FUNCTION MD_String8 MD_ExtensionFromPath(MD_String8 string); MD_FUNCTION MD_String8 MD_FolderFromPath(MD_String8 string); MD_FUNCTION MD_String8 MD_PushStringCopy(MD_String8 string); MD_FUNCTION MD_String8 MD_PushStringFV(char *fmt, va_list args); MD_FUNCTION MD_String8 MD_PushStringF(char *fmt, ...); #define MD_StringExpand(s) (int)(s).size, (s).str MD_FUNCTION void MD_PushStringToList(MD_String8List *list, MD_String8 string); MD_FUNCTION void MD_PushStringListToList(MD_String8List *list, MD_String8List *to_push); // TODO(rjf): Just simplify to a single splitter MD_FUNCTION MD_String8List MD_SplitString(MD_String8 string, int split_count, MD_String8 *splits); MD_FUNCTION MD_String8List MD_SplitStringByString(MD_String8 string, MD_String8 split); MD_FUNCTION MD_String8List MD_SplitStringByCharacter(MD_String8 string, MD_u8 character); MD_FUNCTION MD_String8 MD_JoinStringList(MD_String8List list); MD_FUNCTION MD_String8 MD_JoinStringListWithSeparator(MD_String8List list, MD_String8 separator); // TODO(rjf): Radix MD_FUNCTION MD_i64 MD_I64FromString(MD_String8 string); MD_FUNCTION MD_f64 MD_F64FromString(MD_String8 string); MD_FUNCTION MD_u64 MD_HashString(MD_String8 string); MD_FUNCTION MD_u64 MD_CalculateCStringLength(char *cstr); MD_FUNCTION MD_String8 MD_StyledStringFromString(MD_String8 string, MD_WordStyle word_style, MD_String8 separator); //~ Enum/Flag Strings MD_FUNCTION MD_String8 MD_StringFromNodeKind(MD_NodeKind kind); MD_FUNCTION MD_String8List MD_StringListFromNodeFlags(MD_NodeFlags flags); //~ Unicode Conversions MD_FUNCTION MD_UnicodeConsume MD_CodepointFromUtf8(MD_u8 *str, MD_u64 max); MD_FUNCTION MD_UnicodeConsume MD_CodepointFromUtf16(MD_u16 *str, MD_u64 max); MD_FUNCTION MD_u32 MD_Utf8FromCodepoint(MD_u8 *out, MD_u32 codepoint); MD_FUNCTION MD_u32 MD_Utf16FromCodepoint(MD_u16 *out, MD_u32 codepoint); MD_FUNCTION MD_String8 MD_S8FromS16(MD_String16 str); 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-Node-List Table MD_FUNCTION MD_NodeTableSlot *MD_NodeTable_Lookup(MD_NodeTable *table, MD_String8 string); MD_FUNCTION MD_b32 MD_NodeTable_Insert(MD_NodeTable *table, MD_NodeTableCollisionRule collision_rule, MD_String8 string, MD_Node *node); //~ Parsing MD_FUNCTION MD_Token MD_ZeroToken(void); 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 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); MD_FUNCTION MD_Token MD_Parse_PeekSkipSome(MD_ParseCtx *ctx, MD_TokenGroups skip_groups); MD_FUNCTION MD_b32 MD_Parse_TokenMatch(MD_Token token, MD_String8 string, MD_StringMatchFlags flags); MD_FUNCTION MD_b32 MD_Parse_Require(MD_ParseCtx *ctx, MD_String8 string); MD_FUNCTION MD_b32 MD_Parse_RequireKind(MD_ParseCtx *ctx, MD_TokenKind kind, MD_Token *out_token); MD_FUNCTION MD_ParseResult MD_ParseOneNode (MD_String8 filename, MD_String8 contents); MD_FUNCTION MD_Node * MD_ParseWholeString (MD_String8 filename, MD_String8 contents); MD_FUNCTION MD_Node * MD_ParseWholeFile (MD_String8 filename); //~ Tree/List Building MD_FUNCTION MD_b32 MD_NodeIsNil(MD_Node *node); MD_FUNCTION MD_Node *MD_NilNode(void); MD_FUNCTION MD_Node *MD_MakeNodeFromToken(MD_NodeKind kind, MD_String8 filename, MD_u8 *file, MD_u8 *at, MD_Token token); MD_FUNCTION MD_Node *MD_MakeNodeFromString(MD_NodeKind kind, MD_String8 filename, MD_u8 *file, MD_u8 *at, MD_String8 string); MD_FUNCTION void MD_PushSibling(MD_Node **first, MD_Node **last, MD_Node *parent, MD_Node *new_sibling); MD_FUNCTION void MD_PushChild(MD_Node *parent, MD_Node *new_child); MD_FUNCTION void MD_PushTag(MD_Node *node, MD_Node *tag); //~ Introspection Helpers MD_FUNCTION MD_Node * MD_NodeFromString(MD_Node *first, MD_Node *last, MD_String8 string); MD_FUNCTION MD_Node * MD_NodeFromIndex(MD_Node *first, MD_Node *last, int n); MD_FUNCTION int MD_IndexFromNode(MD_Node *node); MD_FUNCTION MD_Node * MD_NextNodeSibling(MD_Node *last, MD_String8 string); MD_FUNCTION MD_Node * MD_ChildFromString(MD_Node *node, MD_String8 child_string); MD_FUNCTION MD_Node * MD_TagFromString(MD_Node *node, MD_String8 tag_string); MD_FUNCTION MD_Node * MD_ChildFromIndex(MD_Node *node, int n); MD_FUNCTION MD_Node * MD_TagFromIndex(MD_Node *node, int n); MD_FUNCTION MD_Node * MD_TagArgFromIndex(MD_Node *node, MD_String8 tag_string, int n); MD_FUNCTION MD_b32 MD_NodeHasTag(MD_Node *node, MD_String8 tag_string); MD_FUNCTION MD_CodeLoc MD_CodeLocFromNode(MD_Node *node); MD_FUNCTION MD_i64 MD_ChildCountFromNode(MD_Node *node); MD_FUNCTION MD_i64 MD_TagCountFromNode(MD_Node *node); MD_FUNCTION MD_i64 MD_ChildCountFromNodeAndString(MD_Node *node, MD_String8 string, MD_StringMatchFlags flags); MD_FUNCTION MD_i64 MD_TagCountFromNodeAndString(MD_Node *node, MD_String8 string, MD_StringMatchFlags flags); // NOTE(rjf): For-Loop Helper #define MD_EachNode(it, first) MD_Node *it = (first); !MD_NodeIsNil(it); it = it->next //~ Error/Warning Helpers MD_FUNCTION void MD_NodeMessage(MD_Node *node, MD_MessageKind kind, MD_String8 str); MD_FUNCTION void MD_NodeError(MD_Node *node, MD_String8 str); MD_FUNCTION void MD_NodeWarning(MD_Node *node, MD_String8 str); MD_FUNCTION void MD_NodeMessageF(MD_Node *node, MD_MessageKind kind, char *fmt, ...); MD_FUNCTION void MD_NodeErrorF(MD_Node *node, char *fmt, ...); MD_FUNCTION void MD_NodeWarningF(MD_Node *node, char *fmt, ...); //~ Tree Comparison/Verification MD_FUNCTION MD_b32 MD_NodeMatch(MD_Node *a, MD_Node *b, MD_StringMatchFlags str_flags, MD_NodeMatchFlags node_flags); MD_FUNCTION MD_b32 MD_NodeDeepMatch(MD_Node *a, MD_Node *b, MD_StringMatchFlags str_flags, MD_NodeMatchFlags node_flags); //~ Expression and Type-Expression Helper MD_FUNCTION MD_Expr * MD_NilExpr(void); MD_FUNCTION MD_b32 MD_ExprIsNil(MD_Expr *expr); MD_FUNCTION MD_ExprKind MD_PreUnaryExprKindFromNode(MD_Node *node); MD_FUNCTION MD_ExprKind MD_BinaryExprKindFromNode(MD_Node *node); MD_FUNCTION MD_ExprPrec MD_ExprPrecFromExprKind(MD_ExprKind kind); MD_FUNCTION MD_Expr * MD_MakeExpr(MD_Node *node, MD_ExprKind kind, MD_Expr *left, MD_Expr *right); MD_FUNCTION MD_Expr * MD_ParseAsExpr(MD_Node *first, MD_Node *last); MD_FUNCTION MD_Expr * MD_ParseAsType(MD_Node *first, MD_Node *last); MD_FUNCTION MD_i64 MD_EvaluateExpr_I64(MD_Expr *expr); MD_FUNCTION MD_f64 MD_EvaluateExpr_F64(MD_Expr *expr); MD_FUNCTION MD_b32 MD_ExprMatch(MD_Expr *a, MD_Expr *b, MD_StringMatchFlags str_flags); MD_FUNCTION MD_b32 MD_ExprDeepMatch(MD_Expr *a, MD_Expr *b, MD_StringMatchFlags str_flags); //~ Generation MD_FUNCTION void MD_OutputTree(FILE *file, MD_Node *node); MD_FUNCTION void MD_OutputExpr(FILE *file, MD_Expr *expr); MD_FUNCTION void MD_OutputTree_C_String(FILE *file, MD_Node *node); MD_FUNCTION void MD_OutputTree_C_Struct(FILE *file, MD_Node *node); MD_FUNCTION void MD_OutputTree_C_Decl(FILE *file, MD_Node *node); MD_FUNCTION void MD_Output_C_DeclByNameAndType(FILE *file, MD_String8 name, MD_Expr *type); MD_FUNCTION void MD_OutputType_C_LHS(FILE *file, MD_Expr *type); MD_FUNCTION void MD_OutputType_C_RHS(FILE *file, MD_Expr *type); //~ Command Line Argument Helper MD_FUNCTION MD_CommandLine MD_CommandLine_Start(int argument_count, char **arguments); MD_FUNCTION MD_b32 MD_CommandLine_Flag(MD_CommandLine *cmdln, MD_String8 string); MD_FUNCTION MD_b32 MD_CommandLine_FlagStrings(MD_CommandLine *cmdln, MD_String8 string, int out_count, MD_String8 *out); MD_FUNCTION MD_b32 MD_CommandLine_FlagIntegers(MD_CommandLine *cmdln, MD_String8 string, int out_count, MD_i64 *out); MD_FUNCTION MD_b32 MD_CommandLine_FlagString(MD_CommandLine *cmdln, MD_String8 string, MD_String8 *out); MD_FUNCTION MD_b32 MD_CommandLine_FlagInteger(MD_CommandLine *cmdln, MD_String8 string, MD_i64 *out); MD_FUNCTION MD_b32 MD_CommandLine_Increment(MD_CommandLine *cmdln, MD_String8 **string_ptr); //~ File System MD_FUNCTION MD_String8 MD_LoadEntireFile(MD_String8 filename); MD_FUNCTION MD_b32 MD_FileIterIncrement(MD_FileIter *it, MD_String8 path, MD_FileInfo *out_info); #endif // MD_H