Specified before all Metadesk library functions. Expands to nothing by default. Can be overridden in usage code by using #define MD_FUNCTION ... (where ... is whatever you want to be in front of all functions).
#define MD_FUNCTION ...
Specified before all Metadesk library global variables. Expands to static by default. Can be overridden in usage code by using #define MD_GLOBAL ... (where ... is whatever you want to be in front of all global variable declarations).
#define MD_GLOBAL ...
Will cause a crash when c is false.
#define MD_Assert(c) ...
Will cause a compilation failure when c is false.
#define MD_StaticAssert(c, label) ...
A label for this static assertion. Necessary for static asserts in C.
Treats a as a static array to calculate the number of elements in the array. Does not work on pointers used to point at a number of elements.
#define MD_ArrayCount(a) ...
Expands to an expression returning the lesser of a and b. Expands both arguments multiple times, so avoiding complex expressions for a and b is recommended.
#define MD_Min(a, b) ...
Expands to an expression returning the higher of a and b. Expands both arguments multiple times, so avoiding complex expressions for a and b is recommended.
#define MD_Max(a, b) ...
Equivalent to MD_Max.
#define MD_ClampBot(a, b) ...
Equivalent to MD_Min.
#define MD_ClampTop(a, b) ...
Expands to an expression returning a multiple of b that is nearest to x, while still being larger.
#define MD_AlignPow2(x, b) ...
Returns true if p is a null pointer. Used as a helper in other linked list macros.
#define MD_CheckNull(p) ...
Sets p to a null pointer. Used as a helper in other linked list macros.
#define MD_SetNull(p) ...
Returns true if p is a nil MD_Node pointer. Used as a helper in other linked list macros.
#define MD_CheckNil(p) ...
Sets p to a nil MD_Node pointer. Used as a helper in other linked list macros.
#define MD_SetNil(p) ...
Expands to an expression that pushes n into a singly-linked-list queue, with f being a pointer to the first element in the queue, and l being a pointer to the last element in the queue. Allows for overrides on both what is considered the zero-value, as well as what the name of the next pointer inside of the associated type is.
#define MD_QueuePush_NZ(f, l, n, next, zchk, zset) ...
A pointer to the first element of the queue. When the queue is empty, this should be equivalent to a zero-value compatible with the zchk and zset arguments.
A pointer to the last element of the queue. When the queue is empty, this should be equivalent to a zero-value compatible with the zchk and zset arguments.
A pointer to the element that is to be added to the end of the queue.
The name of the next pointer member within the type used for the queue.
The name of a macro that accepts one argument, and returns whether it is considered the zero-value.
The name of a macro that accepts one argument, and assigns the zero-value to it.
Expands to an expression that pops the first element out of the queue, with f being a pointer to the first element in the queue, and l being a pointer to the last element in the queue. Allows for overrides on both what is considered the zero-value, as well as what the name of the next pointer inside of the associated type is.
#define MD_QueuePop_NZ(f, l, next, zset) ...
A pointer to the first element of the queue. When the queue is empty, this should be equivalent to a zero-value compatible with the zchk and zset arguments.
A pointer to the last element of the queue. When the queue is empty, this should be equivalent to a zero-value compatible with the zchk and zset arguments.
The name of the next pointer member within the type used for the queue.
The name of a macro that accepts one argument, and assigns the zero-value to it.
Expands to an expression that pushes a new element onto the top of a singly-linked stack, with f being a pointer to the top of the stack. Allows overriding the name of the pointer member inside of the type used for the stack, which is used to point at the next node in the chain.
#define MD_StackPush_N(f, n, next) ...
A pointer to the first element of the stack. When the stack is empty, this should be 0.
A pointer to the new element to be added to the stack.
The name of the next pointer member within the type used for the stack.
Expands to an expression that pops the top of a singly-linked stack. Does not return the popped element, which should be grabbed before using this macro. Allows overriding both the name of the pointer member inside of the type used for the stack's links, and how the zero-value is checked.
#define MD_StackPop_NZ(f, next, zchk) ...
A pointer to the first element of the stack. When the stack is empty, this should be 0.
The name of the next pointer member within the type used for the stack.
The name of a macro that accepts one argument, and returns whether it is considered the zero-value.
Expands to an expression that pushes a new element to the back of a doubly-linked-list, with f being a pointer to the first element in the linked list, l being a pointer to the last element in the linked list, and n being the new element to add. Allows overriding the names of the pointer members used to store the next and previous links of a node, and the way that the zero-value is both checked for and set.
#define MD_DblPushBack_NPZ(f, l, n, next, prev, zchk, zset) ...
A pointer to the first element of the list. When the list is empty, this should be the zero-value compatible with the zchk and zset arguments.
A pointer to the last element of the list. When the list is empty, this should be the zero-value compatible with the zchk and zset arguments.
A pointer to the new element of the list to be added.
The name of the pointer member in the list's type to consider as encoding the next node in the list.
The name of the pointer member in the list's type to consider as encoding the previous node in the list.
The name of a macro that accepts one argument, and returns whether it is considered the zero-value.
The name of a macro that accepts one argument, and assigns the zero-value to it.
Expands to an expression that removes an element from a doubly-linked-list, with f being a pointer to the first element in the linked list, l being a pointer to the last element in the linked list, and n being the node to be removed. Allows overriding the names of the pointer members used to store the next and previous links of a node, and the way that the zero-value is both checked for and set.
#define MD_DblRemove_NPZ(f, l, n, next, prev, zset) ...
A pointer to the first element of the list. When the list is empty, this should be the zero-value compatible with the zchk and zset arguments.
A pointer to the last element of the list. When the list is empty, this should be the zero-value compatible with the zchk and zset arguments.
A pointer to the new element of the list to be removed.
The name of the pointer member in the list's type to consider as encoding the next node in the list.
The name of the pointer member in the list's type to consider as encoding the previous node in the list.
The name of a macro that accepts one argument, and assigns the zero-value to it.
Expands to an expression that pushes a node n to the back of a singly-linked-list queue defined by f, a pointer to the first element in the list, and l, a pointer to the last element in the list. Null pointers are used to delimit the end of the list, and to encode that the list is empty. Expects that there exists a next member inside of the type of f, l, and n, which encodes the link to the next node.
#define MD_QueuePush(f, l, n) ...
Expands to an expression that pops a node n from the front of a singly-linked-list queue defined by f, a pointer to the first element in the list, and l, a pointer to the last element in the list. Null pointers are used to delimit the end of the list, and to encode that the list is empty. Expects that there exists a next member inside of the type of f, l, and n, which encodes the link to the next node.
#define MD_QueuePop(f, l) ...
Expands to an expression that pushes a node n to the top of a singly-linked-list stack defined by f, a pointer to the top element of the stack. Null pointers are used to delimit the end of the stack, and an empty stack. Expects that there exists a next member inside of the type of f and n, which encodes the link to the next node.
#define MD_StackPush(f, n) ...
Expands to an expression that pops a node n off the top of a singly-linked-list stack defined by f, a pointer to the top element of the stack. Null pointers are used to delimit the end of the stack, and an empty stack. Expects that there exists a next member inside of the type of f, which encodes the link to the next node in the stack.
#define MD_StackPop(f) ...
Expands to an expression that pushes a node n to the back of a doubly-linked-list defined by f, a pointer to the first element in the list, and l, a pointer to the last element in the list. Null pointers are used to delimit the end of the list, and to encode that the list is empty. Expects that there exists a next member inside of the type of f, l, and n, which encodes the link to the next node. Expects that there also exists a prev member inside of the type of f, l, and n, which encodes the link to the previous node.
#define MD_DblPushBack(f, l, n) ...
Expands to an expression that pushes a node n to the front of a doubly-linked-list defined by f, a pointer to the first element in the list, and l, a pointer to the last element in the list. Null pointers are used to delimit the end of the list, and to encode that the list is empty. Expects that there exists a next member inside of the type of f, l, and n, which encodes the link to the next node. Expects that there also exists a prev member inside of the type of f, l, and n, which encodes the link to the previous node.
#define MD_DblPushFront(f, l, n) ...
Expands to an expression that removes a node n from a doubly-linked-list defined by f, a pointer to the first element in the list, and l, a pointer to the last element in the list. Null pointers are used to delimit the end of the list, and to encode that the list is empty. Expects that there exists a next member inside of the type of f, l, and n, which encodes the link to the next node. Expects that there also exists a prev member inside of the type of f, l, and n, which encodes the link to the previous node.
#define MD_DblRemove(f, l, n) ...
Expands to an expression that pushes an MD_Node n to the back of a doubly-linked-list defined by f, a pointer to the first element in the list, and l, a pointer to the last element in the list. Nil pointers, identical to those returned by MD_NilNode, are used to delimit the end of the list, and to encode that the list is empty.
#define MD_NodeDblPushBack(f, l, n) ...
Expands to an expression that pushes an MD_Node n to the front of a doubly-linked-list defined by f, a pointer to the first element in the list, and l, a pointer to the last element in the list. Nil pointers, identical to those returned by MD_NilNode, are used to delimit the end of the list, and to encode that the list is empty.
#define MD_NodeDblPushFront(f, l, n) ...
Expands to an expression that removes an MD_Node n from a doubly-linked-list defined by f, a pointer to the first element in the list, and l, a pointer to the last element in the list. Nil pointers, identical to those returned by MD_NilNode, are used to delimit the end of the list, and to encode that the list is empty.
#define MD_NodeDblRemove(f, l, n) ...
A macro that expands to an overrideable memset equivalent call that sets size bytes at the address stored in memory to byte_value.
#define MD_MemorySet(memory, byte_value, size) ...
A macro that expands to an overrideable memset equivalent call that zeroes size bytes at the address stored in memory.
#define MD_MemoryZero(memory, size) ...
A macro that expands to an overrideable memset equivalent call that zeroes sizeof(*(struct_pointer)) bytes at the address stored in struct_pointer.
#define MD_MemoryZeroStruct(struct_pointer) ...
A macro that expands to an overrideable memmove equivalent call that copies size bytes from source to destination. The ranges defined by the pointers and size may overlap.
#define MD_MemoryCopy(destination, source, size) ...
Returns whether an ASCII character is alphabetic.
MD_b32 MD_CharIsAlpha(MD_u8 c);
Returns whether an ASCII character is alphabetic and upper-case.
MD_b32 MD_CharIsAlphaUpper(MD_u8 c);
Returns whether an ASCII character is alphabetic and lower-case.
MD_b32 MD_CharIsAlphaLower(MD_u8 c);
Returns whether an ASCII character is numeric.
MD_b32 MD_CharIsDigit(MD_u8 c);
Returns whether an ASCII character is a non-reserved symbol as defined by the Metadesk grammar: ~, !, $, %, ^, &, *, -, =, +, <, ., >, /, ?, or |.
MD_b32 MD_CharIsUnreservedSymbol(MD_u8 c);
Returns whether an ASCII character is a reserved symbol as defined by the Metadesk grammar: {, }, (, ), \\, [, ], #, ,, ;, :, or @.
MD_b32 MD_CharIsReservedSymbol(MD_u8 c);
Return whether an ASCII character is whitespace.
MD_b32 MD_CharIsSpace(MD_u8 c);
Return the alphabetic uppercase equivalent of an ASCII character, or just returns the passed-in character if it is not alphabetic.
MD_u8 MD_CharToUpper(MD_u8 c);
Return the alphabetic lowercase equivalent of an ASCII character, or just returns the passed-in character if it is not alphabetic.
MD_u8 MD_CharToLower(MD_u8 c);
Return a / if \\ is passed in, otherwise just returns the passed character.
MD_u8 MD_CharToForwardSlash(MD_u8 c);
This type is used as the fundamental string type in Metadesk, and as the type for byte granularity data blobs. Strings of this type are encoded in UTF-8.
struct MD_String8 { MD_u8* str; MD_u64 size; };
This type represents a string encoded in UTF-16.
struct MD_String16 { MD_u16* str; MD_u64 size; };
This type represents a string encoded in UTF-32.
struct MD_String32 { MD_u32* str; MD_u64 size; };
MD_String8Node forms one node in a linked list of strings. Generally used as a part of an MD_String8List data structure.
struct MD_String8Node { MD_String8Node* next; MD_String8 string; };
The next node in the list, or null if this is the last node.
The string value stored at this node.
This type is implemented as a singly linked list with an MD_String8 at each node.
struct MD_String8List { MD_u64 node_count; MD_u64 total_size; MD_String8Node* first; MD_String8Node* last; };
The number of nodes in the list.
The size of all strings in the list summed together.
A pointer to the first node in the list.
A pointer to the last node in the list.
MD_S8ListPush, MD_S8Split, MD_S8ListJoin
A sample loop over MD_String8List:
MD_String8List list;
for(MD_String8Node *node = list.first; node != 0; node = node->next)
{
MD_String8 string = node->string;
// ... work on string ...
}
The node_count and total_size are automatically maintained by the helpers for inserting to the list, and are used in the string joining functions. Hand rolled code for building string lists should take those fields into consideration if the join functions need to work.
Used as optional parameters for MD_S8ListJoin.
struct MD_StringJoin { MD_String8 pre; MD_String8 mid; MD_String8 post; };
The string to insert before the joined strings in the list.
The string to insert between each node in the string list.
The string to insert after the joined strings in the list.
MD_S8ListJoin, MD_String8List, MD_String8
These flags control matching rules in routines that perform matching on strings and MD_Node trees. Not all flags are within this enum. These flags must not be overlapping with those in the MD_StringMatchFlags enum, nor those in the MD_NodeMatchFlags enum. This allows all flags to be associated with their respective behaviors, but also be combined when appropriate.
typedef MD_u32 MD_MatchFlags; enum { MD_MatchFlag_FindLast = 1<<0, };
For routines returning the location of a substring, alters the behavior to return the last match instead of the first match.
MD_Node, MD_String8, MD_S8Match, MD_NodeMatch, MD_NodeDeepMatch, MD_StringMatchFlags, MD_NodeMatchFlags
These flags control matching rules in routines that perform matching on strings. These flags must not be overlapping with those in the MD_MatchFlags enum, nor those in the MD_NodeMatchFlags enum. This allows all flags to be associated with their respective behaviors, but also be combined when appropriate.
typedef MD_u32 MD_StringMatchFlags; enum { MD_StringMatchFlag_CaseInsensitive = 1<<4, MD_StringMatchFlag_RightSideSloppy = 1<<5, MD_StringMatchFlag_SlashInsensitive = 1<<6, };
When comparing strings, consider lower case letters equivalent to upper case equivalents in the ASCII range.
When comparing strings, do not require the strings to be the same length. If one of the strings is a prefix of another, the two strings will count as a match.
When comparing strings, consider forward slash and backward slash to be equivalents.
MD_Node, MD_String8, MD_S8Match, MD_NodeMatch, MD_NodeDeepMatch, MD_MatchFlags, MD_NodeMatchFlags
These flags control matching rules in routines that perform matching on MD_Node trees. These flags must not be overlapping with those in the MD_MatchFlags enum, nor those in the MD_StringMatchFlags enum. This allows all flags to be associated with their respective behaviors, but also be combined when appropriate.
typedef MD_u32 MD_NodeMatchFlags; enum { MD_NodeMatchFlag_Tags = 1<<16, MD_NodeMatchFlag_TagArguments = 1<<17, };
When comparing nodes with this flag set, differences in the order and names of tags on a node count as differences in the input nodes. Without this flag tags are ignored in tree comparisons.
When comparing nodes with this flag set in addition to MD_NodeMatchFlag_Tags, the differences in the arguments of each tag (the tag's children in the tree) count as differences in the input nodes. Tag arguments are compared with fully recursive compares, whether or not the compare routine would be recursive or not.
MD_Node, MD_String8, MD_S8Match, MD_NodeMatch, MD_NodeDeepMatch, MD_StringMatchFlags, MD_MatchFlags
This type is used to report the results of consuming one character from a unicode encoded stream.
struct MD_DecodedCodepoint { MD_u32 codepoint; MD_u32 advance; };
The codepoint of the consumed character.
The size of the character in the encoded stream, measured in 'units'. A unit is one byte in UTF-8, two bytes in UTF-16, and four bytes in UTF-32.
MD_DecodeCodepointFromUtf8, MD_DecodeCodepointFromUtf16
These constants control how MD_S8Stylize forms strings.
enum MD_IdentifierStyle { MD_IdentifierStyle_UpperCamelCase, MD_IdentifierStyle_LowerCamelCase, MD_IdentifierStyle_UpperCase, MD_IdentifierStyle_LowerCase, };
Creates identifiers where each word begins with an upper-case letter, with each subsequent letter in the word being lower-case. With no word separators, creates identifiers that look like ExampleIdentifier.
Creates identifiers where each word begins with an upper-case letter, except the first word (which begins with a lower-case letter), with each subsequent letter in the word being lower-case. With no word separators, creates identifiers that look like exampleIdentifier.
All letters in all words are upper-case.
All letters in all words are lower-case.
Calculates the number of bytes in a C-string by checking for a null-terminator.
MD_u64 MD_CalculateCStringLength(char* cstr);
Constructs an MD_String8.
MD_String8 MD_S8(MD_u8* str, MD_u64 size);
The base pointer of the returned MD_String8.
The size of the returned MD_String8.
Constructs an MD_String8 from a C-string by calling MD_CalculateCStringLength.
#define MD_S8CString(s) ...
Constructs an MD_String8 from a C-string literal by using sizeof. In C++, the equivalent can be done with the user-defined literal code provided in the library, which uses _md as a suffix on a string literal.
#define MD_S8Lit(s) ...
Constructs an MD_String8 from a C-string literal by using sizeof. Differs from MD_S8Lit in that it does not expand with (MD_String8) before the brace initializer, allowing it to be used in C for static initializations.
#define MD_S8LitComp(s) ...
Constructs an MD_String8 from two pointers into the same buffer, corresponding to the beginning and one past the last byte of a string.
MD_String8 MD_S8Range(MD_u8* first, MD_u8* opl);
Returns an MD_String8 encoding a sub-range of the passed MD_String8.
MD_String8 MD_S8Substring(MD_String8 str, MD_u64 min, MD_u64 max);
The string for which the substring is returned.
The offset, from the passed string's base, of the first character of the returned substring.
The offset, from the passed string's base, of one byte past the last character of the returned substring.
Returns a sub-range of the passed MD_String8, skipping the first min bytes.
MD_String8 MD_S8Skip(MD_String8 str, MD_u64 min);
The string for which the substring is returned.
The new minimum offset, relative to the base of str. Also the number of bytes to skip at the beginning of str.
Returns a sub-range of the passed MD_String8, chopping off the last nmax bytes.
MD_String8 MD_S8Chop(MD_String8 str, MD_u64 nmax);
The string for which the substring is returned.
The number of bytes to chop off at the end of str.
Returns a prefix of the passed MD_String8.
MD_String8 MD_S8Prefix(MD_String8 str, MD_u64 size);
The string for which the substring is returned.
The desired size of the returned prefix.
Returns a suffix of the passed MD_String8.
MD_String8 MD_S8Suffix(MD_String8 str, MD_u64 size);
The string for which the substring is returned.
The desired size of the returned suffix.
Compares the passed strings a and b, and determines whether or not the two strings match. The passed MD_MatchFlags argument will modify the string matching algorithm; for example, allowing case insensitivity. Return 1 if the strings are found to match, and 0 otherwise.
MD_b32 MD_S8Match(MD_String8 a, MD_String8 b, MD_MatchFlags flags);
The first string to compare.
The second string to compare.
Controls for the string matching algorithm.
1 if the strings match, or 0 otherwise.
Searches str for an occurrence of substring. The passed flags can be used to modify the matching rules. Returns the position at which the search ended; if the return value is equivalent to str.size, then the substring was not found.
MD_u64 MD_S8FindSubstring(MD_String8 str, MD_String8 substring, MD_u64 start_pos, MD_MatchFlags flags);
The string to search within for the substring.
The 'needle' string to find within str.
The first position, in bytes relative to the base of str, to conduct the search from.
Controls for the string matching algorithm.
The last position at which the substring was searched for. Will be equal to str.size if the substring was not found. If it is less than that, the substring was found at the returned offset.
Copies string by allocating an entirely new portion of memory and copying the passed string's memory to the newly allocated memory. Returns the copy of string using the new memory.
MD_String8 MD_S8Copy(MD_Arena* arena, MD_String8 string);
Allocates a new string, with the contents of the string being determined by a mostly-standard C formatting string passed in fmt, with a variable-argument list being passed in args. Used when composing variable argument lists at multiple levels, and when you need to pass a va_list. The format string is non-standard because it allows %S as a specifier for MD_String8 arguments. Before this call, it is expected that you call va_start on the passed va_list, and also that you call va_end after the function returns. If you just want to pass variable arguments yourself (instead of a va_list), then see MD_S8Fmt.
MD_String8 MD_S8FmtV(MD_Arena* arena, char* fmt, va_list args);
Allocates a new string, with the contents of the string being determined by a mostly-standard C formatting string passed in fmt, with variable arguments fitting the expected ones in fmt being passed in after. The format string is non-standard because it allows %S as a specifier for MD_String8 arguments. If you are composing this with your own variable-arguments call, use MD_S8FmtV instead.
MD_String8 MD_S8Fmt(MD_Arena* arena, char* fmt, ...);
This is a helper macro that is normally used with passing an MD_String8 into a printf like function, usually used in combination with the %.*s format specifier. Metadesk uses length-based strings, not null-terminated (like many C functions expect), so this is often convenient when interacting with C-like APIs. This will expand to passing the size of the passed string first, a comma, and the pointer to the base of the string being passed immediately after.
#define MD_S8VArg(s) ...
Pushes a new MD_String8 to an MD_String8List by allocating a new MD_String8Node, filling it with string, and modifying the existing list elements in list to end with the newly allocated node.
void MD_S8ListPush(MD_Arena* arena, MD_String8List* list, MD_String8 string);
MD_String8List, MD_String8Node, MD_String8
Pushes a new MD_String8 to an MD_String8List by allocating a new MD_String8Node, filling it with a C-style format string defined by fmt and the variadic arguments following it, and modifying the existing list elements in list to end with the newly allocated node.
void MD_S8ListPushFmt(MD_Arena* arena, MD_String8List* list, char* fmt, ...);
MD_String8List, MD_String8Node, MD_String8
Pushes an MD_String8List to another MD_String8List. This will zero all memory in to_push, so you cannot expect to_push to retain any of the list elements it had before this call. This is because no strings nor nodes are copied, so the nodes in to_push are repurposed for being a part of list.
void MD_S8ListConcat(MD_String8List* list, MD_String8List* to_push);
MD_String8List, MD_String8Node, MD_String8, MD_S8ListPush
Divides string into an MD_String8List, each node of which corresponds to a substring of string that was separated by an occurrence of one of the 'splitter's passed in splits.
MD_String8List MD_S8Split(MD_Arena* arena, MD_String8 string, MD_u32 split_count, MD_String8* splits);
The arena to use for allocation.
The string to search for splitting strings, and to subdivide.
The number of splitting strings to search for.
A pointer to an array of strings stored as MD_String8 objects, each corresponding to a string pattern that should split string.
A list containing all of the strings separated by the passed splitter strings. None of the strings will contain the splitter strings themselves.
MD_String8, MD_String8List, MD_String8Node, MD_S8ListJoin
Returns a new MD_String8 that contains the contents of each string in list, in order, with the separator string inserted between each string.
MD_String8 MD_S8ListJoin(MD_Arena* arena, MD_String8List list, MD_StringJoin* join);
The arena to use for allocation.
The list to join.
Optional join parameters.
MD_String8, MD_String8List, MD_String8Node, MD_S8Split
Provided an MD_String8 string in a traditional identifier style, attempts heuristically to return a transformed version of string to a new identifier style. Cannot be fully correct in all cases.
MD_String8 MD_S8Stylize(MD_Arena* arena, MD_String8 string, MD_IdentifierStyle style, MD_String8 separator);
The arena to use for allocation.
The string to attempt to transform.
The style that each word should have.
A string to separate each word in the returned string.
MD_DecodedCodepoint MD_DecodeCodepointFromUtf8(MD_u8 str, MD_u64 max);
MD_DecodedCodepoint MD_DecodeCodepointFromUtf16(MD_u16* str, MD_u64 max);
MD_u32 MD_Utf8FromCodepoint(MD_u8* out, MD_u32 codepoint);
MD_u32 MD_Utf16FromCodepoint(MD_u16* out, MD_u32 codepoint);
Converts a UTF-16 string, encoded into an MD_String16 object, into a UTF-8 string. Allocates the required storage for the UTF-8 string onto arena.
MD_String8 MD_S8FromS16(MD_Arena* arena, MD_String16 str);
The arena to use for memory allocation.
The UTF-16 string to convert.
Converts a UTF-8 string, encoded into an MD_String8 object, into a UTF-16 string. Allocates the required storage for the UTF-16 string onto arena.
MD_String16 MD_S16FromS8(MD_Arena* arena, MD_String8 str);
The arena to use for memory allocation.
The UTF-8 string to convert.
Converts a UTF-32 string, encoded into an MD_String32 object, into a UTF-8 string. Allocates the required storage for the UTF-8 string onto arena.
MD_String8 MD_S8FromS32(MD_Arena* arena, MD_String32 str);
The arena to use for memory allocation.
The UTF-32 string to convert.
Converts a UTF-8 string, encoded into an MD_String8 object, into a UTF-32 string. Allocates the required storage for the UTF-32 string onto arena.
MD_String32 MD_S32FromS8(MD_Arena* arena, MD_String8 str);
The arena to use for memory allocation.
The UTF-8 string to convert.
Searches string for the last . character occurring in the string, and chops the . and anything following after it off of the returned string.
MD_String8 MD_PathChopLastPeriod(MD_String8 string);
Searches string for the last / or \\ character occurring in the string, and skips it and anything before it in the returned string.
MD_String8 MD_PathSkipLastSlash(MD_String8 string);
Searches string for the last . character, and returns the substring starting at the character after it, to the end of the string. For usual file naming schemes where the extension of a file is encoded by any characters following the last . of a filename, this will return the extension.
MD_String8 MD_PathSkipLastPeriod(MD_String8 string);
MD_PathChopLastSlash, MD_S8Suffix, MD_S8Substring, MD_S8Chop
Searches string for the last / or \\ character, and returns the substring that ends with that character. For usual file naming schemes where folders are encoded with / or \\ characters, this will return the entire path to the passed filename, not including the filename itself.
MD_String8 MD_PathChopLastSlash(MD_String8 string);
MD_PathSkipLastPeriod, MD_S8Prefix, MD_S8Substring, MD_S8Skip
Returns the equivalent of string with all leading whitespace skipped.
MD_String8 MD_S8SkipWhitespace(MD_String8 string);
MD_S8Substring, MD_S8ChopWhitespace, MD_S8Skip, MD_S8Chop
Returns the equivalent of string with all trailing whitespace chopped.
MD_String8 MD_S8ChopWhitespace(MD_String8 string);
MD_S8Substring, MD_S8SkipWhitespace, MD_S8Skip, MD_S8Chop
Returns 1 if string appears to encode an integer value with a base of radix, or 0 otherwise.
MD_b32 MD_StringIsU64(MD_String8 string, MD_u32 radix);
Returns 1 if string appears to encode an integer value in C-style syntax, or 0 otherwise.
MD_b32 MD_StringIsCStyleInt(MD_String8 string);
Parses string as an integer with a base defined by radix. Returns the parsed value.
MD_u64 MD_U64FromString(MD_String8 string, MD_u32 radix);
Parses string as an integer with a base defined by C-like rules: If the numeric part of the string begins with 0x, then it will be parsed as base-16. If it begins with 0b, it will be parsed as base-2. Otherwise, it will be parsed as base 10. Returns the parsed value.
MD_i64 MD_CStyleIntFromString(MD_String8 string);
Parses string as a floating point number, and returns the parsed value.
MD_f64 MD_F64FromString(MD_String8 string);
Builds and returns a string on arena that is the textual representation of x.
MD_String8 MD_CStyleHexStringFromU64(MD_Arena* arena, MD_u64 x, MD_b32 caps);
Determines whether or not the alphabetic characters used in the hex textual representation are upper-case or lower-case.
The type used for the default arena allocator implementation. This type is used for MD_Arena if an override is not provided by usage code.
struct MD_ArenaDefault { MD_ArenaDefault* prev; MD_ArenaDefault* current; MD_u64 base_pos; MD_u64 pos; MD_u64 cmt; MD_u64 cap; MD_u64 align; };
The name defined to refer to a memory arena allocator handle. Equivalent to MD_IMPL_Arena, which can be overridden by a custom arena implementation. If an override is not specified, then this type is equivalent to MD_ArenaDefault.
struct MD_Arena { // opaque };
This type is used for temporary lifetimes where a portion of an arena is treated like a stack temporarily. This type stores the position at which stack-like allocation began, so that everything pushed onto the arena during this temporary lifetime can be freed all at once.
struct MD_ArenaTemp { MD_Arena* arena; MD_u64 pos; };
The arena that is being used for temporary allocation.
The position to which the arena should be restored when the associated temporary lifetime ends.
MD_Arena, MD_ArenaBeginTemp, MD_ArenaEndTemp, MD_GetScratch, MD_ReleaseScratch
Returns a newly allocated MD_Arena, which can be used as a bucket for memory allocation.
MD_Arena, MD_ArenaRelease, MD_ArenaClear, MD_PushArray, MD_ArenaTemp, MD_ArenaBeginTemp, MD_ArenaEndTemp
Releases an MD_Arena allocated originally with MD_ArenaAlloc.
void MD_ArenaRelease(MD_Arena* arena);
Allocates a block of memory on arena that is size bytes large.
void* MD_ArenaPush(MD_Arena* arena, MD_u64 size);
The arena from which the block of memory should be allocated.
The number of bytes to allocate.
A pointer to the beginning of the allocated block, or 0 on failure.
Pops size bytes off of arena, freeing that space for more allocations.
void MD_ArenaPutBack(MD_Arena* arena, MD_u64 size);
The arena to pop bytes from.
The number of bytes to pop.
Sets the auto-alignment value for arena. Calls to MD_ArenaPush will automatically align to this value.
void MD_ArenaSetAlign(MD_Arena* arena, MD_u64 boundary);
The arena to set alignment for.
The number of bytes to which allocations should align.
Pushes the required number of bytes onto arena in order to guarantee that the following call to MD_ArenaPush returns an allocation that is aligned to boundary bytes.
void MD_ArenaPushAlign(MD_Arena* arena, MD_u64 boundary);
The arena to use.
The number of bytes to which the arena's next allocation should align.
MD_Arena, MD_ArenaAlloc, MD_ArenaPush
Pops all bytes off of arena, freeing that space for more allocations. Does not deallocate the arena entirely (for that, use MD_ArenaRelease); this function is to be used when more allocations are expected on the same arena, but all of the present allocations are no longer needed.
void MD_ArenaClear(MD_Arena* arena);
The arena to clear.
MD_Arena, MD_ArenaPutBack, MD_ArenaRelease
A helper macro for easily allocating blocks of memory for c instances of type T onto arena a.
#define MD_PushArray(a, T, c) ...
The arena to use for allocation.
The type that should be allocated.
The number of instances of T to allocate.
MD_Arena, MD_ArenaAlloc, MD_ArenaPush
A helper macro for easily allocating blocks of memory for c instances of type T onto arena a, with the returned block of memory being guaranteed to be zero-initialized.
#define MD_PushArrayZero(a, T, c) ...
The arena to use for allocation.
The type that should be allocated.
The number of instances of T to allocate.
MD_Arena, MD_ArenaAlloc, MD_ArenaPush, MD_MemoryZero
Initializes an MD_ArenaTemp instance for arena which can be used for temporary memory allocations. MD_ArenaEndTemp should be called once with the return value of this function, to avoid leaving temporary allocations as being allocated within the memory belonging to arena. This function, along with MD_ArenaEndTemp, can be useful for using an arena like a stack.
MD_ArenaTemp MD_ArenaBeginTemp(MD_Arena* arena);
MD_Arena, MD_ArenaTemp, MD_ArenaEndTemp, MD_ArenaPush, MD_ArenaPutBack
Pops all bytes allocated onto the arena stored in temp, after temp was constructed with MD_ArenaBeginTemp.
void MD_ArenaEndTemp(MD_ArenaTemp temp);
MD_Arena, MD_ArenaTemp, MD_ArenaBeginTemp, MD_ArenaPush, MD_ArenaPutBack
Retrieves an arena for temporary stack-like scratch memory allocation from a thread-local set of arenas.
MD_ArenaTemp MD_GetScratch(MD_Arena** conflicts, MD_u64 count);
Scratch arenas already obtained from previous calls to MD_GetScratch—generally arenas that have been passed into a function that could be scratch arenas—that should not be returned. Most often used when a passed arena, which could be a scratch arena, is being used to push results onto, and one desires a separate channel for scratch allocation that is not required to be allocated onto the arena which is being used for results.
The number of MD_Arena pointers pointed to by conflicts.
MD_Arena, MD_ArenaTemp, MD_ReleaseScratch
Expands to MD_ArenaEndTemp. Equivalent in usage, just used as the symmetric counterpart for MD_GetScratch.
#define MD_ReleaseScratch(scratch) ...
MD_Arena, MD_ArenaTemp, MD_GetScratch, MD_ArenaEndTemp
Flags encoding the kind of a token produced by the lexer.
enum MD_TokenKind { MD_TokenKind_Identifier = (1<<0), MD_TokenKind_NumericLiteral = (1<<1), MD_TokenKind_StringLiteral = (1<<2), MD_TokenKind_Symbol = (1<<3), MD_TokenKind_Reserved = (1<<4), MD_TokenKind_Comment = (1<<5), MD_TokenKind_Whitespace = (1<<6), MD_TokenKind_Newline = (1<<7), MD_TokenKind_BrokenComment = (1<<8), MD_TokenKind_BrokenStringLiteral = (1<<9), MD_TokenKind_BadCharacter = (1<<10), };
When this bit is set, the token follows C-like identifier rules. It may start with an alphabetic character or an underscore, and can contain alphanumeric characters or underscores inside it.
When this bit is set, the token follows C-like numeric literal rules.
When this bit is set, the token was recognized as a string literal. These may be formed with C-like rules, with a single-quote or double-quote around the string contents. They may also be formed with Metadesk's additional rules. These rules allow using ` characters to mark the boundaries of the string, and also using triplets of any of these characters (```This is a string```) to allow newlines within the string's contents.
When this bit is set, the token was recognized as a symbolic character. Whether a character is considered symbolic is determined by the MD_CharIsSymbol function.
When this bit is set, the token is reserved for special uses by the Metadesk parser.
When this bit is set, the token was recognized as a comment. Comments can be formed in the traditional C-like ways, using // for single-line, or /* and */ for multiline. Metadesk differs, slightly, in that it allows nested multiline comments. So, every /* must be matched by a */.
When this bit is set, the token contains only whitespace.
When this bit is set, the token is a newline character.
When this bit is set, the token is a comment that was malformed syntactically.
When this bit is set, the token is a string literal that was malformed syntactically.
When this bit is set, the token contains a character in an encoding that is not supported by the parser Metadesk.
Used to group several MD_TokenKind flags; used in the parser.
enum MD_TokenGroups { MD_TokenGroup_Comment = MD_TokenKind_Comment, MD_TokenGroup_Whitespace = (MD_TokenKind_Whitespace|MD_TokenKind_Newline), MD_TokenGroup_Irregular = (MD_TokenGroup_Comment|MD_TokenGroup_Whitespace), MD_TokenGroup_Regular = ~MD_TokenGroup_Irregular, MD_TokenGroup_Label = (MD_TokenKind_Identifier|MD_TokenKind_Numeric|MD_TokenKind_StringLiteral|MD_TokenKind_Symbol), MD_TokenGroup_Error = (MD_TokenKind_BrokenComment|MD_TokenKind_BrokenStringLiteral|MD_TokenKind_BadCharacter), };
MD_TokenKind, MD_Token, MD_TokenFromString
The type used for encoding data about any token produced by the lexer.
struct MD_Token { MD_TokenKind kind; MD_NodeFlags node_flags; MD_String8 string; MD_String8 raw_string; };
Flags that should be attached to an MD_Node that uses this token to define its string. Only includes flags that can be understood by the lexer; is not the comprehensive set of node flags that a node needs.
The contents of this token, not including any boundary characters.
The full contents of the string used to form this token, including all boundary characters.
Produces a single token, given some input string.
MD_Token MD_TokenFromString(MD_String8 string);
Returns the number of bytes that can be skipped, when skipping over certain token kinds.
MD_u64 MD_LexAdvanceFromSkips(MD_String8 string, MD_TokenKind skip_kinds);
This type distinguishes the roles of messages, including errors and warnings.
enum MD_MessageKind { MD_MessageKind_Null, MD_MessageKind_Note, MD_MessageKind_Warning, MD_MessageKind_Error, MD_MessageKind_FatalError, };
The message does not have a particular role.
The message is not suggesting that anything wrong occurred, but is instead just providing additional information.
The message is a warning.
The message has information about a non-catastrophic error. Reasonable results may still have been produced, but something illegal was encountered.
The message has information about a catastrophic error, meaning that the output of whatever the error was for cannot be trusted, and should be treated as a complete failure.
This type encodes information about messages.
struct MD_Message { MD_Message* next; MD_Node* node; MD_MessageKind kind; MD_String8 string; };
A pointer to the next error, in a chain of errors. This is 0 when it is the last error in a chain.
The node that this message refers to.
This message's kind.
The message contents.
This type is for a chain of error messages, with data about the entire list.
struct MD_MessageList { MD_MessageKind max_message_kind; MD_u64 node_count; MD_Message* first; MD_Message* last; };
The most severe message kind in this chain, where a message kind is more severe than another if it has a higher numeric value (if it is defined later in MD_MessageKind) than another.
The number of errors in this list.
The first error in the list.
The last error in the list.
An enum to describe how a list of nodes should be delimited.
enum MD_ParseSetRule { MD_ParseSetRule_EndOnDelimiter, MD_ParseSetRule_Global, };
The list of nodes stops being parsed when a delimiter, meaning a set closing symbol or an implicitly-delimited set closer, is encountered in the token stream.
The list of nodes is never terminated until there are no tokens remaining in the token stream; used when parsing entire files.
This type is used to return results from all MD_Node parsing functions.
struct MD_ParseResult { MD_Node* node; MD_u64 string_advance; MD_MessageList errors; };
The number of bytes that were parsed. Skipping this many bytes in the parse input string will provide the point at which the parser stopped parsing.
A list of messages (especially errors) that were encountered during the parse. If this list contains an MD_Message with MD_MessageKind_FatalError set as its MD_MessageKind, then the output of the parser should not be trusted.
MD_ParseWholeFile, MD_ParseWholeString, MD_ParseOneNode, MD_ParseNodeSet
Constructs a default MD_ParseResult, which indicates that nothing was parsed.
Parses a single Metadesk node set, starting at offset bytes into string. Parses the associated set delimiters in accordance with rule.
MD_ParseResult MD_ParseNodeSet(MD_Arena* arena, MD_String8 string, MD_u64 offset, MD_Node* parent, MD_ParseSetRule rule);
The arena onto which the parser should allocate memory.
The string containing the source text to parse.
The offset into string where this function should start parsing.
The parent node for which the set's children are being parsed.
The rule to use for determining the end of the set.
Parses a single Metadesk subtree, starting at offset bytes into string.
MD_ParseResult MD_ParseOneNode(MD_Arena* arena, MD_String8 string, MD_u64 offset);
The arena onto which the parser should allocate memory.
The string containing the source text to parse.
The offset into string where this function should start parsing.
Parses an entire string encoding Metadesk. Parents all parsed nodes with a node with MD_NodeKind_File set as its kind.
MD_ParseResult MD_ParseWholeString(MD_Arena* arena, MD_String8 filename, MD_String8 contents);
The arena onto which the parser should allocate memory.
The filename to associate with the parse.
The string that contains the text to parse.
Uses the C standard library to load the file associated with filename, and parses all of it to return a single tree for the whole file.
MD_ParseResult MD_ParseWholeFile(MD_Arena* arena, MD_String8 filename);
The arena onto which the parser should allocate memory.
The filename for the file to be loaded and parsed.
Constructs an MD_Node on arena for the purpose of marking the location at which an error in source text input occurred.
MD_Node* MD_MakeErrorMarkerNode(MD_Arena* arena, MD_String8 parse_contents, MD_u64 offset);
The arena onto which the returned message should be allocated.
The string that was being parsed, in which an error was found.
The offset, in bytes, into parse_contents where the error occurred.
Allocates and initializes an MD_Message associated with a particular MD_Node.
MD_Message* MD_MakeNodeError(MD_Arena* arena, MD_Node* node, MD_MessageKind kind, MD_String8 str);
The arena onto which the returned message should be allocated.
The node associated with the message.
The message kind, encoding its severity.
The string for the message.
Allocates and initializes an MD_Message associated with a user-controlled pointer.
MD_Message* MD_MakeDetachedError(MD_Arena* arena, MD_Node* node, MD_MessageKind kind, MD_String8 str);
The arena onto which the returned message should be allocated.
The node associated with the message.
The message kind, encoding its severity.
The string for the message.
Allocates and initializes an MD_Message associated with a particular MD_Token.
MD_Message* MD_MakeTokenError(MD_Arena* arena, MD_String8 parse_contents, MD_Token token, MD_MessageKind kind, MD_String8 str);
The entire string that is being parsed. The parser used a substring of this string to form token.
The token associated with this message.
The message kind, encoding its severity.
The string for the message.
Pushes a constructed MD_Message into an MD_MessageList.
void MD_MessageListPush(MD_MessageList* list, MD_Message* error);
Pushes the contents of to_push into list. Zeroes to_push; the memory used in forming to_push will be used in list, and nothing will be copied.
void MD_MessageListConcat(MD_MessageList* list, MD_MessageList* to_push);
These constants distinguish major roles of MD_Node in the Metadesk abstract syntax tree data structure.
enum MD_NodeKind { MD_NodeKind_Nil, MD_NodeKind_File, MD_NodeKind_ErrorMarker, MD_NodeKind_Main, MD_NodeKind_Tag, MD_NodeKind_List, MD_NodeKind_Reference, MD_NodeKind_COUNT, };
The Nil node is a unique node representing the lack of information, for example iterating off the end of a list, or up to the parent of a root node results in Nil.
A File node represents parsed Metadesk source text.
An ErrorMarker node is generated when reporting errors. It is used to record the location of an error that occurred in the lexing phase of a parse.
A Main node represents the main structure of the metadesk abstract syntax tree. Some of these nodes have children which will also be Main nodes. These nodes can be given their text by identifiers, numerics, string and character literals, and operator symbols.
A Tag node represents a tag attached to a label node with the @identifer syntax. The children of a tag node represent the arguments placed in the tag.
A List node serves as the root of an externally chained list of nodes. Its children are nodes with the MD_NodeKind_Reference kind.
A Reference node is an indirection to another node. The node field ref_target contains a pointer to the referenced node. These nodes are typically used for creating externally chained linked lists that gather nodes from a parse tree.
Not a real kind value given to nodes, this is always one larger than the largest enum value that can be given to a node.
These flags are set on MD_Node to indicate particular details about the strings that were parsed to create the node.
typedef MD_u32 MD_NodeFlags; enum { MD_NodeFlag_HasParenLeft = (1<<0), MD_NodeFlag_HasParenRight = (1<<1), MD_NodeFlag_HasBracketLeft = (1<<2), MD_NodeFlag_HasBracketRight = (1<<3), MD_NodeFlag_HasBraceLeft = (1<<4), MD_NodeFlag_HasBraceRight = (1<<5), MD_NodeFlag_IsBeforeSemicolon = (1<<6), MD_NodeFlag_IsAfterSemicolon = (1<<7), MD_NodeFlag_IsBeforeComma = (1<<8), MD_NodeFlag_IsAfterComma = (1<<9), MD_NodeFlag_StringSingleQuote = (1<<10), MD_NodeFlag_StringDoubleQuote = (1<<11), MD_NodeFlag_StringTick = (1<<12), MD_NodeFlag_StringTriplet = (1<<13), MD_NodeFlag_Numeric = (1<<14), MD_NodeFlag_Identifier = (1<<15), MD_NodeFlag_StringLiteral = (1<<16), };
This node's children open with (
This node's children close with )
This node's children open with [
This node's children close with ]
This node's children open with {
This node's children close with }
The delimiter between this node and its next sibling is a ;
The delimiter between this node and its previous sibling is a ;
The delimiter between this node and its next sibling is a ,
The delimiter between this node and its previous sibling is a ,
This is a string literal, with ' character(s) marking the boundaries.
This is a string literal, with " character(s) marking the boundaries.
This is a string literal, with ` character(s) marking the boundaries.
This is a string literal that used triplets (three of its boundary characters in a row, on either side) to mark its boundaries, making it multiline.
The label on this node comes from a token with the MD_TokenKind_Numeric kind.
The label on this node comes from a token with the MD_TokenKind_Identifier kind.
The label on this node comes from a token with the MD_TokenKind_StringLiteral kind.
The MD_Node is the main 'lego-brick' for modeling the result of a Metadesk parse. Also used in some auxiliary data structures.
struct MD_Node { MD_Node* next; MD_Node* prev; MD_Node* parent; MD_Node* first_child; MD_Node* last_child; MD_Node* first_tag; MD_Node* last_tag; MD_NodeKind kind; MD_NodeFlags flags; MD_String8 string; MD_String8 raw_string; MD_u64 string_hash; MD_String8 prev_comment; MD_String8 next_comment; MD_u64 offset; MD_Node* ref_target; };
The next sibling in the hierarchy, or the next tag in a list of tags, or next node in an externally chained linked list.
The previous sibling in the hierarchy, or the previous tag in a list of tags, or previous node in an externally chained linked list.
The parent in the hierarchy, or root node of an externally chained linked list.
The first child in the hierarchy, or the first node in an externally chained linked list.
The last child in the hierarchy, or the last node in an externally chained linked list.
The first tag attached to a node.
The last tag attached to a node.
Indicates the role that the node plays in metadesk node graph.
Extra information about the source that generated this node in the parse.
The string of the token labeling this node, after processing. Processing removing quote marks that delimits string literals and character literals
The raw string of the token labeling this node.
A hash of the string field using the metadesk built in hash function.
The raw string of the comment token before this node, if there is one.
The raw string of the comment token after this node, if there is one.
The byte-offset into the string from which this node was parsed. Used for producing data for an MD_CodeLoc.
The external pointer from an MD_NodeKind_Reference kind node in an externally linked list.
Returns a string that contains a name matching kind.
Builds a string list for all bits set in flags, with each string being the name of one of the flags that is set.
MD_String8List MD_StringListFromNodeFlags(MD_Arena* arena, MD_NodeFlags flags);
Returns 1 if the node is nil, or 0 otherwise. A nil node pointer is not equivalent to a null pointer. It can still be dereferenced, and is treated as a dummy placeholder node value.
MD_b32 MD_NodeIsNil(MD_Node* node);
Returns a nil node pointer.
MD_Node* MD_NilNode();
Links new_child up as being a child of parent, inserting it into the end of parent's children list.
void MD_PushChild(MD_Node* parent, MD_Node* new_child);
Links tag up as being a tag of node, inserting it into the end of node's tag list.
void MD_PushTag(MD_Node* node, MD_Node* tag);
Creates a new reference node, pointing at target, and links it up as a child of list.
MD_Node* MD_PushNewReference(MD_Node* list, MD_Node* target);
Finds a node in the range defined by first and one_past_last, with the string matching string in accordance with flags, or returns a nil node pointer if it is not found.
MD_Node* MD_FirstNodeWithString(MD_Node* first, MD_String8 string, MD_MatchFlags flags);
The first node in the range to search.
The string to search for.
Controls what is considered a match, when doing string matching.
The found node, or a nil node pointer if no node was found.
Finds the nth node in the range defined by first and one_past_last, or returns a nil node pointer if it is not found. 0 would match first, 1 would match first->next, and so on.
MD_Node* MD_NodeAtIndex(MD_Node* first, int n);
The first node in the range to search.
The index to search for.
The found node, or a nil node pointer if no node was found.
Given a starting node first, will scan across the node's siblings in-order to find a node that has flags that overlap the passed flags. Useful when, for example, finding the set of node ranges delimited by commas or semicolons inside of a single MD_Node children list.
MD_Node* MD_FirstNodeWithFlags(MD_Node* first, MD_NodeFlags flags);
Finds the child index of node, with 0 being the first child, 1 being the second, and so on.
int MD_IndexFromNode(MD_Node* node);
Finds the highest-most node in the parent chain of node, starting with node. If node has no parent, then node is returned.
MD_Node* MD_RootFromNode(MD_Node* node);
The node for which the root is to be found.
The found root.
Finds a child of node with a string matching child_string, where the rules of matching are determined by flags.
MD_Node* MD_ChildFromString(MD_Node* node, MD_String8 child_string, MD_MatchFlags flags);
The parent whose children are to be searched.
The string that the found child should match.
Controls what is considered a string match.
The found node, or a nil node pointer if no node was found.
MD_FirstNodeWithString, MD_TagFromString
Finds a tag on node with a string matching tag_string, where the rules of matching are determined by flags.
MD_Node* MD_TagFromString(MD_Node* node, MD_String8 tag_string, MD_MatchFlags flags);
The parent whose tags are to be searched.
The string that the found tag should match.
Controls what is considered a string match.
The found node, or a nil node pointer if no node was found.
MD_FirstNodeWithString, MD_ChildFromString
Finds a child of node with an index matching n. Returns a nil node pointer if no such child is found.
MD_Node* MD_ChildFromIndex(MD_Node* node, int n);
The node whose children are to be searched.
The index that the return value should match.
The found node, or a nil node pointer if no such node was found.
MD_NodeAtIndex, MD_IndexFromNode, MD_TagFromIndex
Finds a tag on node with an index matching n. Returns a nil node pointer if no such tag is found.
MD_Node* MD_TagFromIndex(MD_Node* node, int n);
The node whose tags are to be searched.
The index that the return value should match.
The found node, or a nil node pointer if no such node was found.
MD_NodeAtIndex, MD_IndexFromNode, MD_ChildFromIndex
Finds the nth tag argument of the tag matching tag_string on node, with the matching on tag_string being controlled by flags. Returns a nil node pointer if no such node was found.
MD_Node* MD_TagArgFromIndex(MD_Node* node, MD_String8 tag_string, MD_MatchFlags flags, int n);
The node whose tags are to be searched.
The string that the found tag should match.
Controls what is considered a string match.
The index that the return value should match.
The found node, or a nil node pointer if no such node was found.
Finds the tag argument with a string matching arg_string, of the tag matching tag_string, on node. Matching tag_string is controlled by tag_str_flags. Matching arg_string is controlled by arg_str_flags. Returns a nil node pointer if no such node was found.
MD_Node* MD_TagArgFromString(MD_Node* node, MD_String8 tag_string, MD_MatchFlags tag_str_flags, int arg_string, MD_MatchFlags arg_str_flags);
The node whose tags are to be searched.
The string that the found tag should match.
Controls what is considered a string match, when finding the appropriate tag.
The string that the found tag argument should match.
Controls what is considered a string match, when finding the appropriate tag argument.
The found node, or a nil node pointer if no such node was found.
Returns 1 if node has a child with a string matching string, with the matching rules being controlled by flags, or 0 otherwise.
MD_b32 MD_NodeHasChild(MD_Node* node, MD_String8 string, MD_MatchFlags flags);
The node whose children are to be searched.
The string that should match a child in node.
Controls what is considered a match, when comparing against string.
1 if a suitable child was found, or 0 otherwise.
MD_ChildFromIndex, MD_ChildFromString, MD_NodeHasTag
Returns 1 if node has a tag with a string matching tag_string, with the matching rules being controlled by flags, or 0 otherwise.
MD_b32 MD_NodeHasTag(MD_Node* node, MD_String8 tag_string, MD_MatchFlags flags);
The node whose tags are to be searched.
The string that should match a tag in node.
Controls what is considered a match, when comparing against tag_string.
1 if a suitable tag was found, or 0 otherwise.
MD_TagFromIndex, MD_TagFromString, MD_NodeHasChild
Returns the number of children of node.
MD_i64 MD_ChildCountFromNode(MD_Node* node);
Returns the number of tags on node.
MD_i64 MD_TagCountFromNode(MD_Node* node);
If node is of kind MD_NodeKind_Reference, will follow the chain of ref_targets until the final referenced node.
MD_Node* MD_ResolveNodeFromReference(MD_Node* node);
Moves to the next sibling of node, unless it is opl, in which case it returns a nil node.
MD_Node* MD_NodeNextWithLimit(MD_Node* node, MD_Node* opl);
Gets the string of the comment that immediately preceded node, if any.
MD_String8 MD_PrevCommentFromNode(MD_Node* node);
Gets the string of the comment that immediately followed node, if any.
MD_String8 MD_NextCommentFromNode(MD_Node* node);
A helper macro for building for-loops over entire lists of nodes. Place inside of the parentheses of a for-loop, e.g. for(MD_EachNode(child, node->first_child)), to use.
#define MD_EachNode(it, first) ...
The name of the iterator node, as it will be available in the for-loop.
The first node to iterate on.
Returns a string encoding the name of the passed kind value.
Returns the format string for code locations that matches normal encodings of code locations (in error or warning messages by compilers, namely). This string is "%.*s:%i:%i". Used with MD_CodeLocVArg, can be used for easily printing code locations.
#define MD_FmtCodeLoc ...
Expands to the appropriate C format string arguments for an MD_CodeLoc loc matching the format string for code-locations provided by MD_FmtCodeLoc.
#define MD_CodeLocVArg(loc) ...
Provides a standard way to format a message string that is associated with an MD_CodeLoc and an MD_MessageKind.
MD_String8 MD_FormatMessage(MD_Arena* arena, MD_CodeLoc loc, MD_MessageKind kind, MD_String8 string);
The arena to use for allocating the string.
The location to associate this message with.
The MD_MessageKind to associate this message with.
The contents of the message.
Formats and prints a standardly-formatted string that is associated with an MD_CodeLoc and MD_MessageKind, in the same format that MD_FormatMessage uses. Relies on MD_DISABLE_PRINT_HELPERS not being set, as it relies on fprintf and the passed FILE *.
void MD_PrintMessage(FILE* file, MD_CodeLoc loc, MD_MessageKind kind, MD_String8 string);
The output file stream to which the formatted message is printed.
The location to associate this message with.
The MD_MessageKind to associate this message with.
The contents of the message.
MD_FormatMessage, MD_PrintMessageFmt
Formats and prints a standardly-formatted string (being derived from a C-style format-string) that is associated with an MD_CodeLoc and MD_MessageKind, in the same format that MD_FormatMessage uses. Relies on MD_DISABLE_PRINT_HELPERS not being set, as it relies on fprintf and the passed FILE *.
void MD_PrintMessageFmt(FILE* file, MD_CodeLoc loc, MD_MessageKind kind, char* fmt, ...);
The output file stream to which the formatted message is printed.
The location to associate this message with.
The MD_MessageKind to associate this message with.
The C-style format C-string for the message.
MD_FormatMessage, MD_PrintMessage
Uses fprintf to print a C-style comment that specifies the location of the code that was used to generate it. Useful when correlating generated code with associated generator code.
#define MD_PrintGenNoteCComment(f) ...
The FILE* to which the comment is printed.
Compares the passed MD_Node nodes a and b non-recursively, and determines whether or not they match. flags determines the rules used in the matching algorithm, including tag-sensitivity and case-sensitivity.
MD_b32 MD_NodeMatch(MD_Node* a, MD_Node* b, MD_MatchFlags flags);
Compares the passed MD_Node trees a and b recursively, and determines whether or not they and their children match. flags determines the rules used in the matching algorithm, including tag-sensitivity and case-sensitivity.
MD_b32 MD_NodeDeepMatch(MD_Node* a, MD_Node* b, MD_MatchFlags flags);
MD_NodeMatch, MD_S8Match, MD_MatchFlags
This type encodes source code locations using file, line, column coordinates.
struct MD_CodeLoc { MD_String8 filename; MD_u32 line; MD_u32 column; };
Line numbers are 1 based, the lowest valid location is on line number 1.
Column numbers are 1 based, the lowest valid location is on column number 1.
Calculates a position in a source code file in filename/line/column coordinates, provided a filename, a base pointer for the file's contents, and an offset into the file's contents.
MD_CodeLoc MD_CodeLocFromFileOffset(MD_String8 filename, MD_u8* base, MD_u64 offset);
Calculates a position in a source code file in filename/line/column coordinates, provided a parsed MD_Node.
MD_CodeLoc MD_CodeLocFromNode(MD_Node* node);
These flags are used to control what is generated in an MD_Node tree string generation function.
typedef MD_u32 MD_GenerateFlags; enum { MD_GenerateFlag_Tags = (1<<0), MD_GenerateFlag_TagArguments = (1<<1), MD_GenerateFlag_Children = (1<<2), MD_GenerateFlag_Comments = (1<<3), MD_GenerateFlag_NodeKind = (1<<4), MD_GenerateFlag_NodeFlags = (1<<5), MD_GenerateFlag_StringHash = (1<<6), MD_GenerateFlag_Location = (1<<7), MD_GenerateFlag_Tree = MD_GenerateFlag_Tags | MD_GenerateFlag_TagArguments | MD_GenerateFlag_Children, MD_GenerateFlag_All = 0xffffffff, };
This turns on the code that generates strings associated with tags attached to nodes. This will not enable string generation for tag arguments, which is separately controlled by the MD_GenerateFlag_TagArguments flag.
This turns on the code that generates strings associated with tags arguments. Does nothing if MD_GenerateFlag_Tags is not set.
This enables recursive descent on the input MD_Node tree, generating strings for all children recursively.
This enables string generation for comments that were identified by the Metadesk parser as being attached to nodes.
This enables string generation relating to each node's MD_NodeKind value.
This enables string generation relating to each node's MD_NodeFlags value.
This enables string generation for the 64-bit hash associated with the string of an MD_Node, which is generated by the parser automatically.
This enables string generation for the source code coordinates of the originally-parsed MD_Node structure.
A mask used to generate strings for the entire tree structure of an MD_Node tree. Skips comments, location, and other metadata.
A mask used to generate everything.
Writes to out, writing legal Metadesk strings that document details of node.
void MD_DebugDumpFromNode(MD_Arena* arena, MD_String8List* out, MD_Node* node, int indent, MD_String8 indent_string, MD_GenerateFlags flags);
The arena to use for string allocation.
The string list to push to.
The node for which details are printed.
The indentation level to generate strings for, with each indentation level implying one occurrence of indent_string.
The string to output per-indentation level.
Used to control which aspects of node are generated.
Writes to out, writing legal Metadesk strings that attempt to reconstruct the code that was parsed to form node as closely as possible.
void MD_ReconstructionFromNode(MD_Arena* arena, MD_String8List* out, MD_Node* node, int indent, MD_String8 indent_string);
The arena to use for string allocation.
The string list to push to.
The node for which details are printed.
The indentation level to generate strings for, with each indentation level implying one occurrence of indent_string.
The string to output per-indentation level.
An abstraction over the types of keys used in an MD_Map and the work of hashing those keys. Can be constructed from an MD_String8 or a void *.
struct MD_MapKey { MD_u64 hash; MD_u64 size; void* ptr; };
The hash of the key. The hash function used is determined from the key type.
For a non-empty MD_String8, the size of the string data. For a void*, zero.
For a non-empty MD_String8, points to the string data of the key. For a void*, the direct pointer value.
A slot containing one (key,value) pair in an MD_Map.
struct MD_MapSlot { MD_MapSlot* next; MD_MapKey key; void* value; };
The next slot in the same bucket of the MD_Map.
The key that maps to this slot.
The value part of the pair.
The data used to form a table in an MD_Map. Stores pointers that form a linked list of all MD_MapSlot instances that mapped to this bucket.
struct MD_MapBucket { MD_MapSlot* first; MD_MapSlot* last; };
The map is a chained hash table data structure. Data written to the map is a key-value pair. The key of a pair may either be a pointer, or a string. Both types may be mixed inside a single map. Keys stored with one type never match keys of the other type. The values of the pairs are pointers.
struct MD_Map { MD_MapBucket* buckets; MD_u64 bucket_count; };
Returns a 64-bit hash of the input string. Used in implementing string-to-slot mapping in MD_MapKeyStr.
MD_u64 MD_HashStr(MD_String8 string);
Returns a 64-bit hash of the passed pointer. Used in implementing pointer-to-slot mapping in MD_MapKeyPtr.
void MD_HashPtr(void* p);
Constructs a new MD_Map on arena with the specified bucket_count.
MD_Map MD_MapMakeBucketCount(MD_Arena* arena, MD_u64 bucket_count);
Constructs a new MD_Map on arena with a default bucket count that fits common cases. MD_MapMakeBucketCount can be used as an alternative for constructing an MD_Map with a specific number of buckets.
MD_Map MD_MapMake(MD_Arena* arena);
Forms an MD_Map key from a string.
MD_MapKey MD_MapKeyStr(MD_String8 string);
Forms an MD_Map key from a pointer.
MD_MapKey MD_MapKeyPtr(void* ptr);
Returns a pointer to the stored MD_MapSlot that is associated with key inside of map, if it exists.
MD_MapSlot* MD_MapLookup(MD_Map* map, MD_MapKey key);
MD_MapSlot, MD_MapScan, MD_MapKeyStr, MD_MapKeyPtr
Given a pointer to an existing MD_MapSlot (constructed from a function like MD_MapLookup), scans to the next MD_MapSlot in the table's hash-chain that uses the same key. Useful in cases when you are mapping one key to multiple values, instead of assuming a one-to-one mapping.
MD_MapSlot* MD_MapScan(MD_MapSlot* first_slot, MD_MapKey key);
MD_MapLookup, MD_MapKeyStr, MD_MapKeyPtr
Inserts a new value associated with key into map. Allocates a new slot for the value with arena.
MD_MapSlot* MD_MapInsert(MD_Arena* arena, MD_Map* map, MD_MapKey key, void* val);
Overwrites the first existing slot associated with key with a new value, or allocates a new slot if an existing slot does not already exist.
MD_MapSlot* MD_MapOverwrite(MD_Arena* arena, MD_Map* map, MD_MapKey key, void* val);
This type determines how an operator entered into the expression system is parsed.
enum MD_ExprOprKind { MD_ExprOprKind_Null, MD_ExprOprKind_Prefix, MD_ExprOprKind_Postfix, MD_ExprOprKind_Binary, MD_ExprOprKind_BinaryRightAssociative, MD_ExprOprKind_COUNT, };
The operator is parsed as a prefix unary operator.
The operator is parsed as a postfix unary operator.
The operator is parsed as a left-to-right binary operator.
The operator is parsed as a right-to-left binary operator.
This type carries the primary information regarding an operator in an expression system.
struct MD_ExprOpr { MD_ExprOpr* next; MD_u32 op_id; MD_ExprOprKind kind; MD_u32 precedence; MD_String8 string; void* op_ptr; };
Internal - used in forming chains of operators.
User data set on the creation of the operator.
Determines what kind of associativity the operator has.
Determines the precedence level of the operator.
The string of the operator.
User data set on the creation of the operator.
A simple linked list of MD_ExprOpr nodes. This type is used to gather operators before they are baked down to an optimized operator table.
struct MD_ExprOprList { MD_ExprOpr* first; MD_ExprOpr* last; MD_u64 count; };
First node of the chain.
Last node of the chain.
The number of nodes in the chain.
An operator table determines the set of operators that will be understood by the parser. It's exact structure is likely to get rearranged whenever it is upgraded to provide faster operator lookups, so it's contents should all be considered 'internal'.
struct MD_ExprOprTable { // opaque };
An expression node used as the output type from the expression parser.
struct MD_Expr { MD_Expr* parent; MD_Expr* left; MD_Expr* right; MD_ExprOpr* op; MD_Node* md_node; };
The parent node in the expression tree, null for the root node.
The left operand of binary operators - also the operand of unary operators.
The right operand of binary operators - null for unary operators.
If this expression node is an operator this points to the operator's primary data. If this expression node is a leaf then this pointer is null.
A pointer to the metadesk node directly responsible for generating this node of the expression.
The expression parser returns this, a combined expression node tree and a list of error messages.
struct MD_ExprParseResult { MD_Expr* expr; MD_MessageList errors; };
The root of the expression tree.
The list of parser errors.
The parse context used in expression parsing. Currently considered entirely internal.
struct MD_ExprParseCtx { // opaque };
Pushes a new operator onto the back of an operator list. All of the pushes on a list should be allocated on the same arena.
void MD_ExprOprPush(MD_Arena* arena, MD_ExprOprList* list, MD_ExprOprKind kind, MD_u64 precedence, MD_String8 op_string, MD_u32 op_id, void* op_ptr);
The list accumulating the operators.
This operator's association rule.
This precedence level. Higher precedence means 'more tightly binding'.
The string for this operator. It should parse as a single Metadesk token, either a symbol token or an identifier token.
User data. Intended for statically allocated ids like enums for operator switches.
User data. Intended for dynamically allocated ids like pointers to some other structure.
MD_ExprOprList, MD_ExprOprKind
Convert a simple list of operators into an operator table - and performing correctness checks along the way.
MD_ExprOprTable MD_ExprBakeOprTableFromList(MD_Arena* arena, MD_ExprOprList* list);
The list of operators to bake into a table.
Get an operator info pointer from an operator table by looking up it's operator kind and name.
MD_ExprOpr* MD_ExprOprFromKindString(MD_ExprOprTable* table, MD_ExprOprKind kind, MD_String8 s);
The table of operators to look into.
Which kind of operator to find. If this is MD_ExprOprKind_Null then any kind of operator can match.
The name of the operator to find.
Create an expression tree from a range of Metadesk nodes.
MD_ExprParseResult MD_ExprParse(MD_Arena* arena, MD_ExprOprTable* op_table, MD_Node* first, MD_Node* one_past_last);
The operator table that controls the parse.
Allocates and initializes a leaf expression node. Currently considered entirely internal.
void MD_Expr_NewLeaf();
Allocates and initializes an operator expression node. Currently considered entirely internal.
void MD_Expr_NewOpr();
Initializes an expression parser context. Currently considered entirely internal.
void MD_ExprParse_MakeContext();
Parser helper: The root call for a parse of a range of metadesk nodes. Currently considered entirely internal.
void MD_ExprParse_TopLevel();
Parse helper: Tries to consume the next node as an operator and return the operator's primary info pointer. Currently considered entirely internal.
void MD_ExprParse_OprConsume();
Parse helper: Handles leaves, prefix operators, and parentheses. Currently considered entirely internal.
void MD_ExprParse_Atom();
Parse helper: Core of the parsing loop, puts together binary operators, does precedence checking, etc. Currently considered entirely internal.
void MD_ExprParse_MinPrecedence();
A type used to encode parsed command line options, that can have values associated with them.
struct MD_CmdLineOption { MD_CmdLineOption* next; MD_String8 name; MD_String8List values; };
A pointer to the next option, if this is within a chain of options. Will be 0 if this is the last option in a chain.
The name of this option.
The values associated with this option.
MD_CmdLine, MD_MakeCmdLineFromOptions
The type encoding a fully parsed set of command line options.
struct MD_CmdLine { MD_String8List inputs; MD_CmdLineOption* first_option; MD_CmdLineOption* last_option; };
The list of all command line arguments that were not parsed as flags with optional values. Can be used as a list of unstructured input strings; for example, to be considered as input file paths.
The first option that was parsed, forming the head of a chain of options.
The last option that was parsed.
Converts a traditional C-style argc, argv pair into an MD_String8List.
MD_String8List MD_StringListFromArgCV(MD_Arena* arena, int argument_count, char** arguments);
The arena to allocate with.
The number of command line arguments. Traditionally referred to as argc.
A pointer to the command line arguments. Traditionally referred to as argv.
Parses an MD_String8List as a set of command line options.
MD_CmdLine MD_MakeCmdLineFromOptions(MD_Arena* arena, MD_String8List options);
The arena to allocate with.
An MD_String8List encoding the list of command line arguments. Can be produced from a traditional argc and argv pair using MD_StringListFromArgCV.
MD_CmdLine, MD_StringListFromArgCV, MD_CmdLineValuesFromString, MD_CmdLineB32FromString
Gets the list of values associated with name in the parsed command line arguments.
MD_String8List MD_CmdLineValuesFromString(MD_CmdLine cmdln, MD_String8 name);
Parsed command line data from MD_MakeCmdLineFromOptions.
The name of the command line option.
MD_CmdLine, MD_MakeCmdLineFromOptions, MD_CmdLineB32FromString, MD_CmdLineI64FromString
Determines whether a command line argument explicitly passed an option matching name.
MD_b32 MD_CmdLineB32FromString(MD_CmdLine cmdln, MD_String8 name);
Parsed command line data from MD_MakeCmdLineFromOptions.
The name of the command line option.
MD_CmdLine, MD_MakeCmdLineFromOptions, MD_CmdLineB32FromString, MD_CmdLineValuesFromString
Gets the list of values associated with name in the parsed command line arguments, treats them as a string representation of a 64-bit signed integer value, and returns that integer value.
MD_i64 MD_CmdLineI64FromString(MD_CmdLine cmdln, MD_String8 name);
Parsed command line data from MD_MakeCmdLineFromOptions.
The name of the command line option.
MD_MakeCmdLineFromOptions, MD_CmdLineValuesFromString, MD_CmdLineB32FromString
Flags encoding certain properties of a file.
typedef MD_u32 MD_FileFlags; enum { MD_FileFlag_Directory = (1<<0), };
The associated file is a directory.
MD_FileInfo, MD_FileIterBegin, MD_FileIterNext, MD_FileIterEnd
Encodes general metadata about a file.
struct MD_FileInfo { MD_FileFlags flags; MD_String8 filename; MD_u64 file_size; };
The name of the file. This includes the extension of the file, but does not include the directory in which the file is stored.
The size of the file, in bytes.
MD_FileFlags, MD_FileIterBegin, MD_FileIterNext, MD_FileIterEnd
An opaque iterator type used to store operating-system-specific state, when iterating files.
struct MD_FileIter { // opaque };
MD_FileIterBegin, MD_FileIterNext, MD_FileIterEnd
Uses the C standard library to load the contents of the file with filename into an MD_String8.
MD_String8 MD_LoadEntireFile(MD_Arena* arena, MD_String8 filename);
The arena to use for allocating.
The filename of the file that is to be loaded.
Uses lower level operating system APIs to begin iterating a file-system directory. Initializes the opaque structure it to do so.
void MD_FileIterBegin(MD_FileIter* it, MD_String8 path);
MD_FileIter, MD_FileIterEnd, MD_FileIterNext
Uses lower level operating system APIs to retrieve the next file in a file-system directory, and advance to the next one, with state being stored in it. Requires calling MD_FileIterBegin on it first. Returns the iterated file's information.
MD_FileInfo MD_FileIterNext(MD_Arena* arena, MD_FileIter* it);
MD_FileIter, MD_FileIterBegin, MD_FileIterEnd
Uses lower level operating system APIs to end iterating a file-system directory. Call once it is done being used.
void MD_FileIterEnd(MD_FileIter* it);