Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion include/boost/parser/detail/printing.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
10 changes: 5 additions & 5 deletions include/boost/parser/parser.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand All @@ -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);
}
Expand Down Expand Up @@ -4328,7 +4328,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;
}
Expand Down Expand Up @@ -5485,7 +5485,7 @@ namespace boost { namespace parser {
dont_assign);
if (success && !dont_assign) {
if constexpr (!detail::is_nope_v<decltype(attr)>)
detail::assign(retval, attr);
detail::assign(retval, std::move(attr));
}
}

Expand Down Expand Up @@ -5580,7 +5580,7 @@ namespace boost { namespace parser {
container<Attribute_> && container<attr_type>) {
detail::move_back(retval, attr, detail::gen_attrs(flags));
} else {
detail::assign(retval, attr);
detail::assign(retval, std::move(attr));
}
}
}
Expand Down
181 changes: 181 additions & 0 deletions test/github_issues.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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()
{
Expand All @@ -615,5 +795,6 @@ int main()
github_pr_290();
github_issue_294();
github_pr_297();
github_issue_312();
return boost::report_errors();
}
Loading