/** * 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 #if __has_include() #define TEST_BOOST_OPTIONAL 1 #include #else #define TEST_BOOST_OPTIONAL 0 #endif #include #include using namespace boost::parser; void github_issue_36() { namespace bp = boost::parser; auto id = bp::lexeme[+bp::char_( "ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz0123456789")]; auto ids = +id; std::string str; std::vector vec; bp::parse("id1", id, bp::ws, str); // (1) BOOST_TEST(str == "id1"); str.clear(); bp::parse("id1 id2", ids, bp::ws, vec); // (2) BOOST_TEST(vec == std::vector({"id1", "id2"})); // Intentionally ill-formed. // bp::parse("i1 i2", ids, bp::ws, str); // (3) } namespace issue_50 { struct X { char a; int b; bool operator<(X rhs) const { return a < rhs.a; } }; struct Y { std::vector x; int c; }; struct Y2 { std::set x; int c; }; static_assert( boost::parser::detail::is_struct_compatible< Y, boost::parser:: tuple>, int>>()); static_assert( boost::parser::detail::is_struct_compatible< Y2, boost::parser:: tuple>, int>>()); } void github_issue_50() { using namespace issue_50; namespace bp = boost::parser; { auto parse_x = bp::char_ >> bp::int_; auto parse_y = +parse_x >> bp::int_; Y y; auto b = bp::parse("d 3 4", parse_y, bp::ws, y); BOOST_TEST(b); BOOST_TEST(y.x[0].a == 'd'); BOOST_TEST(y.x[0].b == 3); BOOST_TEST(y.c == 4); } { auto parse_x = bp::char_ >> bp::int_; auto parse_y = +parse_x >> bp::int_; Y2 y; auto b = bp::parse("d 3 4", parse_y, bp::ws, y); BOOST_TEST(b); BOOST_TEST(y.x.begin()->a == 'd'); BOOST_TEST(y.x.begin()->b == 3); BOOST_TEST(y.c == 4); } } namespace issue_52 { struct X { char a; int b; }; struct Y { std::vector x; int c; }; struct Z { std::vector y; int d; }; struct W { std::vector z; int e; }; } void github_issue_52() { using namespace issue_52; namespace bp = boost::parser; auto parse_x = bp::char_ >> bp::int_; auto parse_y = +parse_x >> bp::int_; auto parse_z = +parse_y >> bp::char_; auto parse_w = +parse_z >> bp::int_; { Z z; auto b = bp::parse("d 2 3 c", parse_z, bp::ws, z); BOOST_TEST(b); BOOST_TEST(z.y[0].x[0].a == 'd'); BOOST_TEST(z.y[0].x[0].b == 2); BOOST_TEST(z.y[0].c == 3); BOOST_TEST(z.d == 'c'); } { W w; auto b = bp::parse("d 2 3 c 4", parse_w, bp::ws, w); BOOST_TEST(b); BOOST_TEST(w.z[0].y[0].x[0].a == 'd'); BOOST_TEST(w.z[0].y[0].x[0].b == 2); BOOST_TEST(w.z[0].y[0].c == 3); BOOST_TEST(w.z[0].d == 'c'); BOOST_TEST(w.e == 4); } } void github_issue_78() { namespace bp = boost::parser; std::vector result; auto b = bp::parse("3 4 c", +bp::int_, bp::ws, result); BOOST_TEST(!b); BOOST_TEST(result.empty()); } namespace issue_90 { namespace parser { const auto string = ('"' >> boost::parser::lexeme[*(boost::parser::char_ - '"')]) > '"'; const auto specifier = string > ':' > string; }} void github_issue_90() { using namespace issue_90; namespace bp = boost::parser; std::string input = R"( "dd" : "2" )"; std::pair result; auto b = bp::parse(input, parser::specifier, bp::ws, result); BOOST_TEST(b); BOOST_TEST(result.first == "dd"); BOOST_TEST(result.second == "2"); } namespace github_issue_125_ { namespace bp = boost::parser; constexpr bp:: rule> replacement_field = "replacement_field"; constexpr auto replacement_field_def = bp::lit('{') >> -bp::ushort_; BOOST_PARSER_DEFINE_RULES(replacement_field); } void github_issue_125() { namespace bp = boost::parser; using namespace github_issue_125_; unsigned short integer_found = 99; auto print_repl_field = [&](auto & ctx) { const std::optional & val = bp::_attr(ctx); if (val) integer_found = *val; else integer_found = 77; }; { integer_found = 99; auto result = bp::parse("{9", replacement_field[print_repl_field]); BOOST_TEST(result); BOOST_TEST(integer_found == 9); } { integer_found = 99; auto result = bp::parse("{", replacement_field[print_repl_field]); BOOST_TEST(result); BOOST_TEST(integer_found == 77); } } void github_issue_209() { namespace bp = boost::parser; BOOST_TEST(std::is_sorted( std::begin(bp::detail::char_set::chars), std::end(bp::detail::char_set::chars))); BOOST_TEST(std::is_sorted( std::begin(bp::detail::char_set::chars), std::end(bp::detail::char_set::chars))); BOOST_TEST(std::is_sorted( std::begin(bp::detail::char_set::chars), std::end(bp::detail::char_set::chars))); BOOST_TEST(std::is_sorted( std::begin(bp::detail::char_set::chars), std::end(bp::detail::char_set::chars))); } void github_issue_223() { namespace bp = boost::parser; // failing case { std::vector v; const auto parser = *('x' | bp::char_('y')); bp::parse("xy", parser, bp::ws, v); BOOST_TEST(v.size() == 1); BOOST_TEST(v == std::vector({'y'})); // the assert fails since there are two elements in the vector: '\0' // and 'y'. Seems pretty surprising to me } // working case { const auto parser = *('x' | bp::char_('y')); const auto result = bp::parse("xy", parser, bp::ws); BOOST_TEST(result->size() == 1); BOOST_TEST(*(*result)[0] == 'y'); // success, the vector has only one 'y' element } } namespace github_issue_248_ { namespace bp = boost::parser; static constexpr bp::rule symbol = "//"; static constexpr bp::rule> list = "(,)*"; static constexpr bp::rule> working = "working"; static constexpr bp::rule> failing = "failing"; static auto const symbol_def = bp::symbols{{"//", 0}}; static constexpr auto list_def = bp::int_ % ','; static constexpr auto working_def = -symbol >> (bp::int_ % ','); static constexpr auto failing_def = -symbol >> list; BOOST_PARSER_DEFINE_RULES(symbol, list, working, failing); } void github_issue_248() { namespace bp = boost::parser; using namespace github_issue_248_; { auto const result = bp::parse("//1,2,3", working, bp::ws); auto const expected = std::vector{0, 1, 2, 3}; BOOST_TEST(result.has_value()); bool const equal = std::equal( result->begin(), result->end(), expected.begin(), expected.end()); BOOST_TEST(equal); if (!equal) { std::cout << "contents of *result:\n"; for (auto x : *result) { std::cout << x << '\n'; } std::cout << '\n'; } } { auto const result = bp::parse("//1,2,3", failing, bp::ws); auto const expected = std::vector{0, 1, 2, 3}; BOOST_TEST(result.has_value()); bool const equal = std::equal( result->begin(), result->end(), expected.begin(), expected.end()); BOOST_TEST(equal); if (!equal) { std::cout << "contents of *result:\n"; for (auto x : *result) { std::cout << x << '\n'; } std::cout << '\n'; } } } #if BOOST_PARSER_USE_CONCEPTS namespace github_issue_268_ { namespace bp = boost::parser; constexpr bp::rule name = "name"; auto name_def = bp::string_view[bp::lexeme[+( bp::lower | bp::upper | bp::digit | bp::char_("_"))]]; BOOST_PARSER_DEFINE_RULES(name) constexpr bp::rule> qd_vec = "qd_vec"; auto qd_vec_def = bp::lit("\"") >> bp::double_ % (bp::lit(",") | (bp::lit("\"") >> bp::lit(",") >> bp::lit("\""))) >> bp::lit('\"'); BOOST_PARSER_DEFINE_RULES(qd_vec) struct lu_table_template_1 { std::vector index_1; std::string_view variable_1; }; constexpr boost::parser:: rule lu_table_template_1_rule = "lu_table_template_1"; auto lu_table_template_1_rule_def = (bp::lit("index_1") >> '(' >> qd_vec >> ')' >> ';') >> (bp::lit("variable_1") >> ':' >> name >> ';'); BOOST_PARSER_DEFINE_RULES(lu_table_template_1_rule) constexpr boost::parser:: rule lu_table_template_1_permut_rule = "lu_table_template_1"; auto lu_table_template_1_permut_rule_def = (bp::lit("index_1") >> '(' >> qd_vec >> ')' >> ';') || (bp::lit("variable_1") >> ':' >> name >> ';'); BOOST_PARSER_DEFINE_RULES(lu_table_template_1_permut_rule) } #endif void github_issue_268() { #if BOOST_PARSER_USE_CONCEPTS namespace bp = boost::parser; using namespace github_issue_268_; std::string inputstring = "index_1 ( \"1\" ) ; variable_1 : bier;"; auto const def_result = bp::parse( inputstring, lu_table_template_1_rule_def, bp::blank, bp::trace::off); std::cout << "seq_parser generates this type:\n" << typeid(def_result.value()).name() << std::endl; BOOST_TEST(def_result); auto const permut_def_result = bp::parse( inputstring, lu_table_template_1_permut_rule_def, bp::blank, bp::trace::off); std::cout << "permut_parser generates this type:\n" << typeid(permut_def_result.value()).name() << std::endl; BOOST_TEST(permut_def_result); auto const result = bp::parse( inputstring, lu_table_template_1_rule, bp::blank, bp::trace::off); std::cout << "seq_parser in rule generates this type:\n" << typeid(result.value()).name() << std::endl; BOOST_TEST(result); auto const permut_result = bp::parse( inputstring, lu_table_template_1_permut_rule, bp::blank, bp::trace::off); std::cout << "permut_parser generates this type:\n" << typeid(permut_result.value()).name() << std::endl; BOOST_TEST(permut_result); #endif } void github_issue_279() { namespace bp = boost::parser; { constexpr auto condition_clause = bp::lit(U"while") > bp::lit(U"someexpression") >> bp::attr(true); constexpr auto do_statement = bp::lexeme[bp::lit(U"do") >> &bp::ws] > -condition_clause > bp::eol; auto const result = bp::parse(U"do\n", do_statement, bp::blank, bp::trace::off); BOOST_TEST(result); std::optional const & condition = result.value(); BOOST_TEST(!condition.has_value()); } { constexpr auto condition_clause = bp::lit(U"while") > bp::lit(U"someexpression") >> bp::attr(true); constexpr auto do_statement_reverse = -condition_clause > bp::lexeme[bp::lit(U"do") >> &bp::ws] > bp::eol; auto const result = bp::parse(U"do\n", do_statement_reverse, bp::blank, bp::trace::off); BOOST_TEST(result); std::optional const & condition = result.value(); BOOST_TEST(!condition.has_value()); } } namespace github_issue_285_ { namespace bp = boost::parser; struct Content { ~Content() { int setbreakpointhere = 0; (void)setbreakpointhere; } }; constexpr bp::rule> content = "content"; constexpr auto content_action = [](auto & ctx) { std::shared_ptr & result = _val(ctx); result = std::make_shared(); }; constexpr auto content_def = (bp::lit(U"content") >> bp::eol)[content_action]; BOOST_PARSER_DEFINE_RULES(content); } void github_issue_285() { using namespace github_issue_285_; namespace bp = boost::parser; constexpr auto prolog = bp::lit(U"prolog") >> bp::eol; constexpr auto epilog = bp::no_case[bp::lexeme[bp::lit(U"epi") >> bp::lit(U"log")]] >> bp::eol; constexpr auto full_parser = prolog >> content >> epilog; std::string teststring = "prolog\n" "content\n" "epilog\n"; // "content" produces a shared_ptr with the result. // The "epilog" parser must not delete the result. auto const result = bp::parse(teststring, full_parser, bp::blank); BOOST_TEST(result); BOOST_TEST(result.value().get() != nullptr); } int main() { github_issue_36(); github_issue_50(); github_issue_52(); github_issue_78(); github_issue_90(); github_issue_125(); github_issue_209(); github_issue_223(); github_issue_248(); github_issue_268(); github_issue_279(); github_issue_285(); return boost::report_errors(); }