Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Example: Toml AST #98

Merged
merged 13 commits into from Aug 15, 2021
357 changes: 333 additions & 24 deletions examples/toml.h

Large diffs are not rendered by default.

48 changes: 30 additions & 18 deletions peppapeg.c
Expand Up @@ -660,6 +660,7 @@ P4_PRIVATE(P4_Node*) match_repeat(P4_Source*, P4_Expression*);
P4_PRIVATE(P4_Node*) match_spaced_rules(P4_Source*, P4_Expression*);
P4_PRIVATE(P4_Node*) match_back_reference(P4_Source*, P4_Expression*, P4_Slice*, P4_Expression*);

P4_PRIVATE(void) P4_DeleteNodeUserData(P4_Grammar* grammar, P4_Node* node);
P4_PRIVATE(P4_Expression*) P4_GetReference(P4_Source*, P4_Expression*);

P4_PRIVATE(P4_String) P4_CopySliceString(P4_String, P4_Slice*);
Expand Down Expand Up @@ -1600,6 +1601,7 @@ P4_CreateNode (const P4_String str,
node->next = NULL;
node->head = NULL;
node->tail = NULL;
node->userdata = NULL;

set_slice(&node->slice, start, stop);

Expand All @@ -1613,16 +1615,19 @@ P4_CreateNode (const P4_String str,
* DANGER: this function does not free children nodes.
*/
P4_PRIVATE(void)
P4_DeleteNodeNode(P4_Node* node) {
if (node) P4_FREE(node);
P4_DeleteNodeNode(P4_Grammar* grammar, P4_Node* node) {
if (node) {
P4_DeleteNodeUserData(grammar, node);
P4_FREE(node);
}
}


/*
* Free all of the children nodes of the node.
*/
P4_PRIVATE(void)
P4_DeleteNodeChildren(P4_Node* node) {
P4_PUBLIC void
P4_DeleteNodeChildren(P4_Grammar* grammar, P4_Node* node) {
if (node == NULL)
return;

Expand All @@ -1632,10 +1637,11 @@ P4_DeleteNodeChildren(P4_Node* node) {
while (child) {
tmp = child->next;
if (child->head)
P4_DeleteNodeChildren(child);
P4_DeleteNodeNode(child);
P4_DeleteNodeChildren(grammar, child);
P4_DeleteNodeNode(grammar, child);
child = tmp;
}
node->head = node->tail = NULL;
}


Expand All @@ -1644,12 +1650,12 @@ P4_DeleteNodeChildren(P4_Node* node) {
* node in the node list.
*/
P4_PUBLIC void
P4_DeleteNode(P4_Node* node) {
P4_DeleteNode(P4_Grammar* grammar, P4_Node* node) {
P4_Node* tmp = NULL;
while (node) {
tmp = node->next;
P4_DeleteNodeChildren(node);
P4_DeleteNodeNode(node);
P4_DeleteNodeChildren(grammar, node);
P4_DeleteNodeNode(grammar, node);
node = tmp;
}
}
Expand All @@ -1661,8 +1667,10 @@ P4_DeleteNodeUserData(P4_Grammar* grammar, P4_Node* node) {

P4_Node* tmp = node;
while (tmp != NULL) {
if (tmp->userdata != NULL)
if (tmp->userdata != NULL) {
grammar->free_func(tmp->userdata);
tmp->userdata = NULL;
}
P4_DeleteNodeUserData(grammar, tmp->head);
tmp = tmp->next;
}
Expand Down Expand Up @@ -1959,7 +1967,7 @@ match_sequence(P4_Source* s, P4_Expression* e) {

finalize:
set_position(s, startpos);
P4_DeleteNode(head);
P4_DeleteNode(s->grammar, head);
return NULL;
}

Expand Down Expand Up @@ -2136,7 +2144,7 @@ match_repeat(P4_Source* s, P4_Expression* e) {
/* nodes between head..tail should be freed. */
finalize:
set_position(s, startpos);
P4_DeleteNode(head);
P4_DeleteNode(s->grammar, head);
return NULL;
}

Expand All @@ -2148,7 +2156,7 @@ match_positive(P4_Source* s, P4_Expression* e) {

P4_Node* node = match_expression(s, e->ref_expr);
if (node != NULL)
P4_DeleteNode(node);
P4_DeleteNode(s->grammar, node);

set_position(s, startpos);

Expand All @@ -2164,7 +2172,7 @@ match_negative(P4_Source* s, P4_Expression* e) {
set_position(s, startpos);

if (no_error(s)) {
P4_DeleteNode(node);
P4_DeleteNode(s->grammar, node);
P4_MatchRaisef(s, P4_MatchError, "expect %s", peek_rule_name(s));
} else if (s->err == P4_MatchError || s->err == P4_CutError) {
rescue_error(s);
Expand Down Expand Up @@ -2243,7 +2251,7 @@ match_expression(P4_Source* s, P4_Expression* e) {
}

/* clean up */
P4_DeleteNode(result);
P4_DeleteNode(s->grammar, result);
if (e->name != NULL && s->errmsg[0] == 0) {
P4_MatchRaisef(s, s->err, "expect %s", e->name);
}
Expand Down Expand Up @@ -2336,16 +2344,20 @@ match_back_reference(P4_Source* s, P4_Expression* e, P4_Slice* backrefs, P4_Expr
}

void
P4_JsonifySourceAst(FILE* stream, P4_Node* node) {
P4_JsonifySourceAst(FILE* stream, P4_Node* node,
void (*formatter)(FILE* stream, P4_Node* node)) {
P4_Node* tmp = node;

fprintf(stream, "[");
while (tmp != NULL) {
fprintf(stream, "{\"slice\":[%lu,%lu]", tmp->slice.start.pos, tmp->slice.stop.pos);
fprintf(stream, ",\"type\":\"%s\"", tmp->rule_name);
if (formatter != NULL) {
formatter(stream, tmp);
}
if (tmp->head != NULL) {
fprintf(stream, ",\"children\":");
P4_JsonifySourceAst(stream, tmp->head);
P4_JsonifySourceAst(stream, tmp->head, formatter);
}
fprintf(stream, "}");
if (tmp->next != NULL) fprintf(stream, ",");
Expand Down Expand Up @@ -2803,7 +2815,7 @@ P4_ResetSource(P4_Source* source) {

if (source->root) {
P4_DeleteNodeUserData(source->grammar, source->root);
P4_DeleteNode(source->root);
P4_DeleteNode(source->grammar, source->root);
}

}
Expand Down
28 changes: 21 additions & 7 deletions peppapeg.h
Expand Up @@ -1450,7 +1450,7 @@ P4_Node* P4_GetSourceAst(P4_Source* source);
*
* P4_Node* root = P4_AcquireSourceAst(source);
* // ...
* P4_DeleteNode(root);
* P4_DeleteNode(grammar, root);
*/
P4_Node* P4_AcquireSourceAst(P4_Source* source);

Expand All @@ -1463,15 +1463,16 @@ size_t P4_GetSourcePosition(P4_Source* source);

/**
* @brief Print the node tree.
* @param stream The output stream.
* @param stream The output stream.
* @param node The root node of source ast.
* *param formatter A callback function to format node.
*
* Example:
*
* P4_Node* root = P4_GetSourceAst(source);
* P4_JsonifySourceAst(stdout, root);
*/
void P4_JsonifySourceAst(FILE* stream, P4_Node* node);
void P4_JsonifySourceAst(FILE* stream, P4_Node* node, void (*formatter)(FILE* stream, P4_Node* node));

/**
* @brief Inspect the node tree.
Expand Down Expand Up @@ -1577,21 +1578,34 @@ P4_String P4_GetErrorMessage(P4_Source* source);
*
* // do something.
*
* P4_DeleteNode(node);
* P4_DeleteNode(grammar, node);
*/
P4_Node* P4_CreateNode(P4_String text, P4_Position* start, P4_Position* stop, P4_String rule);

/**
* @brief Delete the node.
* This will free the occupied memory for node.
* The str of the node won't be free-ed since the node only owns not the string but the slice of a string.
* @param node The node.
* @param grammar The grammar.
* @param node The node.
*
* Example:
*
* P4_DeleteNode(grammar, node);
*/
void P4_DeleteNode(P4_Grammar* grammar, P4_Node* node);

/**
* @brief Delete the node children.
* This will free the occupied memory for all node children.
* @param grammar The grammar.
* @param node The node.
*
* Example:
*
* P4_DeleteNode(node);
* P4_DeleteNodeChildren(grammar, node);
*/
void P4_DeleteNode(P4_Node* node);
void P4_DeleteNodeChildren(P4_Grammar* grammar, P4_Node* node);

/**
* @brief Get the slice that the node covers.
Expand Down
2 changes: 1 addition & 1 deletion tests/test_example_dot.c
Expand Up @@ -10,7 +10,7 @@
TEST_ASSERT_EQUAL_MESSAGE((code), P4_Parse(grammar, source), "unexpected parse grammar return code"); \
P4_Node* root = P4_GetSourceAst(source); \
FILE *f = fopen("check.json","w"); \
P4_JsonifySourceAst(f, root); \
P4_JsonifySourceAst(f, root, NULL); \
fclose(f); \
P4_String s = read_file("check.json"); \
TEST_ASSERT_EQUAL_STRING((output), s); \
Expand Down
52 changes: 32 additions & 20 deletions tests/test_example_toml.c
Expand Up @@ -10,7 +10,7 @@
TEST_ASSERT_EQUAL_MESSAGE((code), P4_Parse(grammar, source), "unexpected parse grammar return code"); \
P4_Node* root = P4_GetSourceAst(source); \
FILE *f = fopen("check.json","w"); \
P4_JsonifySourceAst(f, root); \
P4_JsonifySourceAst(f, root, P4_TomlFormatNode); \
fclose(f); \
P4_String s = read_file("check.json"); \
printf("%s\n%s\n", input, s); \
Expand All @@ -37,19 +37,6 @@ void test_valid(void) {
ASSERT_TOML("toml", "abc = 'a\\u0031\\U00000032\\n'", P4_Ok, "[]");
ASSERT_TOML("toml", "'abc' = ''", P4_Ok, "[]");
ASSERT_TOML("toml", "a.'b'.c = ''", P4_Ok, "[]");
ASSERT_TOML("toml", "abc = 2000-01-01", P4_Ok, "[]");
ASSERT_TOML("toml", "abc = 00:00:00", P4_Ok, "[]");
ASSERT_TOML("toml", "abc = 00:00:00.000000", P4_Ok, "[]");
ASSERT_TOML("toml", "abc = 2000-01-01T00:00:00", P4_Ok, "[]");
ASSERT_TOML("toml", "abc = 2000-01-01T00:00:00.0000", P4_Ok, "[]");
ASSERT_TOML("toml", "abc = 2000-01-01t00:00:00", P4_Ok, "[]");
ASSERT_TOML("toml", "abc = 2000-01-01t00:00:00.0000", P4_Ok, "[]");
ASSERT_TOML("toml", "abc = 2000-01-01 00:00:00", P4_Ok, "[]");
ASSERT_TOML("toml", "abc = 2000-01-01 00:00:00.0000", P4_Ok, "[]");
ASSERT_TOML("toml", "abc = 2000-01-01T00:00:00Z", P4_Ok, "[]");
ASSERT_TOML("toml", "abc = 2000-01-01T00:00:00.0000Z", P4_Ok, "[]");
ASSERT_TOML("toml", "abc = 2000-01-01T00:00:00+12:00", P4_Ok, "[]");
ASSERT_TOML("toml", "abc = 2000-01-01T00:00:00.0000+12:00", P4_Ok, "[]");
ASSERT_TOML("toml", "abc = []", P4_Ok, "[]");
ASSERT_TOML("toml", "abc = [ # comment\n ]", P4_Ok, "[]");
ASSERT_TOML("toml", "abc = [true]", P4_Ok, "[]");
Expand All @@ -61,6 +48,12 @@ void test_valid(void) {
ASSERT_TOML("toml", "[ a.\"b\".c ]", P4_Ok, "[]");
ASSERT_TOML("toml", "[[abc]]", P4_Ok, "[]");
ASSERT_TOML("toml", "[[ a.\"b\".c ]]", P4_Ok, "[]");
ASSERT_TOML("toml", "abc = '''abc'''", P4_Ok, "[]");
/* ASSERT_TOML("toml", "abc = '''abc'''''", P4_Ok, "[]"); */
ASSERT_TOML("toml", "abc = '''a'b'c'''", P4_Ok, "[]");
ASSERT_TOML("toml", "abc = \"\"\"abc\"\"\"", P4_Ok, "[]");
ASSERT_TOML("toml", "abc = \"\"\"a\"b\"c\"\"\"", P4_Ok, "[]");
/* ASSERT_TOML("toml", "abc = \"\"\"abc\"\"\"\"\"", P4_Ok, "[]"); */
ASSERT_TOML("toml", "abc = 0", P4_Ok, "[]");
ASSERT_TOML("toml", "abc = 1", P4_Ok, "[]");
ASSERT_TOML("toml", "abc = 123_456_789", P4_Ok, "[]");
Expand All @@ -71,12 +64,31 @@ void test_valid(void) {
ASSERT_TOML("toml", "abc = 0o123", P4_Ok, "[]");
ASSERT_TOML("toml", "abc = 1.0", P4_Ok, "[]");
ASSERT_TOML("toml", "abc = -1.0", P4_Ok, "[]");
ASSERT_TOML("toml", "abc = '''abc'''", P4_Ok, "[]");
/* ASSERT_TOML("toml", "abc = '''abc'''''", P4_Ok, "[]"); */
ASSERT_TOML("toml", "abc = '''a'b'c'''", P4_Ok, "[]");
ASSERT_TOML("toml", "abc = \"\"\"abc\"\"\"", P4_Ok, "[]");
ASSERT_TOML("toml", "abc = \"\"\"a\"b\"c\"\"\"", P4_Ok, "[]");
/* ASSERT_TOML("toml", "abc = \"\"\"abc\"\"\"\"\"", P4_Ok, "[]"); */
ASSERT_TOML("toml", "abc = -123_456.0001", P4_Ok, "[]");
ASSERT_TOML("toml", "abc = nan", P4_Ok, "[]");
ASSERT_TOML("toml", "abc = inf", P4_Ok, "[]");
ASSERT_TOML("toml", "abc = +inf", P4_Ok, "[]");
ASSERT_TOML("toml", "abc = -inf", P4_Ok, "[]");
ASSERT_TOML("toml", "abc = 00:00:00", P4_Ok, "[]");
ASSERT_TOML("toml", "abc = 23:59:59.999999", P4_Ok, "[]");
ASSERT_TOML("toml", "abc = 23:59:59.600", P4_Ok, "[]");
ASSERT_TOML("toml", "abc = 00:00:00.000000", P4_Ok, "[]");
ASSERT_TOML("toml", "abc = 2000-01-01", P4_Ok, "[]");
ASSERT_TOML("toml", "abc = 2000-12-31", P4_Ok, "[]");
ASSERT_TOML("toml", "abc = 2000-01-01T00:00:00", P4_Ok, "[]");
ASSERT_TOML("toml", "abc = 2000-01-01T00:00:00.0000", P4_Ok, "[]");
ASSERT_TOML("toml", "abc = 2000-01-01t00:00:00", P4_Ok, "[]");
ASSERT_TOML("toml", "abc = 2000-01-01t00:00:00.0000", P4_Ok, "[]");
ASSERT_TOML("toml", "abc = 2000-01-01 00:00:00", P4_Ok, "[]");
ASSERT_TOML("toml", "abc = 2000-01-01 00:00:00.0000", P4_Ok, "[]");
ASSERT_TOML("toml", "abc = 2000-01-01T00:00:00Z", P4_Ok, "[]");
ASSERT_TOML("toml", "abc = 2000-01-01T00:00:00.0000Z", P4_Ok, "[]");
ASSERT_TOML("toml", "abc = 2000-01-01T00:00:00+12:00", P4_Ok, "[]");
ASSERT_TOML("toml", "abc = 2000-01-01T00:00:00.0000+12:00", P4_Ok, "[]");
ASSERT_TOML("toml", "abc = 2000-01-01T00:00:00-07:00", P4_Ok, "[]");
ASSERT_TOML("toml", "abc = 2000-01-01T00:00:00.0000-07:00", P4_Ok, "[]");
ASSERT_TOML("toml", "abc = 2000-01-01T00:00:00-04:30", P4_Ok, "[]");
ASSERT_TOML("toml", "abc = 2000-01-01T00:00:00.0000-04:30", P4_Ok, "[]");
}

int main(void) {
Expand Down
2 changes: 1 addition & 1 deletion tests/test_misc.c
Expand Up @@ -270,7 +270,7 @@ void test_acquire_source_ast(void) {
TEST_ASSERT_NOT_NULL(root);
TEST_ASSERT_NULL(P4_GetSourceAst(source));

P4_DeleteNode(root);
P4_DeleteNode(grammar, root);
P4_DeleteSource(source);
P4_DeleteGrammar(grammar);
}
Expand Down
4 changes: 2 additions & 2 deletions tests/test_peg.c
Expand Up @@ -27,7 +27,7 @@
} \
P4_Node* ast_node = P4_GetSourceAst(source); \
FILE *f = fopen("check.json","w"); \
P4_JsonifySourceAst(f, ast_node); \
P4_JsonifySourceAst(f, ast_node, NULL); \
fclose(f); \
P4_String s = read_file("check.json"); TEST_ASSERT_EQUAL_STRING((ast), s); free(s); \
P4_DeleteSource(source); \
Expand All @@ -41,7 +41,7 @@
if ((code) == P4_Ok) { \
P4_Node* root = P4_GetSourceAst(source); \
FILE *f = fopen("check.json","w"); \
P4_JsonifySourceAst(f, root); \
P4_JsonifySourceAst(f, root, NULL); \
fclose(f); \
P4_String s = read_file("check.json"); \
TEST_ASSERT_EQUAL_STRING((output), s); \
Expand Down