mirror of
https://github.com/Ed94/metadesk.git
synced 2026-06-12 23:51:37 -07:00
116 lines
4.6 KiB
C
116 lines
4.6 KiB
C
/*
|
|
** Example: user errors
|
|
**
|
|
** This example shows how to print custom error messages.
|
|
**
|
|
** Pass user_errors.mdesk to see the custom messages in action.
|
|
**
|
|
** We will be adding two custom rules that check for certain properties of the
|
|
** top level nodes in a metadesk file:
|
|
** 1. No top level node should have multiple tags
|
|
** 2. Top level sets with brackets '[]' are expected to be unnamed
|
|
**
|
|
*/
|
|
|
|
//~ includes and globals //////////////////////////////////////////////////////
|
|
|
|
#include "md.h"
|
|
#include "md.c"
|
|
|
|
static MD_Arena *arena = 0;
|
|
|
|
|
|
//~ main //////////////////////////////////////////////////////////////////////
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
// setup the global arena
|
|
arena = MD_ArenaAlloc();
|
|
|
|
// parse all files passed to the command line
|
|
Node *list = MD_MakeList(arena);
|
|
for(int i = 1; i < argc; i += 1)
|
|
{
|
|
// parse the file
|
|
MD_String8 file_name = MD_S8CString(argv[i]);
|
|
ParseResult parse_result = MD_ParseWholeFile(arena, file_name);
|
|
|
|
// @notes Here we are printing out all the messages that came back from
|
|
// the parser. We could try to wait and print all the errors at once,
|
|
// or perform the custom checks in this block to put all the error
|
|
// output in a single place. But all that work deferring tasks or
|
|
// analyzing can quickly make things complicated. Out preferred method
|
|
// is to process the Metadesk file in stages. This is the parsing
|
|
// stage so this is where the parsing errors are reported. Custom
|
|
// errors get added in later stages whenever the analyzer finds them.
|
|
|
|
// print metadesk errors
|
|
for (MD_Message *message = parse_result.errors.first;
|
|
message != 0;
|
|
message = message->next)
|
|
{
|
|
MD_CodeLoc code_loc = MD_CodeLocFromNode(message->node);
|
|
MD_PrintMessage(stderr, code_loc, message->kind, message->string);
|
|
}
|
|
|
|
// save to parse results list
|
|
MD_PushNewReference(arena, list, parse_result.node);
|
|
}
|
|
|
|
// check for custom errors
|
|
for(each_node(ref, list->first_child))
|
|
{
|
|
Node *root = MD_ResolveNodeFromReference(ref);
|
|
|
|
// @notes The custom rules in this example apply to the top level nodes
|
|
// so we can check for them by visiting each node from the root.
|
|
// The example "type metadata" includes more advanced custom errors
|
|
// that are only discovered after more analysis.
|
|
for(each_node(node, root->first_child))
|
|
{
|
|
|
|
// top level node should have one or zero tags.
|
|
// @notes This helper gives us a way to treat the tags on `node`
|
|
// as an array and access it by index. If there's a tag at index 1
|
|
// then we know there are at least two tags, which is against
|
|
// the first custom rule.
|
|
Node *tag_2 = MD_TagFromIndex(node, 1);
|
|
if (!MD_NodeIsNil(tag_2))
|
|
{
|
|
// @notes The MD_PrintMessage helper formats a message for us
|
|
// with a filename and line number, and prints it to a FILE.
|
|
// We provide it with the coordinates with a MD_CodeLoc, which
|
|
// we can get from any metadesk node in the parse tree with
|
|
// the helper MD_CodeLoc. In this case we will get an error
|
|
// message pointed right at the offending tag.
|
|
//
|
|
// Messages don't have to be printed with MD_PrintMessage.
|
|
// In cases where the errors have a final destination other
|
|
// than a FILE, the message can be saved as a string with
|
|
// MD_FormatMessage.
|
|
MD_CodeLoc loc = MD_CodeLocFromNode(tag_2);
|
|
MD_PrintMessage(stderr, loc, MD_MessageKind_Error,
|
|
MD_S8Lit("Not supposed to have multiple tags."));
|
|
}
|
|
|
|
// top level sets with brackets should not have names
|
|
// @notes The second custom rule applies to sets with "[]"
|
|
// delimiters. We can easily detect nodes for those sets by
|
|
// checking the node flags:
|
|
if ((node->flags & NodeFlag_HasBracketLeft) ||
|
|
(node->flags & NodeFlag_HasBracketRight))
|
|
{
|
|
if (node->string.size > 0)
|
|
{
|
|
MD_CodeLoc loc = MD_CodeLocFromNode(node);
|
|
MD_PrintMessage(stderr, loc, MD_MessageKind_Error,
|
|
MD_S8Lit("Nodes with brackets should not have names."));
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|