diff --git a/docs/metadesk_reference.mdesk b/docs/metadesk_reference.mdesk index 844a251..2d1d124 100644 --- a/docs/metadesk_reference.mdesk +++ b/docs/metadesk_reference.mdesk @@ -1851,7 +1851,6 @@ MD_ParseWholeFile: @doc("Prints a message to @code 'out', corresponding with the source code location encoded by @code 'loc'.") @see(MD_PrintMessageFmt) @see(MD_PrintNodeMessage) -@see(MD_PrintNodeMessageFmt) @func MD_PrintMessage: { @doc("The file to print the message to.") out: *FILE, @@ -1867,7 +1866,6 @@ MD_ParseWholeFile: @doc("Prints a C format string message to @code 'out', corresponding with the source code location encoded by @code 'loc'.") @see(MD_PrintMessage) @see(MD_PrintNodeMessage) -@see(MD_PrintNodeMessageFmt) @func MD_PrintMessageFmt: { @doc("The file to print the message to.") out: *FILE, @@ -1883,7 +1881,6 @@ MD_ParseWholeFile: @send(Nodes) @see(MD_PrintMessage) @see(MD_PrintMessageFmt) -@see(MD_PrintNodeMessageFmt) @doc("Prints a message to @code 'out', corresponding with the source code location of @code 'node'.") @func MD_PrintNodeMessage: { @doc("The file to print the message to.") @@ -1896,23 +1893,6 @@ MD_ParseWholeFile: str: MD_String8, }; -@send(Nodes) -@doc("Prints a C format string message to @code 'out', corresponding with the source code location of @code 'node'.") -@see(MD_PrintMessage) -@see(MD_PrintMessageFmt) -@see(MD_PrintNodeMessage) -@func MD_PrintNodeMessageFmt: { - @doc("The file to print the message to.") - out: *FILE, - @doc("The node for which the message is intended.") - node: *MD_Node, - @doc("The kind/severity of the message.") - kind: MD_MessageKind, - @doc("The format string to form the message contents.") - fmt: *char, - "..." -}; - //////////////////////////////// //~ Tree Comparison/Verification diff --git a/examples/datadesk_like_template.c b/examples/datadesk_like_template.c index a95b966..17b0916 100644 --- a/examples/datadesk_like_template.c +++ b/examples/datadesk_like_template.c @@ -2,7 +2,7 @@ ** Example: datadesk-like-template ** ** This example is setup as a copy-pastable template for creating metadesk -** based metaprograms that have the same structure as datadesk. +** based metaprograms that have the same structure as datadesk metaprograms. ** ** Datadesk was a precursor language to metadesk. This example is mostly meant ** to help datadesk users understand metadesk and migrate onto it. @@ -16,6 +16,8 @@ //~ Includes and globals ////////////////////////////////////////////////////// +#define MD_ENABLE_PRINT_HELPERS 1 + #include "md.h" #include "md.c" @@ -24,47 +26,67 @@ static MD_Arena *arena = 0; //~ Declare user defined functions (the datadesk "custom layer") ////////////// -// Called when the program starts. -static void Initialize(void); -// Called for every top-level node that is parsed from passed files. -static void TopLevel(MD_Node *node); -// Runs before the program ends. -static void CleanUp(void); +static void Initialize(void); // Runs at the beginning of generation. +static void TopLevel(MD_Node *node); // Runs once for each top-level node from each file. +static void CleanUp(void); // Runs at the end of generation. //~ main ////////////////////////////////////////////////////////////////////// int main(int argument_count, char **arguments) { - // simple single-threaded one-run memory management setup + // setup the global arena arena = MD_ArenaAlloc(1ull << 40); // parse all files passed to the command line + MD_b32 failed_parse = 0; MD_Node *list = MD_MakeList(arena); for(int i = 1; i < argument_count; i += 1) { - MD_Node *root = MD_ParseWholeFile(arena, MD_S8CString(arguments[i])).node; - MD_PushNewReference(arena, list, root); - } - - // calls to the "custom layer" - Initialize(); - for(MD_EachNode(ref, list->first_child)) - { - MD_Node *root = MD_NodeFromReference(ref); - for(MD_EachNode(node, root->first_child)) + + // parse the file + MD_String8 file_name = MD_S8CString(arguments[i]); + MD_ParseResult parse_result = MD_ParseWholeFile(arena, file_name); + + // print metadesk errors + for (MD_Message *message = parse_result.errors.first; + message != 0; + message = message->next) { - TopLevel(node); + MD_CodeLoc code_loc = MD_CodeLocFromNode(message->node); + MD_PrintMessage(stdout, code_loc, message->kind, message->string); + } + + // save to parse results list + MD_PushNewReference(arena, list, parse_result.node); + + // mark failure state + if (parse_result.errors.max_message_kind >= MD_MessageKind_Error) + { + failed_parse = 1; } } - CleanUp(); + + // call the "custom layer" + if (!failed_parse) + { + Initialize(); + for(MD_EachNode(ref, list->first_child)) + { + MD_Node *root = MD_NodeFromReference(ref); + for(MD_EachNode(node, root->first_child)) + { + TopLevel(node); + } + } + CleanUp(); + } return 0; } -//~ The "custom layer" definitions //////////////////////////////////////////// - +//~ The "custom layer" //////////////////////////////////////////////////////// static void Initialize(void) diff --git a/examples/parse_check.c b/examples/parse_check.c index 6870929..6e1ea43 100644 --- a/examples/parse_check.c +++ b/examples/parse_check.c @@ -1,26 +1,87 @@ +/* +** Example: parse-check +** + ** This example shows how to use the metadesk library to parse metadesk files, +** print errors, and dump verbose feedback on the resulting metadesk trees. +** This is also a nice utility for checking and inspecting your metadesk files. +** +*/ + +//~ Includes and globals ////////////////////////////////////////////////////// + +// @notes Print helpers will make it easier to print the errors. This brings in +// C's stdio.h. It is possible to use error messages without print helpers, +// but a dependency on stdio.h is fine here so we will use it. +#define MD_ENABLE_PRINT_HELPERS 1 + #include "md.h" #include "md.c" +// @notes For simple single-threaded memory management in a run-once-and-exit +// utility, a single global arena is our prefered setup. static MD_Arena *arena = 0; + +//~ main ////////////////////////////////////////////////////////////////////// + int main(int argument_count, char **arguments) { + // setup the global arena + // @notes Metadesk arenas do linear reserve-and-commit allocation. This + // code makes an arena with a 1 terabyte reserve which works quite nicely, + // so long as we aren't doing more than a few of them. arena = MD_ArenaAlloc(1ull << 40); + + // parse all files passed to the command line MD_Node *list = MD_MakeList(arena); for(int i = 1; i < argument_count; i += 1) { - MD_Node *root = MD_ParseWholeFile(arena, MD_S8CString(arguments[i])).node; - MD_PushNewReference(arena, list, root); + + // parse the file + // @notes Here we rely on MD_ParseWholeFile which loads the file itself + // and then does the whole parse. In a simple utility program like + // this metadesk's default implementations for the overrides make + // this work. + MD_String8 file_name = MD_S8CString(arguments[i]); + MD_ParseResult parse_result = MD_ParseWholeFile(arena, file_name); + + // print metadesk errors + for (MD_Message *message = parse_result.errors.first; + message != 0; + message = message->next) + { + // @notes To print a message from the parse, technically we can do + // whatever we want. But we'll use the message format suggested + // by the metadesk library. First we get the code location - which + // means the file name and line number - for the node on this + // message. Then we pass the details of this message to the + // MD_PrintMessage helper function. + MD_CodeLoc code_loc = MD_CodeLocFromNode(message->node); + MD_PrintMessage(stdout, code_loc, message->kind, message->string); + } + + // save to parse results list + // @notes Metadesk message kinds are sorted in order of severity. So we + // can easily check the severity of a entire parse by looking at the + // `max_message_kind` field on the errors from the parse result. Here + // only push the parse result onto our list if there were no errors. + if (parse_result.errors.max_message_kind >= MD_MessageKind_Error) + { + MD_PushNewReference(arena, list, parse_result.node); + } } + // print the verbose parse results for(MD_EachNodeRef(root, list->first_child)) { for(MD_EachNode(node, root->first_child)) { - MD_String8List strs = MD_DebugStringListFromNode(arena, node, 0, MD_S8Lit(" "), MD_GenerateFlags_Tree); + MD_String8List strs = + MD_DebugStringListFromNode(arena, node, 0, MD_S8Lit(" "), MD_GenerateFlags_Tree); MD_String8 str = MD_S8ListJoin(arena, strs, 0); - fprintf(stdout, "%.*s\n", MD_S8VArg(str)); + fwrite(str.str, str.size, 1, stdout); + fwrite("\n", 1, 1, stdout); } } diff --git a/intro_notes.txt b/intro_notes.txt index 8233ce6..b3c8ef6 100644 --- a/intro_notes.txt +++ b/intro_notes.txt @@ -5,8 +5,8 @@ immutable tree model nil Examples: +[ ] Metadesk hello world [ ] Metadesk parse checker -[ ] Metadesk reprinter [ ] Example of helpers: string helpers, linked lists, map type printing errors, cmd line, file iter [x] Datadesk-like setup diff --git a/source/md.c b/source/md.c index 724ca4e..81b3c17 100644 --- a/source/md.c +++ b/source/md.c @@ -2903,19 +2903,6 @@ MD_PrintMessageFmt(FILE *file, MD_CodeLoc code_loc, MD_MessageKind kind, char *f MD_ReleaseScratch(scratch); } -MD_FUNCTION void -MD_PrintNodeMessageFmt(FILE *file, MD_Node *node, MD_MessageKind kind, char *fmt, ...){ - MD_ArenaTemp scratch = MD_GetScratch(0, 0); - va_list args; - va_start(args, fmt); - MD_String8 string = MD_S8FmtV(scratch.arena, fmt, args); - va_end(args); - MD_CodeLoc code_loc = MD_CodeLocFromNode(node); - MD_String8 message = MD_FormatMessage(scratch.arena, code_loc, kind, string); - fwrite(message.str, message.size, 1, file); - MD_ReleaseScratch(scratch); -} - #endif //~ Tree Comparison/Verification diff --git a/source/md.h b/source/md.h index df60afa..186474f 100644 --- a/source/md.h +++ b/source/md.h @@ -2,6 +2,8 @@ //~ Metadesk Library +// TODO(allen): Welcome & user directory comment here + #ifndef MD_H #define MD_H @@ -1117,8 +1119,6 @@ MD_FUNCTION void MD_PrintMessage(FILE *file, MD_CodeLoc loc, MD_MessageKind kind MD_String8 string); MD_FUNCTION void MD_PrintMessageFmt(FILE *file, MD_CodeLoc code_loc, MD_MessageKind kind, char *fmt, ...); -MD_FUNCTION void MD_PrintNodeMessageFmt(FILE *file, MD_Node *node, MD_MessageKind kind, - char *fmt, ...); #endif //~ Tree Comparison/Verification