From 48d5cceb8f410344fd7356b0388d2375cdecc1b8 Mon Sep 17 00:00:00 2001 From: Zach Laine Date: Sat, 9 Mar 2024 17:41:57 -0600 Subject: [PATCH] Add more tests of seq_parser and or_parser, to cover all the permutations of different parsers that they might use. Fixes #126. --- test/CMakeLists.txt | 5 + test/parser_attributes.cpp | 67 ++++++ test/parser_or_permutations_1.cpp | 338 ++++++++++++++++++++++++++ test/parser_or_permutations_2.cpp | 312 ++++++++++++++++++++++++ test/parser_seq_permutations_1.cpp | 339 ++++++++++++++++++++++++++ test/parser_seq_permutations_2.cpp | 370 +++++++++++++++++++++++++++++ 6 files changed, 1431 insertions(+) create mode 100644 test/parser_attributes.cpp create mode 100644 test/parser_or_permutations_1.cpp create mode 100644 test/parser_or_permutations_2.cpp create mode 100644 test/parser_seq_permutations_1.cpp create mode 100644 test/parser_seq_permutations_2.cpp diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index bc06b8b3..4e95cd51 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -53,6 +53,7 @@ add_test_executable(replace) add_test_executable(transform_replace) add_test_executable(hl) add_test_executable(aggr_tuple_assignment) +add_test_executable(parser_attributes) add_test_executable(parser_lazy_params) add_test_executable(parser_if_switch) add_test_executable(parser_rule) @@ -68,3 +69,7 @@ add_test_executable(case_fold_generated) add_test_executable(no_case) add_test_executable(merge_separate) add_test_executable(parse_coords_new) +add_test_executable(parser_seq_permutations_1) +add_test_executable(parser_seq_permutations_2) +add_test_executable(parser_or_permutations_1) +add_test_executable(parser_or_permutations_2) diff --git a/test/parser_attributes.cpp b/test/parser_attributes.cpp new file mode 100644 index 00000000..e90c3ec6 --- /dev/null +++ b/test/parser_attributes.cpp @@ -0,0 +1,67 @@ +/** + * Copyright (C) 2024 T. Zachary Laine + * + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + */ + +#include + +#include + + +namespace bp = boost::parser; + +bp::rule> seq1 = ""; +bp::rule> seq2 = ""; +auto const seq1_def = bp::int_ >> bp::char_('a'); +auto const seq2_def = bp::int_ >> bp::char_('b'); +BOOST_PARSER_DEFINE_RULES(seq1, seq2); + +TEST(attributes, internal_errors_munging_attributes) +{ + // These are just some assorted cases that have, or seemed likely to, + // cause problems when an internal failure in an alternative wipes out an + // existing result. This covers all the cases where "if (!success)" + // causes the attribute to be overwritten with a default-constructed + // value. + + { + auto const parser = + bp::string("FOO") >> -(bp::string("bar") | bp::string("foo")); + + auto result = bp::parse("FOOfoo", parser); + EXPECT_TRUE(result); + EXPECT_EQ(bp::get(*result, bp::llong<0>{}), std::string("FOO")); + EXPECT_EQ(bp::get(*result, bp::llong<1>{}), std::string("foo")); + } + + { + auto const parser = bp::merge + [bp::string("FOO") >> (bp::string("bar") | bp::string("foo"))]; + + auto result = bp::parse("FOOfoo", parser); + EXPECT_TRUE(result); + EXPECT_EQ(*result, std::string("FOOfoo")); + } + + { + auto const parser = bp::merge + [(bp::attr(std::vector({"FOO"})) | bp::eps) >> + (bp::repeat(1)[bp::string("foo")] | bp::eps)]; + + auto result = bp::parse("", parser); + EXPECT_TRUE(result); + EXPECT_TRUE(*result); + EXPECT_EQ(*result, std::vector({"FOO"})); + } + + { + auto const parser = bp::merge[seq1 >> (seq2 | seq1)]; + + auto result = bp::parse("7a9a", parser); + EXPECT_TRUE(result); + EXPECT_EQ(*result, (bp::tuple(9, 'a'))); + } +} diff --git a/test/parser_or_permutations_1.cpp b/test/parser_or_permutations_1.cpp new file mode 100644 index 00000000..4c65d48e --- /dev/null +++ b/test/parser_or_permutations_1.cpp @@ -0,0 +1,338 @@ +/** + * Copyright (C) 2024 T. Zachary Laine + * + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + */ + +#include + +#include + + +namespace bp = boost::parser; + +namespace make { + template + auto tuple(Ts &&... xs) + { + return bp::tuple((Ts &&) xs...); + } +} + +/* +{P0, -P0, *P0, P1, P2, P3, eps} + +{P0, P1, P2, P3, eps, *P0, -P0, (P0 |/>> P2), -(P0 |/>> P1), (-P0 |/>> P1)} + +P0 = bp::string("foo"); +P1 = bp::string("bar"); +P2 = bp::int_; +P3 = bp::char_('c'); +*/ + +using namespace std::literals; + +TEST(attributes, or_parser_permutations_1) +{ + [[maybe_unused]] int dummy = 0; // for clang-format(!) + + // P0 + { + auto result = bp::parse("foo", bp::string("foo") | bp::string("foo")); + EXPECT_TRUE(result); + EXPECT_EQ(*result, "foo"s); + } + { + auto result = bp::parse("bar", bp::string("foo") | bp::string("bar")); + EXPECT_TRUE(result); + EXPECT_EQ(*result, "bar"s); + } + { + auto result = bp::parse("42", bp::string("foo") | bp::int_); + EXPECT_TRUE(result); + EXPECT_EQ(result->index(), 1u); + EXPECT_EQ(std::get(*result), 42); + } + { + auto result = bp::parse("c", bp::string("foo") | bp::char_('c')); + EXPECT_TRUE(result); + EXPECT_EQ(result->index(), 1u); + EXPECT_EQ(std::get(*result), 'c'); + } + { + auto result = bp::parse("foo", bp::string("foo") | bp::eps); + EXPECT_TRUE(result); + EXPECT_EQ(*result, std::optional("foo"s)); + } + { + auto result = bp::parse("foo", bp::string("foo") | *bp::string("foo")); + EXPECT_TRUE(result); + EXPECT_EQ(result->index(), 0); + EXPECT_EQ(std::get(*result), "foo"s); + } + { + auto result = bp::parse("", bp::string("foo") | -bp::string("foo")); + EXPECT_TRUE(result); + EXPECT_EQ(result->index(), 1u); + EXPECT_EQ(std::get>(*result), std::nullopt); + } + { + auto result = bp::parse( + "foo", bp::string("foo") | (bp::string("foo") | bp::int_)); + EXPECT_TRUE(result); + EXPECT_EQ(result->index(), 0); + EXPECT_EQ(std::get(*result), "foo"s); + } + { + auto result = bp::parse( + "bar", + bp::string("foo") | -(bp::string("foo") | bp::string("bar"))); + EXPECT_TRUE(result); + EXPECT_EQ(result->index(), 1); + EXPECT_EQ(std::get>(*result), "bar"s); + } + { + auto result = bp::parse( + "", bp::string("foo") | (-bp::string("foo") | bp::string("bar"))); + EXPECT_TRUE(result); + EXPECT_EQ(result->index(), 1); + EXPECT_EQ(std::get>(*result), std::nullopt); + } + { + auto result = bp::parse( + "foo", bp::string("foo") | (bp::string("foo") >> bp::int_)); + EXPECT_TRUE(result); + EXPECT_EQ(result->index(), 0); + EXPECT_EQ(std::get(*result), "foo"s); + } + { + auto result = bp::parse( + "", bp::string("foo") | -(bp::string("foo") >> bp::string("bar"))); + EXPECT_TRUE(result); + EXPECT_EQ(result->index(), 1u); + EXPECT_EQ( + (std::get>>( + *result)), + std::nullopt); + } + { + auto result = bp::parse( + "bar", + bp::string("foo") | (-bp::string("foo") >> bp::string("bar"))); + EXPECT_TRUE(result); + EXPECT_EQ(result->index(), 1u); + EXPECT_EQ( + (std::get, std::string>>( + *result)), + (make::tuple(std::optional{}, "bar"s))); + } + + // -P0 + { + auto result = bp::parse("foo", -bp::string("foo") | bp::string("foo")); + EXPECT_TRUE(result); + EXPECT_EQ(result->index(), 0); + EXPECT_EQ( + std::get>(*result), + std::optional("foo"s)); + } + { + auto result = bp::parse("", -bp::string("foo") | bp::string("bar")); + EXPECT_TRUE(result); + EXPECT_EQ(result->index(), 0); + EXPECT_EQ(std::get>(*result), std::nullopt); + } + { + auto result = bp::parse("", -bp::string("foo") | bp::int_); + EXPECT_TRUE(result); + EXPECT_EQ(result->index(), 0); + EXPECT_EQ(std::get>(*result), std::nullopt); + } + { + auto result = bp::parse("", -bp::string("foo") | bp::char_('c')); + EXPECT_TRUE(result); + EXPECT_EQ(result->index(), 0); + EXPECT_EQ(std::get>(*result), std::nullopt); + } + { + auto result = bp::parse("foo", -bp::string("foo") | bp::eps); + EXPECT_TRUE(result); + EXPECT_EQ(*result, "foo"s); + } + { + auto result = bp::parse("foo", -bp::string("foo") | *bp::string("foo")); + EXPECT_TRUE(result); + EXPECT_EQ(result->index(), 0); + EXPECT_EQ(std::get>(*result), "foo"s); + } + { + auto result = bp::parse("foo", -bp::string("foo") | -bp::string("foo")); + EXPECT_TRUE(result); + EXPECT_EQ(*result, "foo"s); + } + { + auto result = + bp::parse("", -bp::string("foo") | (bp::string("foo") | bp::int_)); + EXPECT_TRUE(result); + EXPECT_EQ(result->index(), 0); + EXPECT_EQ(std::get>(*result), std::nullopt); + } + { + auto result = bp::parse( + "foo", + -bp::string("foo") | -(bp::string("foo") | bp::string("bar"))); + EXPECT_TRUE(result); + EXPECT_EQ(*result, "foo"s); + } + { + auto result = bp::parse( + "", -bp::string("foo") | (-bp::string("foo") | bp::string("bar"))); + EXPECT_TRUE(result); + EXPECT_EQ(result->index(), 0); + EXPECT_EQ(std::get>(*result), std::nullopt); + } + { + auto result = bp::parse( + "foo", -bp::string("foo") | (bp::string("foo") >> bp::int_)); + EXPECT_TRUE(result); + EXPECT_EQ(result->index(), 0); + EXPECT_EQ(std::get>(*result), "foo"s); + } + { + auto result = bp::parse( + "foo", + -bp::string("foo") | -(bp::string("foo") >> bp::string("bar"))); + EXPECT_TRUE(result); + EXPECT_EQ(result->index(), 0); + EXPECT_EQ(std::get>(*result), "foo"s); + } + { + auto result = bp::parse( + "foo", + -bp::string("foo") | (-bp::string("foo") >> bp::string("bar"))); + EXPECT_TRUE(result); + EXPECT_EQ(result->index(), 0); + EXPECT_EQ(std::get>(*result), "foo"s); + } + + // *P0 + { + auto result = bp::parse( + "foo", bp::lexeme[*bp::string("foo")] | bp::string("foo")); + EXPECT_TRUE(result); + EXPECT_EQ(result->index(), 0); + EXPECT_EQ( + std::get>(*result), std::vector({"foo"s})); + } + { + auto result = + bp::parse("foofoo", *bp::string("foo") | bp::string("bar")); + EXPECT_TRUE(result); + EXPECT_EQ(result->index(), 0); + EXPECT_EQ( + std::get>(*result), + std::vector({"foo"s, "foo"s})); + } + { + auto result = bp::parse("", *bp::string("foo") | bp::int_); + EXPECT_TRUE(result); + EXPECT_EQ(result->index(), 0); + EXPECT_EQ( + std::get>(*result), + std::vector{}); + } + { + auto result = bp::parse("", *bp::string("foo") | bp::char_('c')); + EXPECT_TRUE(result); + EXPECT_EQ(result->index(), 0); + EXPECT_EQ( + std::get>(*result), + std::vector{}); + } + { + auto result = bp::parse("foofoo", *bp::string("foo") | bp::eps); + EXPECT_TRUE(result); + EXPECT_EQ(*result, std::optional(std::vector({"foo"s, "foo"s}))); + } + { + auto result = bp::parse( + "foofoo", bp::lexeme[*bp::string("foo")] | *bp::string("foo")); + EXPECT_TRUE(result); + EXPECT_EQ(*result, std::vector({"foo"s, "foo"s})); + } + { + auto result = + bp::parse("foofoo", *bp::string("foo") | -bp::string("foo")); + EXPECT_TRUE(result); + EXPECT_EQ(result->index(), 0); + EXPECT_EQ( + std::get>(*result), + std::vector({"foo"s, "foo"s})); + } + { + auto result = bp::parse( + "foofoo", + bp::lexeme[*bp::string("foo")] | (bp::string("foo") | bp::int_)); + EXPECT_TRUE(result); + EXPECT_EQ(result->index(), 0); + EXPECT_EQ( + std::get>(*result), + std::vector({"foo"s, "foo"s})); + } + { + auto result = bp::parse( + "foofoo", + bp::lexeme[*bp::string("foo")] | + -(bp::string("foo") | bp::string("bar"))); + EXPECT_TRUE(result); + EXPECT_EQ(result->index(), 0); + EXPECT_EQ( + std::get>(*result), + std::vector({"foo"s, "foo"s})); + } + { + auto result = bp::parse( + "foofoo", + bp::lexeme[*bp::string("foo")] | + (-bp::string("foo") | bp::string("bar"))); + EXPECT_TRUE(result); + EXPECT_EQ(result->index(), 0); + EXPECT_EQ( + std::get>(*result), + std::vector({"foo"s, "foo"s})); + } + { + auto result = bp::parse( + "foofoo", + bp::lexeme[*bp::string("foo")] | (bp::string("foo") >> bp::int_)); + EXPECT_TRUE(result); + EXPECT_EQ(result->index(), 0); + EXPECT_EQ( + std::get>(*result), + std::vector({"foo"s, "foo"s})); + } + { + auto result = bp::parse( + "foofoo", + bp::lexeme[*bp::string("foo")] | + -(bp::string("foo") >> bp::string("bar"))); + EXPECT_TRUE(result); + EXPECT_EQ(result->index(), 0); + EXPECT_EQ( + std::get>(*result), + std::vector({"foo"s, "foo"s})); + } + { + auto result = bp::parse( + "foofoo", + bp::lexeme[*bp::string("foo")] | + (-bp::string("foo") >> bp::string("bar"))); + EXPECT_TRUE(result); + EXPECT_EQ(result->index(), 0); + EXPECT_EQ( + std::get>(*result), + std::vector({"foo"s, "foo"s})); + } +} diff --git a/test/parser_or_permutations_2.cpp b/test/parser_or_permutations_2.cpp new file mode 100644 index 00000000..b4b0327f --- /dev/null +++ b/test/parser_or_permutations_2.cpp @@ -0,0 +1,312 @@ +/** + * Copyright (C) 2024 T. Zachary Laine + * + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + */ + +#include + +#include + + +namespace bp = boost::parser; + +namespace make { + template + auto tuple(Ts &&... xs) + { + return bp::tuple((Ts &&) xs...); + } +} + +/* +{P0, -P0, *P0, P1, P2, P3, eps} + +{P0, P1, P2, P3, eps, *P0, -P0, (P0 >>/| P2), -(P0 >>/| P1), (-P0 >>/| P1)} + +P0 = bp::string("foo"); +P1 = bp::string("bar"); +P2 = bp::int_; +P3 = bp::char_('c'); +*/ + +using namespace std::literals; + +TEST(attributes, or_parser_permutations_2) +{ + [[maybe_unused]] int dummy = 0; // for clang-format(!) + + // P1 + { + auto result = bp::parse("foo", bp::string("bar") | bp::string("foo")); + EXPECT_TRUE(result); + EXPECT_EQ(*result, "foo"s); + } + { + auto result = bp::parse("bar", bp::string("bar") | bp::string("bar")); + EXPECT_TRUE(result); + EXPECT_EQ(*result, "bar"s); + } + { + auto result = bp::parse("42", bp::string("bar") | bp::int_); + EXPECT_TRUE(result); + EXPECT_EQ(result->index(), 1u); + EXPECT_EQ(std::get(*result), 42); + } + { + auto result = bp::parse("bar", bp::string("bar") | bp::char_('c')); + EXPECT_TRUE(result); + EXPECT_EQ(result->index(), 0); + EXPECT_EQ(std::get(*result), "bar"s); + } + { + auto result = bp::parse("", bp::string("bar") | bp::eps); + EXPECT_TRUE(result); + EXPECT_EQ(*result, std::nullopt); + } + { + auto result = + bp::parse("foofoo", bp::string("bar") | *bp::string("foo")); + EXPECT_TRUE(result); + EXPECT_EQ(result->index(), 1u); + EXPECT_EQ( + std::get>(*result), + std::vector({"foo"s, "foo"s})); + } + { + auto result = bp::parse("bar", bp::string("bar") | -bp::string("foo")); + EXPECT_TRUE(result); + EXPECT_EQ(result->index(), 0); + EXPECT_EQ(std::get(*result), "bar"s); + } + { + auto result = + bp::parse("42", bp::string("bar") | (bp::string("foo") | bp::int_)); + EXPECT_TRUE(result); + EXPECT_EQ(result->index(), 1u); + EXPECT_EQ(std::get(*result), 42); + } + { + auto result = bp::parse( + "bar", + bp::string("foo") | -(bp::string("foo") | bp::string("bar"))); + EXPECT_TRUE(result); + EXPECT_EQ(result->index(), 1u); + EXPECT_EQ(std::get>(*result), "bar"s); + } + { + auto result = bp::parse( + "foo", + bp::string("bar") | (-bp::string("foo") | bp::string("bar"))); + EXPECT_TRUE(result); + EXPECT_EQ(result->index(), 1u); + EXPECT_EQ(std::get>(*result), "foo"s); + } + { + auto result = bp::parse( + "bar", bp::string("bar") | (bp::string("foo") >> bp::int_)); + EXPECT_TRUE(result); + EXPECT_EQ(result->index(), 0); + EXPECT_EQ(std::get(*result), "bar"s); + } + { + auto result = bp::parse( + "bar", + bp::string("bar") | -(bp::string("foo") >> bp::string("bar"))); + EXPECT_TRUE(result); + EXPECT_EQ(result->index(), 0); + EXPECT_EQ(std::get(*result), "bar"s); + } + { + auto result = bp::parse( + "bar", + bp::string("bar") | (-bp::string("foo") >> bp::string("bar"))); + EXPECT_TRUE(result); + EXPECT_EQ(result->index(), 0); + EXPECT_EQ(std::get(*result), "bar"s); + } + + // P2 + { + auto result = bp::parse("42", bp::int_ | bp::string("foo")); + EXPECT_TRUE(result); + EXPECT_EQ(result->index(), 0); + EXPECT_EQ(std::get(*result), 42); + } + { + auto result = bp::parse("bar", bp::int_ | bp::string("bar")); + EXPECT_TRUE(result); + EXPECT_EQ(result->index(), 1u); + EXPECT_EQ(std::get(*result), "bar"s); + } + { + auto result = bp::parse("42", bp::int_ | bp::int_, bp::ws); + EXPECT_TRUE(result); + EXPECT_EQ(*result, 42); + } + { + auto result = bp::parse("c", bp::int_ | bp::char_('c')); + EXPECT_TRUE(result); + EXPECT_EQ(result->index(), 1u); + EXPECT_EQ(std::get(*result), 'c'); + } + { + auto result = bp::parse("", bp::int_ | bp::eps); + EXPECT_TRUE(result); + EXPECT_EQ(*result, std::nullopt); + } + { + auto result = bp::parse("foofoo", bp::int_ | *bp::string("foo")); + EXPECT_TRUE(result); + EXPECT_EQ(result->index(), 1u); + EXPECT_EQ( + std::get>(*result), + std::vector({"foo"s, "foo"s})); + } + { + auto result = bp::parse("42", bp::int_ | -bp::string("foo")); + EXPECT_TRUE(result); + EXPECT_EQ(result->index(), 0); + EXPECT_EQ(std::get(*result), 42); + } + { + auto result = + bp::parse("42", bp::int_ | (bp::string("foo") | bp::int_)); + EXPECT_TRUE(result); + EXPECT_EQ(result->index(), 0); + EXPECT_EQ(std::get(*result), 42); + } + { + auto result = bp::parse( + "bar", bp::int_ | -(bp::string("foo") | bp::string("bar"))); + EXPECT_TRUE(result); + EXPECT_EQ(result->index(), 1u); + EXPECT_EQ( + std::get>(*result), + std::optional("bar"s)); + } + { + auto result = + bp::parse("", bp::int_ | (-bp::string("foo") | bp::string("bar"))); + EXPECT_TRUE(result); + EXPECT_EQ(result->index(), 1u); + EXPECT_EQ(std::get>(*result), std::nullopt); + } + { + auto result = + bp::parse("42", bp::int_ | (bp::string("foo") >> bp::int_)); + EXPECT_TRUE(result); + EXPECT_EQ(result->index(), 0); + EXPECT_EQ(std::get(*result), 42); + } + { + auto result = bp::parse( + "42", bp::int_ | -(bp::string("foo") >> bp::string("bar"))); + EXPECT_TRUE(result); + EXPECT_EQ(result->index(), 0); + EXPECT_EQ(std::get(*result), 42); + } + { + auto result = bp::parse( + "42", bp::int_ | (-bp::string("foo") >> bp::string("bar"))); + EXPECT_TRUE(result); + EXPECT_EQ(result->index(), 0); + EXPECT_EQ(std::get(*result), 42); + } + + // P3 + { + auto result = bp::parse("c", bp::char_('c') | bp::string("foo")); + EXPECT_TRUE(result); + EXPECT_EQ(result->index(), 0); + EXPECT_EQ(std::get(*result), 'c'); + } + { + auto result = bp::parse("bar", bp::char_('c') | bp::string("bar")); + EXPECT_TRUE(result); + EXPECT_EQ(result->index(), 1u); + EXPECT_EQ(std::get(*result), "bar"s); + } + { + auto result = bp::parse("42", bp::char_('c') | bp::int_); + EXPECT_TRUE(result); + EXPECT_EQ(result->index(), 1u); + EXPECT_EQ(std::get(*result), 42); + } + { + auto result = bp::parse("c", bp::char_('c') | bp::char_('c')); + EXPECT_TRUE(result); + EXPECT_EQ(*result, 'c'); + } + { + auto result = bp::parse("c", bp::char_('c') | bp::eps); + EXPECT_TRUE(result); + EXPECT_EQ(*result, 'c'); + } + { + auto result = bp::parse("foofoo", bp::char_('c') | *bp::string("foo")); + EXPECT_TRUE(result); + EXPECT_EQ(result->index(), 1u); + EXPECT_EQ( + std::get>(*result), + std::vector({"foo"s, "foo"s})); + } + { + auto result = bp::parse("c", bp::char_('c') | -bp::string("foo")); + EXPECT_TRUE(result); + EXPECT_EQ(result->index(), 0); + EXPECT_EQ(std::get(*result), 'c'); + } + { + auto result = + bp::parse("42", bp::char_('c') | (bp::string("foo") | bp::int_)); + EXPECT_TRUE(result); + EXPECT_EQ(result->index(), 2u); + EXPECT_EQ(std::get(*result), 42); + } + { + auto result = bp::parse( + "bar", bp::char_('c') | -(bp::string("foo") | bp::string("bar"))); + EXPECT_TRUE(result); + EXPECT_EQ(result->index(), 1u); + EXPECT_EQ( + std::get>(*result), + std::optional("bar"s)); + } + { + auto result = bp::parse( + "foo", bp::char_('c') | (-bp::string("foo") | bp::string("bar"))); + EXPECT_TRUE(result); + EXPECT_EQ(result->index(), 1u); + EXPECT_EQ( + std::get>(*result), + std::optional("foo"s)); + } + { + auto result = bp::parse( + "foo42", bp::char_('c') | (bp::string("foo") >> bp::int_)); + EXPECT_TRUE(result); + EXPECT_EQ(result->index(), 1u); + EXPECT_EQ( + (std::get>(*result)), + (make::tuple("foo"s, 42))); + } + { + auto result = bp::parse( + "c", bp::char_('c') | -(bp::string("foo") >> bp::string("bar"))); + EXPECT_TRUE(result); + EXPECT_EQ(result->index(), 0); + EXPECT_EQ(std::get(*result), 'c'); + } + { + auto result = bp::parse( + "c", bp::char_('c') | (-bp::string("foo") >> bp::string("bar"))); + EXPECT_TRUE(result); + EXPECT_EQ(result->index(), 0); + EXPECT_EQ(std::get(*result), 'c'); + } + + // eps | ... prohibited. +} diff --git a/test/parser_seq_permutations_1.cpp b/test/parser_seq_permutations_1.cpp new file mode 100644 index 00000000..5f2844a0 --- /dev/null +++ b/test/parser_seq_permutations_1.cpp @@ -0,0 +1,339 @@ +/** + * Copyright (C) 2024 T. Zachary Laine + * + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + */ + +#include + +#include + + +namespace bp = boost::parser; + +namespace make { + template + auto tuple(Ts &&... xs) + { + return bp::tuple((Ts &&) xs...); + } +} + +/* +{P0, -P0, *P0, P1, P2, P3, eps} + +{P0, P1, P2, P3, eps, *P0, -P0, (P0 >>/| P2), -(P0 >>/| P1), (-P0 >>/| P1)} + +P0 = bp::string("foo"); +P1 = bp::string("bar"); +P2 = bp::int_; +P3 = bp::char_('c'); +*/ + +using namespace std::literals; + +TEST(attributes, seq_parser_permutations_1) +{ + [[maybe_unused]] int dummy = 0; // for clang-format(!) + + // P0 + { + auto result = + bp::parse("foofoo", bp::string("foo") >> bp::string("foo")); + EXPECT_TRUE(result); + EXPECT_EQ(*result, (make::tuple("foo"s, "foo"s))); + } + { + auto result = + bp::parse("foobar", bp::string("foo") >> bp::string("bar")); + EXPECT_TRUE(result); + EXPECT_EQ(*result, (make::tuple("foo"s, "bar"s))); + } + { + auto result = bp::parse("foo42", bp::string("foo") >> bp::int_); + EXPECT_TRUE(result); + EXPECT_EQ(*result, (make::tuple("foo"s, 42))); + } + { + auto result = bp::parse("fooc", bp::string("foo") >> bp::char_('c')); + EXPECT_TRUE(result); + EXPECT_EQ(*result, "fooc"s); + } + { + auto result = bp::parse("foo", bp::string("foo") >> bp::eps); + EXPECT_TRUE(result); + EXPECT_EQ(*result, "foo"s); + } + { + auto result = + bp::parse("foofoofoo", bp::string("foo") >> *bp::string("foo")); + EXPECT_TRUE(result); + EXPECT_EQ(*result, std::vector({"foo"s, "foo"s, "foo"s})); + } + { + auto result = bp::parse("foo", bp::string("foo") >> -bp::string("foo")); + EXPECT_TRUE(result); + EXPECT_EQ(*result, (make::tuple("foo"s, std::optional{}))); + } + { + auto result = bp::parse( + "foofoo42", bp::string("foo") >> (bp::string("foo") >> bp::int_)); + EXPECT_TRUE(result); + EXPECT_EQ(*result, (make::tuple("foo"s, "foo"s, 42))); + } + { + auto result = bp::parse( + "foofoobar", + bp::string("foo") >> -(bp::string("foo") >> bp::string("bar"))); + EXPECT_TRUE(result); + EXPECT_EQ( + *result, + (make::tuple("foo"s, std::optional(make::tuple("foo"s, "bar"s))))); + } + { + auto result = bp::parse( + "foofoobar", + bp::string("foo") >> (-bp::string("foo") >> bp::string("bar"))); + EXPECT_TRUE(result); + EXPECT_EQ( + *result, (make::tuple("foo"s, std::optional("foo"s), "bar"s))); + } + { + auto result = bp::parse( + "foo42", bp::string("foo") >> (bp::string("foo") | bp::int_)); + EXPECT_TRUE(result); + EXPECT_EQ( + *result, (make::tuple("foo"s, std::variant(42)))); + } + { + auto result = bp::parse( + "foo", + bp::string("foo") >> -(bp::string("foo") | bp::string("bar"))); + EXPECT_TRUE(result); + EXPECT_EQ(*result, (make::tuple("foo"s, std::optional{}))); + } + { + auto result = bp::parse( + "foo", + bp::string("foo") >> (-bp::string("foo") | bp::string("bar"))); + EXPECT_TRUE(result); + EXPECT_EQ( + *result, + (make::tuple( + "foo"s, + std::variant, std::string>( + std::nullopt)))); + } + + // -P0 + { + auto result = + bp::parse("foofoo", -bp::string("foo") >> bp::string("foo")); + EXPECT_TRUE(result); + EXPECT_EQ(*result, (make::tuple(std::optional("foo"s), "foo"s))); + } + { + auto result = bp::parse("bar", -bp::string("foo") >> bp::string("bar")); + EXPECT_TRUE(result); + EXPECT_EQ(*result, (make::tuple(std::optional{}, "bar"s))); + } + { + auto result = bp::parse("42", -bp::string("foo") >> bp::int_); + EXPECT_TRUE(result); + EXPECT_EQ(*result, (make::tuple(std::optional{}, 42))); + } + { + auto result = bp::parse("c", -bp::string("foo") >> bp::char_('c')); + EXPECT_TRUE(result); + EXPECT_EQ(*result, (make::tuple(std::optional{}, 'c'))); + } + { + auto result = bp::parse("foo", -bp::string("foo") >> bp::eps); + EXPECT_TRUE(result); + EXPECT_EQ(*result, std::optional("foo"s)); + } + { + auto result = + bp::parse("foofoo", -bp::string("foo") >> *bp::string("foo")); + EXPECT_TRUE(result); + EXPECT_EQ(*result, std::vector({"foo"s, "foo"s})); + } + { + auto result = + bp::parse("foofoo", -bp::string("foo") >> -bp::string("foo")); + EXPECT_TRUE(result); + EXPECT_EQ( + *result, + (make::tuple(std::optional("foo"s), std::optional("foo"s)))); + } + { + auto result = bp::parse( + "foofoo42", -bp::string("foo") >> (bp::string("foo") >> bp::int_)); + EXPECT_TRUE(result); + EXPECT_EQ(*result, (make::tuple(std::optional("foo"s), "foo"s, 42))); + } + { + auto result = bp::parse( + "foofoobar", + -bp::string("foo") >> -(bp::string("foo") >> bp::string("bar"))); + EXPECT_TRUE(result); + EXPECT_EQ( + *result, + (make::tuple( + std::optional("foo"s), + std::optional((make::tuple("foo"s, "bar"s)))))); + } + { + auto result = bp::parse( + "foofoobar", + -bp::string("foo") >> (-bp::string("foo") >> bp::string("bar"))); + EXPECT_TRUE(result); + EXPECT_EQ( + *result, + (make::tuple( + std::optional("foo"s), std::optional("foo"s), "bar"s))); + } + { + auto result = bp::parse( + "foo42", -bp::string("foo") >> (bp::string("foo") | bp::int_)); + EXPECT_TRUE(result); + EXPECT_EQ( + *result, + (make::tuple( + std::optional("foo"s), std::variant(42)))); + } + { + auto result = bp::parse( + "foobar", + -bp::string("foo") >> -(bp::string("foo") | bp::string("bar"))); + EXPECT_TRUE(result); + EXPECT_EQ( + *result, + (make::tuple(std::optional("foo"s), std::optional("bar"s)))); + } + { + auto result = bp::parse( + "foofoo", + -bp::string("foo") >> (-bp::string("foo") | bp::string("bar"))); + EXPECT_TRUE(result); + EXPECT_EQ( + *result, + (make::tuple( + "foo"s, + std::variant, std::string>( + std::optional("foo"s))))); + } + + // *P0 + { + auto result = bp::parse( + "foo foo", + bp::lexeme[*bp::string("foo")] >> bp::string("foo"), + bp::ws); + EXPECT_TRUE(result); + EXPECT_EQ(*result, std::vector({"foo"s, "foo"s})); + } + { + auto result = + bp::parse("foobar", *bp::string("foo") >> bp::string("bar")); + EXPECT_TRUE(result); + EXPECT_EQ(*result, std::vector({"foo"s, "bar"s})); + } + { + auto result = bp::parse("foo42", *bp::string("foo") >> bp::int_); + EXPECT_TRUE(result); + EXPECT_EQ(*result, (make::tuple(std::vector({"foo"s}), 42))); + } + { + auto result = bp::parse("fooc", *bp::string("foo") >> bp::char_('c')); + EXPECT_TRUE(result); + EXPECT_EQ(*result, (make::tuple(std::vector({"foo"s}), 'c'))); + } + { + auto result = bp::parse("foo", *bp::string("foo") >> bp::eps); + EXPECT_TRUE(result); + EXPECT_EQ(*result, std::vector({"foo"s})); + } + { + auto result = bp::parse( + "foo foo", + bp::lexeme[*bp::string("foo")] >> *bp::string("foo"), + bp::ws); + EXPECT_TRUE(result); + EXPECT_EQ( + *result, + (make::tuple(std::vector({"foo"s}), std::vector({"foo"s})))); + } + { + auto result = + bp::parse("foo", *bp::string("foo") >> -bp::string("foo")); + EXPECT_TRUE(result); + EXPECT_EQ(*result, std::vector({"foo"s})); + } + { + auto result = bp::parse( + "foo foo42", + bp::lexeme[*bp::string("foo")] >> (bp::string("foo") >> bp::int_), + bp::ws); + EXPECT_TRUE(result); + EXPECT_EQ(*result, (make::tuple(std::vector({"foo"s, "foo"s}), 42))); + } + { + auto result = bp::parse( + "foo foobar", + bp::lexeme[*bp::string("foo")] >> + -(bp::string("foo") >> bp::string("bar")), + bp::ws); + EXPECT_TRUE(result); + EXPECT_EQ( + *result, + (make::tuple( + std::vector({"foo"s}), + std::optional((make::tuple("foo"s, "bar"s)))))); + } + { + auto result = bp::parse( + "foo foobar", + bp::lexeme[*bp::string("foo")] >> + (-bp::string("foo") >> bp::string("bar")), + bp::ws); + EXPECT_TRUE(result); + EXPECT_EQ(*result, std::vector({"foo"s, "foo"s, "bar"s})); + } + { + auto result = bp::parse( + "foo 42", + bp::lexeme[*bp::string("foo")] >> (bp::string("foo") | bp::int_), + bp::ws); + EXPECT_TRUE(result); + EXPECT_EQ( + *result, + (make::tuple( + std::vector({"foo"s}), std::variant(42)))); + } + { + auto result = bp::parse( + "foo bar", + bp::lexeme[*bp::string("foo")] >> + -(bp::string("foo") | bp::string("bar")), + bp::ws); + EXPECT_TRUE(result); + EXPECT_EQ(*result, std::vector({"foo"s, "bar"s})); + } + { + auto result = bp::parse( + "foo", + bp::lexeme[*bp::string("foo")] >> + (-bp::string("foo") | bp::string("bar")), + bp::ws); + EXPECT_TRUE(result); + EXPECT_EQ( + *result, + (make::tuple( + std::vector({"foo"s}), + std::variant, std::string>( + std::nullopt)))); + } +} diff --git a/test/parser_seq_permutations_2.cpp b/test/parser_seq_permutations_2.cpp new file mode 100644 index 00000000..8cbd5d84 --- /dev/null +++ b/test/parser_seq_permutations_2.cpp @@ -0,0 +1,370 @@ +/** + * Copyright (C) 2024 T. Zachary Laine + * + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + */ + +#include + +#include + + +namespace bp = boost::parser; + +namespace make { + template + auto tuple(Ts &&... xs) + { + return bp::tuple((Ts &&) xs...); + } +} + +/* +{P0, -P0, *P0, P1, P2, P3, eps} + +{P0, P1, P2, P3, eps, *P0, -P0, (P0 >>/| P2), -(P0 >>/| P1), (-P0 >>/| P1)} + +P0 = bp::string("foo"); +P1 = bp::string("bar"); +P2 = bp::int_; +P3 = bp::char_('c'); +*/ + +using namespace std::literals; + +TEST(attributes, seq_parser_permutations_2) +{ + [[maybe_unused]] int dummy = 0; // for clang-format(!) + + // P1 + { + auto result = + bp::parse("barfoo", bp::string("bar") >> bp::string("foo")); + EXPECT_TRUE(result); + EXPECT_EQ(*result, (make::tuple("bar"s, "foo"s))); + } + { + auto result = + bp::parse("barbar", bp::string("bar") >> bp::string("bar")); + EXPECT_TRUE(result); + EXPECT_EQ(*result, (make::tuple("bar"s, "bar"s))); + } + { + auto result = bp::parse("bar42", bp::string("bar") >> bp::int_); + EXPECT_TRUE(result); + EXPECT_EQ(*result, (make::tuple("bar"s, 42))); + } + { + auto result = bp::parse("barc", bp::string("bar") >> bp::char_('c')); + EXPECT_TRUE(result); + EXPECT_EQ(*result, "barc"s); + } + { + auto result = bp::parse("bar", bp::string("bar") >> bp::eps); + EXPECT_TRUE(result); + EXPECT_EQ(*result, "bar"s); + } + { + auto result = + bp::parse("barfoofoo", bp::string("bar") >> *bp::string("foo")); + EXPECT_TRUE(result); + EXPECT_EQ(*result, std::vector({"bar"s, "foo"s, "foo"s})); + } + { + auto result = + bp::parse("barfoo", bp::string("bar") >> -bp::string("foo")); + EXPECT_TRUE(result); + EXPECT_EQ(*result, (make::tuple("bar"s, std::optional("foo"s)))); + } + { + auto result = bp::parse( + "barfoo42", bp::string("bar") >> (bp::string("foo") >> bp::int_)); + EXPECT_TRUE(result); + EXPECT_EQ(*result, (make::tuple("bar"s, "foo"s, 42))); + } + { + auto result = bp::parse( + "barfoobar", + bp::string("bar") >> -(bp::string("foo") >> bp::string("bar"))); + EXPECT_TRUE(result); + EXPECT_EQ( + *result, + (make::tuple("bar"s, std::optional(make::tuple("foo"s, "bar"s))))); + } + { + auto result = bp::parse( + "barfoobar", + bp::string("bar") >> (-bp::string("foo") >> bp::string("bar"))); + EXPECT_TRUE(result); + EXPECT_EQ( + *result, (make::tuple("bar"s, std::optional("foo"s), "bar"s))); + } + { + auto result = bp::parse( + "bar42", bp::string("bar") >> (bp::string("foo") | bp::int_)); + EXPECT_TRUE(result); + EXPECT_EQ( + *result, (make::tuple("bar"s, std::variant(42)))); + } + { + auto result = bp::parse( + "bar", + bp::string("bar") >> -(bp::string("foo") | bp::string("bar"))); + EXPECT_TRUE(result); + EXPECT_EQ(*result, (make::tuple("bar"s, std::optional{}))); + } + { + auto result = bp::parse( + "bar", + bp::string("bar") >> (-bp::string("foo") | bp::string("bar"))); + EXPECT_TRUE(result); + EXPECT_EQ( + *result, + make::tuple( + "bar"s, + std::variant, std::string>( + std::nullopt))); + } + + // P2 + { + auto result = bp::parse("42foo", bp::int_ >> bp::string("foo")); + EXPECT_TRUE(result); + EXPECT_EQ(*result, (make::tuple(42, "foo"s))); + } + { + auto result = bp::parse("42bar", bp::int_ >> bp::string("bar")); + EXPECT_TRUE(result); + EXPECT_EQ(*result, (make::tuple(42, "bar"s))); + } + { + auto result = bp::parse("42 42", bp::int_ >> bp::int_, bp::ws); + EXPECT_TRUE(result); + EXPECT_EQ(*result, (make::tuple(42, 42))); + } + { + auto result = bp::parse("42c", bp::int_ >> bp::char_('c')); + EXPECT_TRUE(result); + EXPECT_EQ(*result, (make::tuple(42, 'c'))); + } + { + auto result = bp::parse("42", bp::int_ >> bp::eps); + EXPECT_TRUE(result); + EXPECT_EQ(*result, 42); + } + { + auto result = bp::parse("42foofoo", bp::int_ >> *bp::string("foo")); + EXPECT_TRUE(result); + EXPECT_EQ(*result, (make::tuple(42, std::vector({"foo"s, "foo"s})))); + } + { + auto result = bp::parse("42foo", bp::int_ >> -bp::string("foo")); + EXPECT_TRUE(result); + EXPECT_EQ(*result, (make::tuple(42, std::optional("foo"s)))); + } + { + auto result = + bp::parse("42foo42", bp::int_ >> (bp::string("foo") >> bp::int_)); + EXPECT_TRUE(result); + EXPECT_EQ(*result, (make::tuple(42, "foo"s, 42))); + } + { + auto result = bp::parse( + "42foobar", bp::int_ >> -(bp::string("foo") >> bp::string("bar"))); + EXPECT_TRUE(result); + EXPECT_EQ( + *result, + (make::tuple(42, std::optional(make::tuple("foo"s, "bar"s))))); + } + { + auto result = bp::parse( + "42foobar", bp::int_ >> (-bp::string("foo") >> bp::string("bar"))); + EXPECT_TRUE(result); + EXPECT_EQ(*result, (make::tuple(42, std::optional("foo"s), "bar"s))); + } + { + auto result = bp::parse( + "42 42", bp::int_ >> (bp::string("foo") | bp::int_), bp::ws); + EXPECT_TRUE(result); + EXPECT_EQ( + *result, (make::tuple(42, std::variant(42)))); + } + { + auto result = bp::parse( + "42", bp::int_ >> -(bp::string("foo") | bp::string("bar"))); + EXPECT_TRUE(result); + EXPECT_EQ(*result, (make::tuple(42, std::optional{}))); + } + { + auto result = bp::parse( + "42", bp::int_ >> (-bp::string("foo") | bp::string("bar"))); + EXPECT_TRUE(result); + EXPECT_EQ( + *result, + make::tuple( + 42, + std::variant, std::string>( + std::nullopt))); + } + + // P3 + { + auto result = bp::parse("cfoo", bp::char_('c') >> bp::string("foo")); + EXPECT_TRUE(result); + EXPECT_EQ(*result, "cfoo"s); + } + { + auto result = bp::parse("cbar", bp::char_('c') >> bp::string("bar")); + EXPECT_TRUE(result); + EXPECT_EQ(*result, "cbar"s); + } + { + auto result = bp::parse("c42", bp::char_('c') >> bp::int_); + EXPECT_TRUE(result); + EXPECT_EQ(*result, (make::tuple('c', 42))); + } + { + auto result = bp::parse("cc", bp::char_('c') >> bp::char_('c')); + EXPECT_TRUE(result); + EXPECT_EQ(*result, "cc"s); + } + { + auto result = bp::parse("c", bp::char_('c') >> bp::eps); + EXPECT_TRUE(result); + EXPECT_EQ(*result, 'c'); + } + { + auto result = + bp::parse("cfoofoo", bp::char_('c') >> *bp::string("foo")); + EXPECT_TRUE(result); + EXPECT_EQ(*result, (make::tuple('c', std::vector({"foo"s, "foo"s})))); + } + { + auto result = bp::parse("cfoo", bp::char_('c') >> -bp::string("foo")); + EXPECT_TRUE(result); + EXPECT_EQ(*result, (make::tuple('c', std::optional("foo"s)))); + } + { + auto result = bp::parse( + "cfoo42", bp::char_('c') >> (bp::string("foo") >> bp::int_)); + EXPECT_TRUE(result); + EXPECT_EQ(*result, (make::tuple("cfoo"s, 42))); + } + { + auto result = bp::parse( + "cfoobar", + bp::char_('c') >> -(bp::string("foo") >> bp::string("bar"))); + EXPECT_TRUE(result); + EXPECT_EQ( + *result, + (make::tuple('c', std::optional(make::tuple("foo"s, "bar"s))))); + } + { + auto result = bp::parse( + "cfoobar", + bp::char_('c') >> (-bp::string("foo") >> bp::string("bar"))); + EXPECT_TRUE(result); + EXPECT_EQ(*result, (make::tuple('c', std::optional("foo"s), "bar"s))); + } + { + auto result = + bp::parse("c42", bp::char_('c') >> (bp::string("foo") | bp::int_)); + EXPECT_TRUE(result); + EXPECT_EQ( + *result, (make::tuple('c', std::variant(42)))); + } + { + auto result = bp::parse( + "c", bp::char_('c') >> -(bp::string("foo") | bp::string("bar"))); + EXPECT_TRUE(result); + EXPECT_EQ(*result, (make::tuple('c', std::optional{}))); + } + { + auto result = bp::parse( + "c", bp::char_('c') >> (-bp::string("foo") | bp::string("bar"))); + EXPECT_TRUE(result); + EXPECT_EQ( + *result, + (make::tuple( + 'c', + std::variant, std::string>( + std::nullopt)))); + } + + // eps + { + auto result = bp::parse("foo", bp::eps >> bp::string("foo")); + EXPECT_TRUE(result); + EXPECT_EQ(*result, "foo"s); + } + { + auto result = bp::parse("bar", bp::eps >> bp::string("bar")); + EXPECT_TRUE(result); + EXPECT_EQ(*result, "bar"s); + } + { + auto result = bp::parse("42", bp::eps >> bp::int_); + EXPECT_TRUE(result); + EXPECT_EQ(*result, 42); + } + { + auto result = bp::parse("c", bp::eps >> bp::char_('c')); + EXPECT_TRUE(result); + EXPECT_EQ(*result, 'c'); + } + { + auto result = bp::parse("", bp::eps >> bp::eps); + EXPECT_TRUE(result); + } + { + auto result = bp::parse("foofoo", bp::eps >> *bp::string("foo")); + EXPECT_TRUE(result); + EXPECT_EQ(*result, std::vector({"foo"s, "foo"s})); + } + { + auto result = bp::parse("foo", bp::eps >> -bp::string("foo")); + EXPECT_TRUE(result); + EXPECT_EQ(*result, std::optional("foo"s)); + } + { + auto result = + bp::parse("foo42", bp::eps >> (bp::string("foo") >> bp::int_)); + EXPECT_TRUE(result); + EXPECT_EQ(*result, (make::tuple("foo"s, 42))); + } + { + auto result = bp::parse( + "foobar", bp::eps >> -(bp::string("foo") >> bp::string("bar"))); + EXPECT_TRUE(result); + EXPECT_EQ(*result, std::optional((make::tuple("foo"s, "bar"s)))); + } + { + auto result = bp::parse( + "foobar", bp::eps >> (-bp::string("foo") >> bp::string("bar"))); + EXPECT_TRUE(result); + EXPECT_EQ(*result, (make::tuple(std::optional("foo"s), "bar"s))); + } + { + auto result = + bp::parse("42", bp::eps >> (bp::string("foo") | bp::int_)); + EXPECT_TRUE(result); + EXPECT_EQ(*result, (std::variant(42))); + } + { + auto result = + bp::parse("", bp::eps >> -(bp::string("foo") | bp::string("bar"))); + EXPECT_TRUE(result); + EXPECT_EQ(*result, std::optional{}); + } + { + auto result = + bp::parse("", bp::eps >> (-bp::string("foo") | bp::string("bar"))); + EXPECT_TRUE(result); + EXPECT_EQ( + *result, + (std::variant, std::string>( + std::nullopt))); + } +}