From 701b77e11894b9bad61c0a8cf5ddd95be77b767e Mon Sep 17 00:00:00 2001 From: Miguel Lechon Date: Wed, 10 Mar 2021 18:32:29 +0100 Subject: [PATCH] Parsing errors for unbalanced sets and text literals. --- build.bat | 7 + build.sh | 9 +- build_with_clang.bat | 7 + samples/c_code_generation.c | 2 +- samples/node_errors/node_errors.c | 2 +- samples/old_style_custom_layer.c | 2 +- samples/output_parse/output_parse.c | 2 +- .../static_site_generator.c | 4 +- samples/syntax_errors/00.md | 1 + samples/syntax_errors/01.md | 1 + samples/syntax_errors/02.md | 1 + samples/syntax_errors/03.md | 1 + samples/syntax_errors/syntax_errors.c | 25 +++ source/md.h | 9 +- source/md_impl.c | 192 ++++++++++++++---- tests/grammar.c | 4 +- 16 files changed, 219 insertions(+), 50 deletions(-) create mode 100644 samples/syntax_errors/00.md create mode 100644 samples/syntax_errors/01.md create mode 100644 samples/syntax_errors/02.md create mode 100644 samples/syntax_errors/03.md create mode 100644 samples/syntax_errors/syntax_errors.c diff --git a/build.bat b/build.bat index 2462dab..6b4dd68 100644 --- a/build.bat +++ b/build.bat @@ -12,6 +12,7 @@ cl %compile_flags% ..\samples\static_site_generator\static_site_generator.c cl %compile_flags% ..\samples\output_parse\output_parse.c cl %compile_flags% ..\samples\c_code_generation.c cl %compile_flags% ..\samples\node_errors\node_errors.c +cl %compile_flags% ..\samples\syntax_errors\syntax_errors.c echo. echo ~~~ Build All Tests ~~~ cl %compile_flags% ..\tests\sanity_tests.c @@ -63,3 +64,9 @@ echo ~~~ Running Error Generation Sample ~~~ pushd build node_errors.exe %~dp0\samples\node_errors\node_errors.md popd + +echo. +echo ~~~ Running Syntax Error Detection and Reporting Sample ~~~ +pushd build +for /f "tokens=*" %%f in ('dir /s/b ..\samples\syntax_errors\*.md ^| sort') do syntax_errors.exe %%f +popd diff --git a/build.sh b/build.sh index cf8e298..db9df47 100755 --- a/build.sh +++ b/build.sh @@ -24,6 +24,7 @@ $CC $compile_flags ../samples/static_site_generator/static_site_generator.c -o s $CC $compile_flags ../samples/output_parse/output_parse.c -o output_parse $CC $compile_flags ../samples/c_code_generation.c -o c_code_generation $CC $compile_flags ../samples/node_errors/node_errors.c -o node_errors +$CC $compile_flags ../samples/syntax_errors/syntax_errors.c -o syntax_errors echo echo ~~~ Build All Tests ~~~ $CC $compile_flags ../tests/sanity_tests.c -o sanity_tests @@ -58,9 +59,15 @@ pushd build ./c_code_generation popd -echo. +echo echo ~~~ Running Error Generation Sample ~~~ pushd build ./node_errors ../samples/node_errors/node_errors.md popd +echo +echo ~~~ Running Syntax Error Detection and Reporting Sample ~~~ +pushd build +./syntax_errors ../samples/syntax_errors/*.md +popd + diff --git a/build_with_clang.bat b/build_with_clang.bat index 155b415..9a2e496 100644 --- a/build_with_clang.bat +++ b/build_with_clang.bat @@ -14,6 +14,7 @@ clang %compile_flags% ..\samples\static_site_generator\static_site_generator.c - clang %compile_flags% ..\samples\output_parse\output_parse.c -o output_parse.exe clang %compile_flags% ..\samples\c_code_generation.c -o c_code_generation.exe clang %compile_flags% ..\samples\node_errors\node_errors.c -o node_errors.exe +clang %compile_flags% ..\samples\syntax_errors\syntax_errors.c -o syntax_errors.exe echo. echo ~~~ Build All Tests ~~~ clang %compile_flags% ..\tests\sanity_tests.c -o sanity_tests.exe @@ -65,3 +66,9 @@ echo ~~~ Running Error Generation Sample ~~~ pushd build node_errors.exe %~dp0\samples\node_errors\node_errors.md popd + +echo. +echo ~~~ Running Syntax Error Detection and Reporting Sample ~~~ +pushd build +for /f "tokens=*" %%f in ('dir /s/b ..\samples\syntax_errors\*.md ^| sort') do syntax_errors.exe %%f +popd diff --git a/samples/c_code_generation.c b/samples/c_code_generation.c index 36698e0..2145b64 100644 --- a/samples/c_code_generation.c +++ b/samples/c_code_generation.c @@ -16,7 +16,7 @@ int main(int argument_count, char **arguments) " f: ([4 + 5]S32),\n" " g: ([FOO + BAR]I32),\n" "}\n\n"); - MD_Node *code = MD_ParseWholeString(MD_S8Lit("Generated Test Code"), example_code); + MD_Node *code = MD_ParseWholeString(MD_S8Lit("Generated Test Code"), example_code).node; printf("Source Metadesk Code:\n"); printf("%.*s\n\n", MD_StringExpand(example_code)); diff --git a/samples/node_errors/node_errors.c b/samples/node_errors/node_errors.c index b2bf971..255694c 100644 --- a/samples/node_errors/node_errors.c +++ b/samples/node_errors/node_errors.c @@ -10,7 +10,7 @@ int main(int argument_count, char **arguments) MD_Node *last = MD_NilNode(); for(int i = 1; i < argument_count; i += 1) { - MD_Node *root = MD_ParseWholeFile(MD_S8CString(arguments[i])); + MD_Node *root = MD_ParseWholeFile(MD_S8CString(arguments[i])).node; MD_PushSibling(&first, &last, MD_NilNode(), root); } diff --git a/samples/old_style_custom_layer.c b/samples/old_style_custom_layer.c index ca8f82a..ef12f97 100644 --- a/samples/old_style_custom_layer.c +++ b/samples/old_style_custom_layer.c @@ -28,7 +28,7 @@ int main(int argument_count, char **arguments) MD_Node *last = MD_NilNode(); for(int i = 1; i < argument_count; i += 1) { - MD_Node *root = MD_ParseWholeFile(MD_S8CString(arguments[i])); + MD_Node *root = MD_ParseWholeFile(MD_S8CString(arguments[i])).node; MD_PushSibling(&first, &last, MD_NilNode(), root); } diff --git a/samples/output_parse/output_parse.c b/samples/output_parse/output_parse.c index 4a2ed6d..e1035aa 100644 --- a/samples/output_parse/output_parse.c +++ b/samples/output_parse/output_parse.c @@ -63,7 +63,7 @@ int main(int argument_count, char **arguments) MD_Node *last = MD_NilNode(); for(int i = 1; i < argument_count; i += 1) { - MD_Node *root = MD_ParseWholeFile(MD_S8CString(arguments[i])); + MD_Node *root = MD_ParseWholeFile(MD_S8CString(arguments[i])).node; MD_PushSibling(&first, &last, MD_NilNode(), root); } diff --git a/samples/static_site_generator/static_site_generator.c b/samples/static_site_generator/static_site_generator.c index 25c80b9..ccb27b7 100644 --- a/samples/static_site_generator/static_site_generator.c +++ b/samples/static_site_generator/static_site_generator.c @@ -51,7 +51,7 @@ int main(int argument_count, char **arguments) SiteInfo site_info = {0}; { printf("Parsing site metadata at \"%.*s\"...\n", MD_StringExpand(site_info_path)); - MD_Node *site_info_file = MD_ParseWholeFile(site_info_path); + MD_Node *site_info_file = MD_ParseWholeFile(site_info_path).node; site_info = ParseSiteInfo(site_info_file); } @@ -74,7 +74,7 @@ int main(int argument_count, char **arguments) MD_String8 path = MD_PushStringF("%.*s/%.*s", MD_StringExpand(folder), MD_StringExpand(file_info.filename)); - MD_PushSibling(&first_root, &last_root, MD_NilNode(), MD_ParseWholeFile(path)); + MD_PushSibling(&first_root, &last_root, MD_NilNode(), MD_ParseWholeFile(path).node); } } } diff --git a/samples/syntax_errors/00.md b/samples/syntax_errors/00.md new file mode 100644 index 0000000..98232c6 --- /dev/null +++ b/samples/syntax_errors/00.md @@ -0,0 +1 @@ +{ diff --git a/samples/syntax_errors/01.md b/samples/syntax_errors/01.md new file mode 100644 index 0000000..2d06f37 --- /dev/null +++ b/samples/syntax_errors/01.md @@ -0,0 +1 @@ +( diff --git a/samples/syntax_errors/02.md b/samples/syntax_errors/02.md new file mode 100644 index 0000000..5c34318 --- /dev/null +++ b/samples/syntax_errors/02.md @@ -0,0 +1 @@ +} diff --git a/samples/syntax_errors/03.md b/samples/syntax_errors/03.md new file mode 100644 index 0000000..eef843b --- /dev/null +++ b/samples/syntax_errors/03.md @@ -0,0 +1 @@ +' diff --git a/samples/syntax_errors/syntax_errors.c b/samples/syntax_errors/syntax_errors.c new file mode 100644 index 0000000..c446baa --- /dev/null +++ b/samples/syntax_errors/syntax_errors.c @@ -0,0 +1,25 @@ +// Sample code to demonstrate syntax error detection and reporting + +#include "md.h" +#include "md.c" + +int main(int argument_count, char **arguments) +{ + for(int i = 1; i < argument_count; i += 1) + { + MD_ParseResult parse = MD_ParseWholeFile(MD_S8CString(arguments[i])); + if(parse.first_error) + { + for(MD_Error *error = parse.first_error; error; error = error->next) + { + MD_OutputError(stderr, error); + } + } + else + { + printf("No error in file %s\n", arguments[i]); + } + } + + return 0; +} diff --git a/source/md.h b/source/md.h index 52a5bce..588d3e0 100644 --- a/source/md.h +++ b/source/md.h @@ -482,6 +482,8 @@ struct MD_Error MD_String8 string; MD_String8 filename; MD_Node *node; + MD_b32 catastrophic; + MD_CodeLoc location; }; typedef struct MD_ParseCtx MD_ParseCtx; @@ -496,6 +498,7 @@ struct MD_ParseCtx MD_String8 file_contents; MD_NodeTable namespace_table; MD_Node *selected_namespace; + MD_b32 catastrophic_error; }; typedef struct MD_ParseResult MD_ParseResult; @@ -619,6 +622,7 @@ MD_FUNCTION MD_b32 MD_CharIsAlphaUpper(MD_u8 c); MD_FUNCTION MD_b32 MD_CharIsAlphaLower(MD_u8 c); MD_FUNCTION MD_b32 MD_CharIsDigit(MD_u8 c); MD_FUNCTION MD_b32 MD_CharIsSymbol(MD_u8 c); +MD_FUNCTION MD_b32 MD_CharIsReservedSymbol(MD_u8 c); MD_FUNCTION MD_b32 MD_CharIsSpace(MD_u8 c); MD_FUNCTION MD_u8 MD_CharToUpper(MD_u8 c); MD_FUNCTION MD_u8 MD_CharToLower(MD_u8 c); @@ -707,8 +711,8 @@ MD_FUNCTION MD_b32 MD_Parse_TokenMatch(MD_Token token, MD_String8 string MD_FUNCTION MD_b32 MD_Parse_Require(MD_ParseCtx *ctx, MD_String8 string, MD_TokenKind kind); MD_FUNCTION MD_b32 MD_Parse_RequireKind(MD_ParseCtx *ctx, MD_TokenKind kind, MD_Token *out_token); MD_FUNCTION MD_ParseResult MD_ParseOneNode (MD_String8 filename, MD_String8 contents); -MD_FUNCTION MD_Node * MD_ParseWholeString (MD_String8 filename, MD_String8 contents); -MD_FUNCTION MD_Node * MD_ParseWholeFile (MD_String8 filename); +MD_FUNCTION MD_ParseResult MD_ParseWholeString (MD_String8 filename, MD_String8 contents); +MD_FUNCTION MD_ParseResult MD_ParseWholeFile (MD_String8 filename); //~ Tree/List Building MD_FUNCTION MD_b32 MD_NodeIsNil(MD_Node *node); @@ -745,6 +749,7 @@ MD_FUNCTION void MD_NodeWarning(MD_Node *node, MD_String8 str); MD_FUNCTION void MD_NodeMessageF(MD_Node *node, MD_MessageKind kind, char *fmt, ...); MD_FUNCTION void MD_NodeErrorF(MD_Node *node, char *fmt, ...); MD_FUNCTION void MD_NodeWarningF(MD_Node *node, char *fmt, ...); +MD_FUNCTION void MD_OutputError(FILE *f, MD_Error *error); //~ Tree Comparison/Verification MD_FUNCTION MD_b32 MD_NodeMatch(MD_Node *a, MD_Node *b, MD_StringMatchFlags str_flags, MD_NodeMatchFlags node_flags); diff --git a/source/md_impl.c b/source/md_impl.c index 24d0a6e..e005dca 100644 --- a/source/md_impl.c +++ b/source/md_impl.c @@ -110,6 +110,13 @@ MD_CharIsSymbol(MD_u8 c) c == '?' || c == '|' || c == '\\'); } +MD_FUNCTION_IMPL MD_b32 +MD_CharIsReservedSymbol(MD_u8 c) +{ + return (c == '{' || c == '}' || c == '(' || c == ')' || + c == '[' || c == ']' || c == '#'); +} + MD_FUNCTION_IMPL MD_b32 MD_CharIsSpace(MD_u8 c) { @@ -1091,6 +1098,23 @@ MD_TokenizerScanEscaped(MD_u8 *at, MD_u8 *one_past_last, MD_u8 c) return at; } +MD_PRIVATE_FUNCTION_IMPL MD_u32 +_MD_ComputeTextLiteralChop(MD_u32 bytes_to_skip, MD_u8 *beg, MD_u8 *end) +{ + // NOTE(mal): By counting the bytes to chop off text literals and encoding exact token.string and + // token.outer_string we delegate the responsibility of generating errors to the parser + // That way, we can avoid generating errors during peeks and save them for actual token + // consumption. That allows predictable error ordering. + MD_u32 result = 0; + MD_u8 *skip_end = beg + bytes_to_skip; + MD_u8 *chop_beg = end - bytes_to_skip; + if(skip_end <= chop_beg && MD_StringMatch(MD_S8(beg, bytes_to_skip), MD_S8(chop_beg, bytes_to_skip), 0)) + { + result = bytes_to_skip; + } + return result; +} + MD_FUNCTION_IMPL MD_Token MD_Parse_LexNext(MD_ParseCtx *ctx) { @@ -1184,17 +1208,18 @@ MD_Parse_LexNext(MD_ParseCtx *ctx) token.kind = MD_TokenKind_StringLiteral; if (at + 2 < one_past_last && at[1] == '`' && at[2] == '`') { - skip_n = chop_n = 3; + skip_n = 3; at += 3; MD_TokenizerScan(!(at + 2 < one_past_last && at[0] == '`' && at[1] == '`' && at[2] == '`')); at += 3; } else { - skip_n = chop_n = 1; + skip_n = 1; at += 1; at = MD_TokenizerScanEscaped(at, one_past_last, '`'); } + chop_n = _MD_ComputeTextLiteralChop(skip_n, first, at); }break; // NOTE(allen): Strings @@ -1203,17 +1228,18 @@ MD_Parse_LexNext(MD_ParseCtx *ctx) token.kind = MD_TokenKind_StringLiteral; if (at + 2 < one_past_last && at[1] == '"' && at[2] == '"') { - skip_n = chop_n = 3; + skip_n = 3; at += 3; MD_TokenizerScan(!(at + 2 < one_past_last && at[0] == '"' && at[1] == '"' && at[2] == '"')); at += 3; } else { - skip_n = chop_n = 1; + skip_n = 1; at += 1; at = MD_TokenizerScanEscaped(at, one_past_last, '"'); } + chop_n = _MD_ComputeTextLiteralChop(skip_n, first, at); }break; case '\'': @@ -1221,7 +1247,7 @@ MD_Parse_LexNext(MD_ParseCtx *ctx) if (at + 2 < one_past_last && at[1] == '\'' && at[2] == '\'') { token.kind = MD_TokenKind_StringLiteral; - skip_n = chop_n = 3; + skip_n = 3; at += 3; MD_TokenizerScan(!(at + 2 < one_past_last && at[0] == '\'' && at[1] == '\'' && at[2] == '\'')); at += 3; @@ -1229,10 +1255,11 @@ MD_Parse_LexNext(MD_ParseCtx *ctx) else { token.kind = MD_TokenKind_CharLiteral; - skip_n = chop_n = 1; + skip_n = 1; at += 1; at = MD_TokenizerScanEscaped(at, one_past_last, '\''); } + chop_n = _MD_ComputeTextLiteralChop(skip_n, first, at); }break; // NOTE(allen): Identifiers, Numbers, Operators @@ -1362,15 +1389,62 @@ MD_Parse_RequireKind(MD_ParseCtx *ctx, MD_TokenKind kind, MD_Token *out_token) return result; } -MD_PRIVATE_FUNCTION_IMPL void -_MD_Error(MD_ParseCtx *ctx, char *fmt, ...) +MD_PRIVATE_FUNCTION_IMPL MD_CodeLoc +_MD_CodeLocFromFileOffset(MD_String8 filename, MD_u8 * file_contents, MD_u8 *at) { - MD_Error *error = _MD_PushArray(_MD_GetCtx(), MD_Error, 1); - error->filename = ctx->filename; - va_list args; - va_start(args, fmt); - error->string = MD_PushStringFV(fmt, args); - va_end(args); + MD_CodeLoc loc; + loc.filename = filename; + loc.line = 1; + loc.column = 1; + for(MD_u64 i = 0; file_contents[i]; i += 1) + { + if(file_contents[i] == '\n') + { + loc.line += 1; + loc.column = 1; + } + else + { + loc.column += 1; + } + if(file_contents + i >= at) + { + break; + } + } + return loc; +} + +MD_PRIVATE_FUNCTION_IMPL void +_MD_Error(MD_ParseCtx *ctx, MD_Node *node, MD_u8 *at, MD_b32 catastrophic, char *fmt, ...) +{ + if(!ctx->catastrophic_error) // NOTE(mal): Can't trust parsing errors after first catastrophic error + { + MD_Error *error = _MD_PushArray(_MD_GetCtx(), MD_Error, 1); + error->node = node; + error->catastrophic = catastrophic; + error->location = _MD_CodeLocFromFileOffset(ctx->filename, ctx->file_contents.str, at-1); + error->filename = ctx->filename; + va_list args; + va_start(args, fmt); + error->string = MD_PushStringFV(fmt, args); + va_end(args); + + if(ctx->last_error) + { + ctx->last_error->next = error; + ctx->last_error = error; + } + else + { + ctx->first_error = ctx->last_error = error; + } + + if(catastrophic) + { + ctx->catastrophic_error = 1; + } + } } MD_PRIVATE_FUNCTION_IMPL MD_Node * @@ -1431,6 +1505,16 @@ _MD_SetNodeFlagsByToken(MD_Node *node, MD_Token token) #undef Flag } +MD_PRIVATE_FUNCTION_IMPL MD_b32 +_MD_StringLiteralIsBalanced(MD_Token token) +{ + MD_b32 result = 0; + MD_u64 front_len = token.string.str - token.outer_string.str; + MD_u64 back_len = (token.outer_string.str + token.outer_string.size) - (token.string.str + token.string.size); + result = (front_len == back_len); + return result; +} + MD_PRIVATE_FUNCTION_IMPL MD_ParseResult _MD_ParseOneNode(MD_ParseCtx *ctx) { @@ -1542,6 +1626,31 @@ _MD_ParseOneNode(MD_ParseCtx *ctx) { result.node = MD_MakeNodeFromToken(MD_NodeKind_Label, ctx->filename, ctx->file_contents.str, ctx->at, token); _MD_SetNodeFlagsByToken(result.node, token); + + if(token.kind == MD_TokenKind_CharLiteral || token.kind == MD_TokenKind_StringLiteral) + { + if(!_MD_StringLiteralIsBalanced(token)) + { + _MD_Error(ctx, result.node, at_first, 1, "Unbalanced text literal \"%.*s\"", + MD_StringExpand(token.outer_string)); + } + } + else if(token.kind == MD_TokenKind_Symbol && token.string.size == 1 && MD_CharIsReservedSymbol(token.string.str[0])) + { + MD_u8 c = token.string.str[0]; + const char *error_message = 0; + if(c == '}' || c == ']' || c == ')') + { + error_message = "Unbalanced"; + } + else + { + error_message = "Unexpected reserved symbol"; + } + + _MD_Error(ctx, result.node, at_first, 1, "%s \"%c\"", error_message, c); + } + // NOTE(rjf): Children if(MD_Parse_Require(ctx, MD_S8Lit(":"), MD_TokenKind_Symbol)) { @@ -1587,9 +1696,10 @@ _MD_ParseOneNode(MD_ParseCtx *ctx) comment_after = comment_token.string; } + result.bytes_parsed = (MD_u64)(ctx->at - at_first); + if(!MD_NodeIsNil(result.node)) { - result.bytes_parsed = (MD_u64)(ctx->at - at_first); result.node->first_tag = first_tag; result.node->last_tag = last_tag; for(MD_Node *tag = first_tag; !MD_NodeIsNil(tag); tag = tag->next) @@ -1671,13 +1781,21 @@ _MD_ParseSet(MD_ParseCtx *ctx, MD_Node *parent, _MD_ParseSetFlags flags, goto end_parse; } } - + MD_ParseResult parse = _MD_ParseOneNode(ctx); MD_Node *child = parse.node; child->flags |= next_child_flags; next_child_flags = 0; if(MD_NodeIsNil(child)) { + if(brace || paren || bracket) + { + char delimiter_char = 0; + if(brace) delimiter_char = '{'; + else if(paren) delimiter_char = '('; + else if(bracket) delimiter_char = '['; + _MD_Error(ctx, parse.node, ctx->at - parse.bytes_parsed, 1, "Unbalanced \"%c\"", delimiter_char); + } goto end_parse; } else @@ -1771,9 +1889,10 @@ MD_ParseOneNode(MD_String8 filename, MD_String8 contents) return _MD_ParseOneNode(&ctx); } -MD_FUNCTION MD_Node * +MD_FUNCTION MD_ParseResult MD_ParseWholeString(MD_String8 filename, MD_String8 contents) { + MD_ParseResult result = MD_ZERO_STRUCT; 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) { @@ -1806,11 +1925,14 @@ MD_ParseWholeString(MD_String8 filename, MD_String8 contents) next_child_flags |= MD_NodeFlag_AfterSemicolon; } } + result.bytes_parsed = (MD_u64)(ctx.at - contents.str); + result.first_error = ctx.first_error; } - return root; + result.node = root; + return result; } -MD_FUNCTION_IMPL MD_Node * +MD_FUNCTION_IMPL MD_ParseResult MD_ParseWholeFile(MD_String8 filename) { return MD_ParseWholeString(filename, MD_LoadEntireFile(filename)); @@ -2020,26 +2142,7 @@ MD_NodeHasTag(MD_Node *node, MD_String8 tag_string) MD_FUNCTION_IMPL MD_CodeLoc MD_CodeLocFromNode(MD_Node *node) { - MD_CodeLoc loc; - loc.filename = node->filename; - loc.line = 1; - loc.column = 1; - for(MD_u64 i = 0; node->file_contents[i]; i += 1) - { - if(node->file_contents[i] == '\n') - { - loc.line += 1; - loc.column = 1; - } - else - { - loc.column += 1; - } - if(node->file_contents + i == node->at) - { - break; - } - } + MD_CodeLoc loc = _MD_CodeLocFromFileOffset(node->filename, node->file_contents, node->at); return loc; } @@ -2144,6 +2247,17 @@ MD_NodeWarningF(MD_Node *node, char *fmt, ...) va_end(args); } +MD_FUNCTION_IMPL void +MD_OutputError(FILE *f, MD_Error *error) +{ + const char *kind_name = "error"; + fprintf(stderr, "%.*s:%i:%i: %s: %.*s\n", + MD_StringExpand(error->location.filename), + error->location.line, error->location.column, + kind_name, + MD_StringExpand(error->string)); +} + MD_GLOBAL MD_Expr _md_nil_expr = { &_md_nil_node, diff --git a/tests/grammar.c b/tests/grammar.c index d3b9060..de74a29 100644 --- a/tests/grammar.c +++ b/tests/grammar.c @@ -473,7 +473,7 @@ static int StringCompare(MD_String8 a, MD_String8 b) int main(int argument_count, char **arguments) { - MD_Node *grammar = MD_ParseWholeFile(MD_S8Lit("tests/grammar.md")); + MD_Node *grammar = MD_ParseWholeFile(MD_S8Lit("tests/grammar.md")).node; // NOTE(mal): In order to get a BNF-like syntax, I feed the MD output through two transformations: // 1) Tag []-style sets as optional @@ -688,7 +688,7 @@ int main(int argument_count, char **arguments) MD_u32 i_test = 0; for(Test *test = first_test; test; test = test->next) { - MD_Node *file_node = MD_ParseWholeString(MD_S8Lit(""), test->input); + MD_Node *file_node = MD_ParseWholeString(MD_S8Lit(""), test->input).node; file_node->string = file_node->whole_string = (MD_String8){0}; #if DEBUG_PRINT_GENERATED_TESTS