[namespace] uncovered bug in parser; added test case for namespaces

This commit is contained in:
Allen Webster
2021-06-05 18:27:02 -07:00
parent d5d3b85492
commit 8e1b38e21f
3 changed files with 92 additions and 5 deletions
+8
View File
@@ -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
//
+33 -5
View File
@@ -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;
+51
View File
@@ -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;
}