2
0
mirror of https://github.com/boostorg/parser.git synced 2026-02-21 03:12:08 +00:00

Allow move-only attributes

This tests the usage of move-only attributes.
parser.hpp and printing.hpp are slightly modified to make it work.
This commit is contained in:
Andreas Buhr
2026-02-03 13:54:58 +01:00
committed by Zach Laine
parent 316b4921a9
commit 1b984e3546
3 changed files with 185 additions and 4 deletions

View File

@@ -593,7 +593,7 @@ namespace boost { namespace parser { namespace detail {
}
template<typename Context, typename T>
auto resolve(Context const & context, T const & x);
decltype(auto) resolve(Context const & context, T const & x);
template<typename Context>
auto resolve(Context const &, nope n);

View File

@@ -1020,7 +1020,7 @@ namespace boost { namespace parser {
bool Callable = is_detected_v<callable, T const &, Context const &>>
struct resolve_impl
{
static auto call(Context const &, T const & x) { return x; }
static auto& call(Context const &, T const & x) { return x; }
};
template<typename Context, typename T>
@@ -1033,7 +1033,7 @@ namespace boost { namespace parser {
};
template<typename Context, typename T>
auto resolve(Context const & context, T const & x)
decltype(auto) resolve(Context const & context, T const & x)
{
return resolve_impl<Context, T>::call(context, x);
}
@@ -4331,7 +4331,7 @@ namespace boost { namespace parser {
// A 1-tuple is converted to a scalar.
if constexpr (detail::hl::size(retval) == llong<1>{}) {
using namespace literals;
return parser::get(retval, 0_c);
return parser::get(std::move(retval), 0_c);
} else {
return retval;
}

View File

@@ -597,6 +597,186 @@ void github_pr_297()
}
}
namespace github_issue_312_ {
/*
* Recursive descent parser for expressions.
* Supports addition (+), multiplication (*) and
* parethesized expressions, nothing else.
*
* Creates a tree of "evaluatable" objects which
* own their downstream objects in a unique_ptr
*/
// base class for all tree nodes
struct evaluatable
{
virtual double evaluate() = 0;
virtual ~evaluatable() = default;
};
namespace bp = boost::parser;
// top level parser
constexpr bp::rule<struct expression_tag, std::unique_ptr<evaluatable>> expression_parser = "expression_parser";
/*
* LITERAL EXPRESSION
*/
struct literal_evaluatable : evaluatable
{
explicit literal_evaluatable(double v) : value_(v) {}
double evaluate() override
{
return value_;
}
double value_;
};
constexpr bp::rule<struct literal_tag, std::unique_ptr<evaluatable>> literal_parser = "literal_parser";
constexpr auto literal_parser_action = [](auto& ctx) {
std::unique_ptr<evaluatable>& val = _val(ctx);
double& parsed_value = _attr(ctx);
val = std::make_unique<literal_evaluatable>(parsed_value);
};
constexpr auto literal_parser_def =
bp::double_[literal_parser_action];
/*
* PARENTHESIZED EXPRESSION
*/
struct parenthesized_evaluatable : evaluatable
{
explicit parenthesized_evaluatable(std::unique_ptr<evaluatable>&& e) : evaluatable_(std::move(e)) {}
double evaluate() override
{
return evaluatable_->evaluate();
}
std::unique_ptr<evaluatable> evaluatable_;
};
constexpr bp::rule<struct parenthesized_tag, std::unique_ptr<evaluatable>> parenthesized_parser = "parenthesized_parser";
constexpr auto parenthesized_action = [](auto& ctx) {
std::unique_ptr<evaluatable>& val = _val(ctx);
std::unique_ptr<evaluatable>& attr = _attr(ctx);
val = std::make_unique<parenthesized_evaluatable>(std::move(attr));
};
constexpr auto parenthesized_parser_def =
(
bp::lit('(') > expression_parser > bp::lit(')')
)[parenthesized_action];
/*
* ATOM EXPRESSION
*/
struct atom_evaluatable : evaluatable
{
explicit atom_evaluatable(std::unique_ptr<evaluatable>&& e) : evaluatable_(std::move(e)) {}
double evaluate() override
{
return evaluatable_->evaluate();
}
std::unique_ptr<evaluatable> evaluatable_;
};
constexpr bp::rule<struct atom_tag, std::unique_ptr<evaluatable>> atom_parser = "atom_parser";
constexpr auto atom_action = [](auto& ctx) {
std::unique_ptr<evaluatable>& val = _val(ctx);
std::unique_ptr<evaluatable>& attr = _attr(ctx);
val = std::make_unique<atom_evaluatable>(std::move(attr));
};
constexpr auto atom_parser_def =
(
parenthesized_parser
|
literal_parser
)[atom_action];
/*
* MULTIPLICATION EXPRESSION
*/
struct multiplication_evaluatable : evaluatable
{
multiplication_evaluatable(std::vector<std::unique_ptr<evaluatable>>&& e)
: evaluatables_(std::move(e))
{}
double evaluate() override
{
double result = 1;
for (const auto& e : evaluatables_) {
result *= e->evaluate();
}
return result;
}
std::vector<std::unique_ptr<evaluatable>> evaluatables_;
};
constexpr bp::rule<struct mult_tag, std::unique_ptr<evaluatable>> mult_parser = "mult_parser";
constexpr auto mult_parser_action = [](auto& ctx) {
std::unique_ptr<evaluatable>& val = _val(ctx);
std::vector<std::unique_ptr<evaluatable>>& operands = _attr(ctx);
val = std::make_unique<multiplication_evaluatable>(std::move(operands));
};
constexpr auto mult_parser_def =
(atom_parser % bp::lit('*'))[mult_parser_action];
/*
* ADDITION EXPRESSION
*/
struct addition_evaluatable : evaluatable
{
addition_evaluatable(std::vector<std::unique_ptr<evaluatable>>&& e)
: evaluatables_(std::move(e))
{}
double evaluate() override
{
double result = 0;
for (const auto& e : evaluatables_) {
result += e->evaluate();
}
return result;
}
std::vector<std::unique_ptr<evaluatable>> evaluatables_;
};
constexpr bp::rule<struct add_tag, std::unique_ptr<evaluatable>> add_parser = "add_parser";
constexpr auto add_parser_action = [](auto& ctx) {
std::unique_ptr<evaluatable>& val = _val(ctx);
std::vector<std::unique_ptr<evaluatable>>& operands = _attr(ctx);
val = std::make_unique<addition_evaluatable>(std::move(operands));
};
constexpr auto add_parser_def =
(mult_parser % bp::lit('+'))[add_parser_action];
constexpr auto expression_parser_action = [](auto& ctx) {
std::unique_ptr<evaluatable>& val = _val(ctx);
std::unique_ptr<evaluatable>& attr = _attr(ctx);
val = std::move(attr);
};
/*
* EXPRESSION
*/
constexpr auto expression_parser_def =
add_parser[expression_parser_action];
BOOST_PARSER_DEFINE_RULES(
literal_parser,
mult_parser,
add_parser,
expression_parser,
parenthesized_parser,
atom_parser);
}
void github_issue_312()
{
namespace bp = boost::parser;
using namespace github_issue_312_;
auto result = bp::parse("(2 + 3) + 3.1415 * 2", expression_parser, bp::blank);
BOOST_TEST(result);
BOOST_TEST(result.value()->evaluate() == (2 + 3) + 3.1415 * 2);
result = bp::parse("((2*0.1) + 33.) * (2 + 3) + 3.1415 * 2", expression_parser, bp::blank);
BOOST_TEST(result);
BOOST_TEST(result.value()->evaluate() == ((2*0.1) + 33.) * (2 + 3) + 3.1415 * 2);
}
int main()
{
@@ -615,5 +795,6 @@ int main()
github_pr_290();
github_issue_294();
github_pr_297();
github_issue_312();
return boost::report_errors();
}