From e3763bd3ccb9179e7feb3513c86e48a5610361d4 Mon Sep 17 00:00:00 2001 From: Thomas Jollans Date: Sun, 8 Dec 2024 12:53:32 +0100 Subject: [PATCH] keep track of non-slashdashed {} fixes #10 --- src/parser.c | 24 +++++++++++++++++++--- tests/parser_test.c | 49 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 3 deletions(-) diff --git a/src/parser.c b/src/parser.c index 73dcc5d..b1e338a 100644 --- a/src/parser.c +++ b/src/parser.c @@ -58,6 +58,7 @@ struct _kdl_parser { kdl_parse_option opt; int depth; int slashdash_depth; + int child_block_at_depth; enum _kdl_parser_state state; kdl_event_data event; kdl_owned_string tmp_string_type; @@ -73,6 +74,7 @@ static void _init_kdl_parser(kdl_parser* self, kdl_parse_option opt) { self->depth = 0; self->slashdash_depth = -1; + self->child_block_at_depth = -1; self->state = PARSER_OUTSIDE_NODE; self->tmp_string_type = (kdl_owned_string){NULL, 0}; self->tmp_string_key = (kdl_owned_string){NULL, 0}; @@ -408,12 +410,25 @@ static kdl_event_data* _next_node(kdl_parser* self, kdl_token* token) self->state = PARSER_IN_NODE; --self->depth; _reset_event(self); + if (self->slashdash_depth < 0) { + // slashdash is not active, this child block can't be + // followed by another child block. + self->state |= PARSER_FLAG_END_OF_NODE; + self->child_block_at_depth = self->depth; + } else { + // slashdash applies to this child block + if (self->child_block_at_depth == self->depth) { + // we already had a child block here before + self->state |= PARSER_FLAG_END_OF_NODE; + } else { + // all child blocks seen so far in this node have been + // slashdashed + self->state |= PARSER_FLAG_END_OF_NODE_OR_CHILD_BLOCK; + } + } if (self->slashdash_depth == self->depth + 1) { // slashdash is ending here self->slashdash_depth = -1; - self->state |= PARSER_FLAG_END_OF_NODE_OR_CHILD_BLOCK; - } else { - self->state |= PARSER_FLAG_END_OF_NODE; } return NULL; } @@ -549,6 +564,9 @@ static kdl_event_data* _next_event_in_node(kdl_parser* self, kdl_token* token) // end the node self->state = PARSER_OUTSIDE_NODE; --self->depth; + if (self->child_block_at_depth > self->depth) { + self->child_block_at_depth = -1; + } _reset_event(self); self->event.event = KDL_EVENT_END_NODE; ev = _apply_slashdash(self); diff --git a/tests/parser_test.c b/tests/parser_test.c index 3bd789c..37555cd 100644 --- a/tests/parser_test.c +++ b/tests/parser_test.c @@ -2,6 +2,7 @@ #include "test_util.h" +#include #include static void test_basics(void) @@ -188,6 +189,53 @@ static void test_slashdash(void) kdl_destroy_parser(parser); } +static void test_slashdash_child_block(void) +{ + kdl_str invalid_docs[] = { + kdl_str_from_cstr("node /-{child} arg"), // arg can't follow child block + kdl_str_from_cstr("node /-{child} /-arg"), // arg can't follow child block + kdl_str_from_cstr("node {child} /-arg"), // arg can't follow child block + kdl_str_from_cstr("node { one } /-{ two } { three }"), // two child blocks + kdl_str_from_cstr("node /-{ one } { two } { three }"), // two child blocks + }; + int n_invalid = sizeof(invalid_docs) / sizeof(invalid_docs[0]); + + kdl_str valid_docs[] = { + kdl_str_from_cstr("node arg /-{child}"), // child blocks can be slashdashed + kdl_str_from_cstr("node /-arg {child}"), // args can be slashdashed + kdl_str_from_cstr("node /-arg /-{child}"), // multiple slashdashes + kdl_str_from_cstr("node /-{one}/-{two}{three}"), // {} after /-{} + kdl_str_from_cstr("node { one; } /-{ two } /-{ three }"), // /-{} after {} + }; + int n_valid = sizeof(valid_docs) / sizeof(valid_docs[0]); + + for (int i = 0; i < n_invalid; ++i) { + kdl_parser* parser = kdl_create_string_parser(invalid_docs[i], KDL_READ_VERSION_2); + + kdl_event_data* ev; + do { + ev = kdl_parser_next_event(parser); + } while (ev->event != KDL_EVENT_EOF && ev->event != KDL_EVENT_PARSE_ERROR); + + ASSERT(ev->event == KDL_EVENT_PARSE_ERROR); + + kdl_destroy_parser(parser); + } + + for (int i = 0; i < n_valid; ++i) { + kdl_parser* parser = kdl_create_string_parser(valid_docs[i], KDL_READ_VERSION_2); + + kdl_event_data* ev; + do { + ev = kdl_parser_next_event(parser); + } while (ev->event != KDL_EVENT_EOF && ev->event != KDL_EVENT_PARSE_ERROR); + + ASSERT(ev->event == KDL_EVENT_EOF); + + kdl_destroy_parser(parser); + } +} + static void test_unbalanced_brace(void) { char const* const kdl_text = "node1 {"; @@ -278,6 +326,7 @@ void TEST_MAIN(void) { run_test("Parser: basics", &test_basics); run_test("Parser: slashdash", &test_slashdash); + run_test("Parser: slashdash with child blocks", &test_slashdash_child_block); run_test("Parser: unbalanced {", &test_unbalanced_brace); run_test("Parser: arg can't be identifier", &test_identifier_arg); run_test("Parser: type can't be number", &test_number_type);