MD_Node->at fix.

node->at now points to the first relevant character in the source .md file.
For namespaces and tags that is the first character of the identifier
(not the '#'/'@' symbols).
For labels it's the first character in node->whole_string if non-empty.
For unlabeled sets it's the opening '(', '[' or '{' character.
This commit is contained in:
Miguel Lechon
2021-03-16 09:19:02 +01:00
parent 52fdfdbc38
commit eb0cf0c9bf
2 changed files with 82 additions and 7 deletions
+10 -6
View File
@@ -1514,13 +1514,14 @@ _MD_MakeNode(MD_NodeKind kind, MD_String8 string, MD_String8 whole_string, MD_St
MD_PRIVATE_FUNCTION_IMPL MD_Node * MD_PRIVATE_FUNCTION_IMPL MD_Node *
_MD_MakeNodeFromToken_Ctx(MD_ParseCtx *ctx, MD_NodeKind kind, MD_Token token) _MD_MakeNodeFromToken_Ctx(MD_ParseCtx *ctx, MD_NodeKind kind, MD_Token token)
{ {
return _MD_MakeNode(kind, token.string, token.outer_string, ctx->filename, ctx->file_contents.str, ctx->at); return _MD_MakeNode(kind, token.string, token.outer_string, ctx->filename, ctx->file_contents.str,
token.outer_string.str);
} }
MD_PRIVATE_FUNCTION_IMPL MD_Node * MD_PRIVATE_FUNCTION_IMPL MD_Node *
_MD_MakeNodeFromString_Ctx(MD_ParseCtx *ctx, MD_NodeKind kind, MD_String8 string) _MD_MakeNodeFromString_Ctx(MD_ParseCtx *ctx, MD_NodeKind kind, MD_String8 string, MD_u8 *at)
{ {
return _MD_MakeNode(kind, string, string, ctx->filename, ctx->file_contents.str, ctx->at); return _MD_MakeNode(kind, string, string, ctx->filename, ctx->file_contents.str, at);
} }
typedef MD_u32 _MD_ParseSetFlags; typedef MD_u32 _MD_ParseSetFlags;
@@ -1638,7 +1639,8 @@ _MD_ParseOneNode(MD_ParseCtx *ctx)
MD_Parse_TokenMatch(next_token, MD_S8Lit("["), 0)) && MD_Parse_TokenMatch(next_token, MD_S8Lit("["), 0)) &&
next_token.kind == MD_TokenKind_Symbol ) next_token.kind == MD_TokenKind_Symbol )
{ {
result.node = _MD_MakeNodeFromString_Ctx(ctx, MD_NodeKind_Label, MD_S8Lit("")); result.node = _MD_MakeNodeFromString_Ctx(ctx, MD_NodeKind_Label, MD_S8Lit(""), next_token.outer_string.str);
_MD_ParseSet(ctx, result.node, _MD_ParseSet(ctx, result.node,
_MD_ParseSetFlag_Paren | _MD_ParseSetFlag_Paren |
_MD_ParseSetFlag_Brace | _MD_ParseSetFlag_Brace |
@@ -1655,7 +1657,8 @@ _MD_ParseOneNode(MD_ParseCtx *ctx)
MD_Parse_RequireKind(ctx, MD_TokenKind_CharLiteral, &token) || MD_Parse_RequireKind(ctx, MD_TokenKind_CharLiteral, &token) ||
MD_Parse_RequireKind(ctx, MD_TokenKind_Symbol, &token)) MD_Parse_RequireKind(ctx, MD_TokenKind_Symbol, &token))
{ {
result.node = MD_MakeNodeFromToken(MD_NodeKind_Label, ctx->filename, ctx->file_contents.str, ctx->at, token); result.node = MD_MakeNodeFromToken(MD_NodeKind_Label, ctx->filename, ctx->file_contents.str,
token.outer_string.str, token);
_MD_SetNodeFlagsByToken(result.node, token); _MD_SetNodeFlagsByToken(result.node, token);
if(token.kind == MD_TokenKind_CharLiteral || token.kind == MD_TokenKind_StringLiteral) if(token.kind == MD_TokenKind_CharLiteral || token.kind == MD_TokenKind_StringLiteral)
@@ -1975,7 +1978,8 @@ MD_ParseWholeString(MD_String8 filename, MD_String8 contents)
MD_NodeTableSlot *existing_namespace_slot = MD_NodeTable_Lookup(&ctx.namespace_table, token.string); MD_NodeTableSlot *existing_namespace_slot = MD_NodeTable_Lookup(&ctx.namespace_table, token.string);
if(existing_namespace_slot == 0) if(existing_namespace_slot == 0)
{ {
MD_Node *ns = _MD_MakeNodeFromString_Ctx(&ctx, MD_NodeKind_Namespace, token.string); MD_Node *ns = _MD_MakeNodeFromString_Ctx(&ctx, MD_NodeKind_Namespace, token.string,
token.outer_string.str);
MD_NodeTable_Insert(&ctx.namespace_table, MD_NodeTableCollisionRule_Overwrite, token.string, ns); MD_NodeTable_Insert(&ctx.namespace_table, MD_NodeTableCollisionRule_Overwrite, token.string, ns);
existing_namespace_slot = MD_NodeTable_Lookup(&ctx.namespace_table, token.string); existing_namespace_slot = MD_NodeTable_Lookup(&ctx.namespace_table, token.string);
} }
+71
View File
@@ -468,6 +468,65 @@ static int StringCompare(MD_String8 a, MD_String8 b)
return result; return result;
} }
static MD_Node *
FirstBadNodeAtPointer(MD_Node *node)
{
MD_Node *result = 0;
switch(node->kind){
case MD_NodeKind_File:
{
} break;
case MD_NodeKind_Label:
{
if(node->at != node->whole_string.str)
{
if(node->whole_string.size)
{
result = node;
}
else
{
if(!node->at || (node->at[0] != '(' && node->at[0] != '[' && node->at[0] != '{'))
{
result = node;
}
}
if(result)
{
goto end;
}
}
} break;
case MD_NodeKind_Namespace:
case MD_NodeKind_Tag:
{
if(node->at != node->whole_string.str)
{
result = node;
goto end;
}
} break;
default:
break;
}
for(MD_EachNode(child, node->first_child))
{
result = FirstBadNodeAtPointer(child);
if(result) goto end;
}
for(MD_EachNode(child, node->first_tag))
{
result = FirstBadNodeAtPointer(child);
if(result) goto end;
}
end:
return result;
}
int main(int argument_count, char **arguments) int main(int argument_count, char **arguments)
{ {
MD_Node *grammar = MD_ParseWholeFile(MD_S8Lit("tests/grammar.md")).node; MD_Node *grammar = MD_ParseWholeFile(MD_S8Lit("tests/grammar.md")).node;
@@ -701,6 +760,18 @@ int main(int argument_count, char **arguments)
MD_OutputTree(stdout, test->expected_output); printf("\n"); MD_OutputTree(stdout, test->expected_output); printf("\n");
return -1; return -1;
} }
MD_Node *bad_at_node = FirstBadNodeAtPointer(file_node);
if(bad_at_node)
{
printf("\nBad node->at on test %d\n", i_test);
printf("> %.*s <\n", MD_StringExpand(test->input));
printf("MD:\n");
MD_OutputTree(stdout, file_node);
printf("offending_node");
MD_OutputTree(stdout, bad_at_node);
return -1;
}
++i_test; ++i_test;
} }