/* 
** 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 //////////////////////////////////////////////////////

#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 recommended approach.
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
        // @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(argv[i]);
        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
    // @notes The Metadesk library provides a macros for iterating chains of
    //  Node as shown here. The first parameter to the macro names an
    //  Node pointer in the for loop that iterates through each node in the
    //  list. The second parameter is a pointer to the first node of the list.
    //  Generally we past the `first_child` of a list or parent Node, but we
    //  don't always have to.
    for (each_node(root_it, list->first_child))
    {
        
        // @notes The `list` we have been building does not contain a normal
        //  Node chain like in the trees returned from the parser. Instead
        //  it contains a chain of 'reference' nodes, which can point to any
        //  metadesk node from a previous parse. So our `root_it` is iterating
        //  a list of reference nodes. Here we resolve the reference node to
        //  get the root of the parse tree.
        Node *root = MD_ResolveNodeFromReference(root_it);
        
        for (each_node(node, root->first_child))
        {
            // @notes The Metadesk library likes to use MD_String8List for
            //  functions that build and return big strings. This simplifies
            //  memory management for big strings, and means a series of string
            //  builders can be called back to back and gathered into one list.
            //  When the string needs to be finalized into a single contiguous
            //  block a user can just call `MD_S8ListJoin` as shown here.
            MD_String8List stream = {0};
            MD_DebugDumpFromNode(arena, &stream, node, 0, MD_S8Lit(" "), MD_GenerateFlags_Tree);
            MD_String8 str = MD_S8ListJoin(arena, stream, 0);
            fwrite(str.str, str.size, 1, stdout);
            fwrite("\n", 1, 1, stdout);
        }
    }
    
    return 0;
}
