diff --git a/source/md.h b/source/md.h index 07012c4..9dde566 100644 --- a/source/md.h +++ b/source/md.h @@ -19,6 +19,14 @@ // share the same key (important in the case of hash collisions) // [x] Helper for making a reference for a node, e.g. MD_ReferenceFromNode // [x] Organization decision for C generator helpers: splitting from md.h? file name? folder? +// [ ] Collapse down map types +// [ ] Fill in more String -> Integer helpers +// [ ] Memory Management Strategy +// [ ] Gather map of current memory management situation +// [ ] Reset all memory operation? +// [ ] Thread context? +// [ ] Scratch memory? +// [ ] Reference Manual // NOTE(allen): "Plugin" functionality // diff --git a/source/md_impl.c b/source/md_impl.c index 03e3cfa..0d13cba 100644 --- a/source/md_impl.c +++ b/source/md_impl.c @@ -1669,7 +1669,7 @@ MD_Parse_Set(MD_ParseCtx *ctx, MD_Node *parent, MD_ParseSetFlags flags) { MD_u8 *at_before_children = ctx->at; MD_NodeFlags next_child_flags = 0; - for(MD_u64 child_idx = 0;; child_idx += 1) + for(;;) { if(brace) { @@ -1978,19 +1978,46 @@ MD_ParseWholeString(MD_String8 filename, MD_String8 contents) MD_Node *root = MD_MakeNodeFromString(MD_NodeKind_File, filename, contents.str, contents.str, MD_PushStringF("`DD Parsed From \"%.*s\"`", MD_StringExpand(filename))); if(contents.size > 0) { - // NOTE(mal): Parse the content of the file as the inside of a set + // NOTE(allen): setup parse context MD_ParseCtx ctx = MD_Parse_InitializeCtx(filename, contents); - MD_NodeFlags next_child_flags = 0; + // NOTE(allen): setup namespace structure MD_Node *namespaces = _MD_MakeNodeFromString_Ctx(&ctx, MD_NodeKind_List, MD_S8Lit(""), ctx.at); MD_Node *default_namespace = _MD_MakeNodeFromString_Ctx(&ctx, MD_NodeKind_List, MD_S8Lit(""), ctx.at); MD_PushChild(namespaces, default_namespace); - MD_Node *selected_namespace = default_namespace; + MD_Map namespace_table = {0}; MD_StringMap_Insert(&namespace_table, MD_MapCollisionRule_Overwrite, default_namespace->string, default_namespace); - for(MD_u64 child_idx = 0;; child_idx += 1) + // NOTE(allen): setup namespace + MD_NodeFlags next_child_flags = 0; + MD_Node *selected_namespace = default_namespace; + for(;;) { + // TODO(allen): I don't get it... this can only happen once between + // each normal node? + // It feels to me like the picture of "ParseOneNode" and the full + // parse loop is underdeveloped all around. Namespaces can be in + // the full loop but not the single case. Why? What is the + // justification for that? If a new feature is added to the grammar + // how will we determine if it is or isn't in the "single" case? + // Are we sure there is no way to make sense of a namespace in the + // "single" case? + // If it turns out there really isn't a good way to + // namespace in the "single" case, we still need to think through + // how features that only appear in the full loop will be + // expressed. Right now the answer appears to just be "the loop + // will grow more gnarly with each feature". + // It might be useful to figure out an example of a second feature + // that would make sense outside of the "single" case (if this is + // indeed the right direction for namespaces to begin with). + // Suppose, finally, that there are reasons why we specifically + // want to disallow this in the single case *and* we want to + // disallow back-to-back namespaces, that still doesn't mean we + // want to disallow back-to-back `#` cases, right? And we'd want an + // actual error detection path for that rule too, right? Sorting + // these out "later" makes me nervous. + // NOTE(rjf): #-things (just namespaces right now, but can be used for other such // 'directives' in the future maybe) if(MD_Parse_Require(&ctx, MD_S8Lit("#"), MD_TokenKind_Symbol)) @@ -2026,6 +2053,7 @@ MD_ParseWholeString(MD_String8 filename, MD_String8 contents) } } + // NOTE(allen): parse the next node MD_ParseResult parse = MD_ParseOneNodeFromCtx(&ctx); MD_Node *child = parse.node; child->flags |= next_child_flags; diff --git a/tests/sanity_tests.c b/tests/sanity_tests.c index 271e6ae..e9cc8ef 100644 --- a/tests/sanity_tests.c +++ b/tests/sanity_tests.c @@ -641,5 +641,56 @@ int main(void) } + Test("Namespace") + { + char raw_text[] = + "Node;\n" + "#namespace foo\n" + "Node;\n" + "#namespace bar\n" + "Node;\n" + "#namespace foo\n" + "Object;\n" + "#namespace fiz\n" + "#namespace bar\n" + "Object;\n" + ; + MD_String8 text = MD_S8Lit(raw_text); + MD_String8 file_name = MD_S8Lit("namespace_raw_text"); + + MD_ParseResult result = MD_ParseWholeString(file_name, text); + MD_Node *namespaces = result.namespaces; + MD_Node *ns_default = MD_ChildFromString(namespaces, MD_S8Lit("")); + MD_Node *ns_foo = MD_ChildFromString(namespaces, MD_S8Lit("foo")); + MD_Node *ns_bar = MD_ChildFromString(namespaces, MD_S8Lit("bar")); + MD_Node *ns_fiz = MD_ChildFromString(namespaces, MD_S8Lit("fiz")); + TestResult(!MD_NodeIsNil(ns_foo)); + TestResult(!MD_NodeIsNil(ns_bar)); + TestResult(!MD_NodeIsNil(ns_fiz)); + + { + MD_Node *c0 = MD_ChildFromIndex(ns_default, 0); + TestResult(MD_StringMatch(c0->string, MD_S8Lit("Node"), 0)); + } + + { + MD_Node *c0 = MD_ChildFromIndex(ns_foo, 0); + MD_Node *c1 = MD_ChildFromIndex(ns_foo, 1); + TestResult(MD_StringMatch(c0->string, MD_S8Lit("Node"), 0)); + TestResult(MD_StringMatch(c1->string, MD_S8Lit("Object"), 0)); + } + + { + MD_Node *c0 = MD_ChildFromIndex(ns_bar, 0); + MD_Node *c1 = MD_ChildFromIndex(ns_bar, 1); + TestResult(MD_StringMatch(c0->string, MD_S8Lit("Node"), 0)); + TestResult(MD_StringMatch(c1->string, MD_S8Lit("Object"), 0)); + } + + { + TestResult(MD_NodeIsNil(ns_fiz->first_child)); + } + } + return 0; } \ No newline at end of file