From 4adb0abb6453e7ec499c70c1c82c488c5bea56de Mon Sep 17 00:00:00 2001 From: artemp Date: Mon, 25 Aug 2014 14:17:18 +0100 Subject: [PATCH] expressions - implement unary and binary function expression nodes (sample functions: exp, pow, sin, cos, min, max, tan, atan) --- include/mapnik/evaluate_global_attributes.hpp | 23 +++++- include/mapnik/expression_evaluator.hpp | 12 ++- include/mapnik/expression_grammar.hpp | 77 +++++++++++++++++-- include/mapnik/expression_grammar_impl.hpp | 7 +- include/mapnik/expression_node.hpp | 30 +++++--- include/mapnik/expression_node_types.hpp | 6 +- src/expression_string.cpp | 8 +- 7 files changed, 134 insertions(+), 29 deletions(-) diff --git a/include/mapnik/evaluate_global_attributes.hpp b/include/mapnik/evaluate_global_attributes.hpp index 0609cf5b0..502552c4c 100644 --- a/include/mapnik/evaluate_global_attributes.hpp +++ b/include/mapnik/evaluate_global_attributes.hpp @@ -126,9 +126,17 @@ struct evaluate_expression : util::static_visitor #endif } - value_type operator() (function_call const& fun) const + value_type operator() (unary_function_call const& call) const { - return value_type(123);// FIXME + value_type arg = util::apply_visitor(*this, call.arg); + return call.fun(arg); + } + + value_type operator() (binary_function_call const& call) const + { + value_type arg1 = util::apply_visitor(*this, call.arg1); + value_type arg2 = util::apply_visitor(*this, call.arg2); + return call.fun(arg1, arg2); } template @@ -217,11 +225,18 @@ struct evaluate_expression : util::static_visitor #endif } - value_type operator() (function_call const& fun) const + value_type operator() (unary_function_call const& call) const { - return value_type(123);// FIXME + value_type arg = util::apply_visitor(*this, call.arg); + return call.fun(arg); } + value_type operator() (binary_function_call const& call) const + { + value_type arg1 = util::apply_visitor(*this, call.arg1); + value_type arg2 = util::apply_visitor(*this, call.arg2); + return call.fun(arg1, arg2); + } template value_type operator() (ValueType const& val) const diff --git a/include/mapnik/expression_evaluator.hpp b/include/mapnik/expression_evaluator.hpp index 45475655f..0842a9dfd 100644 --- a/include/mapnik/expression_evaluator.hpp +++ b/include/mapnik/expression_evaluator.hpp @@ -149,9 +149,17 @@ struct evaluate : util::static_visitor #endif } - value_type operator() (function_call const& fun) const + value_type operator() (unary_function_call const& call) const { - return value_integer(123);// FIXME + value_type arg = util::apply_visitor(*this, call.arg); + return call.fun(arg); + } + + value_type operator() (binary_function_call const& call) const + { + value_type arg1 = util::apply_visitor(*this, call.arg1); + value_type arg2 = util::apply_visitor(*this, call.arg2); + return call.fun(arg1, arg2); } feature_type const& feature_; diff --git a/include/mapnik/expression_grammar.hpp b/include/mapnik/expression_grammar.hpp index 773dc7f89..b4422bb9c 100644 --- a/include/mapnik/expression_grammar.hpp +++ b/include/mapnik/expression_grammar.hpp @@ -39,8 +39,15 @@ // stl #include -BOOST_FUSION_ADAPT_STRUCT(mapnik::function_call, - (mapnik::function_impl, fun)(mapnik::function_call::arguments_type, arguments)) +BOOST_FUSION_ADAPT_STRUCT(mapnik::unary_function_call, + (mapnik::unary_function_impl, fun) + (mapnik::unary_function_call::argument_type, arg)) + +BOOST_FUSION_ADAPT_STRUCT(mapnik::binary_function_call, + (mapnik::binary_function_impl, fun) + (mapnik::binary_function_call::argument_type, arg1) + (mapnik::binary_function_call::argument_type, arg2)) + namespace mapnik { @@ -122,16 +129,68 @@ inline value_type exp_impl (value_type const& val) { return std::exp(val.to_double()); } - -struct function_types : qi::symbols +// sin +inline value_type sin_impl (value_type const& val) { - function_types() + return std::sin(val.to_double()); +} +// cos +inline value_type cos_impl (value_type const& val) +{ + return std::cos(val.to_double()); +} +// tan +inline value_type tan_impl (value_type const& val) +{ + return std::tan(val.to_double()); +} +// atan +inline value_type atan_impl (value_type const& val) +{ + return std::atan(val.to_double()); +} + +struct unary_function_types : qi::symbols +{ + unary_function_types() { add - ("exp", unary_function_impl { &exp_impl }) + ("sin", unary_function_impl(sin_impl)) + ("cos", unary_function_impl(cos_impl)) + ("tan", unary_function_impl(tan_impl)) + ("atan", unary_function_impl(atan_impl)) + ("exp", unary_function_impl(exp_impl)) ; } +}; +// binary functions +// min +inline value_type min_impl(value_type const& arg1, value_type const& arg2) +{ + return std::min(arg1.to_double(), arg2.to_double()); +} +// max +inline value_type max_impl(value_type const& arg1, value_type const& arg2) +{ + return std::max(arg1.to_double(), arg2.to_double()); +} +// pow +inline value_type pow_impl(value_type const& arg1, value_type const& arg2) +{ + return std::pow(arg1.to_double(), arg2.to_double()); +} + +struct binary_function_types : qi::symbols +{ + binary_function_types() + { + add + ("min", binary_function_impl(min_impl)) + ("max", binary_function_impl(max_impl)) + ("pow", binary_function_impl(pow_impl)) + ; + } }; template @@ -168,7 +227,8 @@ struct expression_grammar : qi::grammar rule_type unary_expr; rule_type not_expr; rule_type primary_expr; - qi::rule function_expr; + qi::rule unary_function_expr; + qi::rule binary_function_expr; qi::rule regex_match_expr; qi::rule, space_type> regex_replace_expr; qi::rule attr; @@ -179,7 +239,8 @@ struct expression_grammar : qi::grammar qi::symbols unesc_char; qi::rule quote_char; geometry_types geom_type; - function_types func_type; + unary_function_types unary_func_type; + binary_function_types binary_func_type; }; } // namespace diff --git a/include/mapnik/expression_grammar_impl.hpp b/include/mapnik/expression_grammar_impl.hpp index 68ea0148c..2a79b4fc3 100644 --- a/include/mapnik/expression_grammar_impl.hpp +++ b/include/mapnik/expression_grammar_impl.hpp @@ -150,7 +150,10 @@ expression_grammar::expression_grammar(std::string const& encoding) ) ; - function_expr = func_type >> lit('(') >> expr >> lit(')') + unary_function_expr = unary_func_type > lit('(') > expr > lit(')') + ; + + binary_function_expr = binary_func_type > lit('(') > expr > lit(',') > expr > lit(')') ; unary_expr = primary_expr [_val = _1] @@ -169,6 +172,8 @@ expression_grammar::expression_grammar(std::string const& encoding) | attr [_val = construct( _1 ) ] | global_attr [_val = construct( _1 )] | lit("not") >> expr [_val = !_1] + | unary_function_expr [_val = _1] + | binary_function_expr [_val = _1] | '(' >> expr [_val = _1 ] >> ')' | ustring[_val = unicode_(_1)] // if we get here then try parsing as unquoted string ; diff --git a/include/mapnik/expression_node.hpp b/include/mapnik/expression_node.hpp index c476db850..7ec5a13a3 100644 --- a/include/mapnik/expression_node.hpp +++ b/include/mapnik/expression_node.hpp @@ -36,6 +36,7 @@ #include #endif +#include #include namespace mapnik @@ -125,23 +126,32 @@ struct regex_replace_node }; #endif -using nullary_function_impl = std::function; using unary_function_impl = std::function; using binary_function_impl = std::function; -typedef util::variant function_impl; - -struct function_call +struct unary_function_call { - using arguments_type = std::vector; - function_call(function_impl fun, arguments_type const& arguments) - : fun(fun), arguments(arguments) { } + using argument_type = expr_node; + unary_function_call() = default; + unary_function_call(unary_function_impl fun, argument_type const& arg) + : fun(fun), arg(arg) {} - function_impl fun; - arguments_type arguments; + unary_function_impl fun; + argument_type arg; }; -inline expr_node& operator- (expr_node& expr) +struct binary_function_call +{ + using argument_type = expr_node; + binary_function_call() = default; + binary_function_call(binary_function_impl fun, argument_type const& arg1, argument_type const& arg2) + : fun(fun), arg1(arg1), arg2(arg2) {} + binary_function_impl fun; + argument_type arg1; + argument_type arg2; +}; + +inline expr_node & operator- (expr_node& expr) { return expr = unary_node(expr); } diff --git a/include/mapnik/expression_node_types.hpp b/include/mapnik/expression_node_types.hpp index 2e4fe3c26..665b8080d 100644 --- a/include/mapnik/expression_node_types.hpp +++ b/include/mapnik/expression_node_types.hpp @@ -163,7 +163,8 @@ struct regex_replace_node; struct attribute; struct global_attribute; struct geometry_type_attribute; -struct function_call; +struct unary_function_call; +struct binary_function_call; using expr_node = util::variant< value_null, @@ -191,7 +192,8 @@ util::recursive_wrapper >, util::recursive_wrapper >, util::recursive_wrapper, util::recursive_wrapper, -util::recursive_wrapper +util::recursive_wrapper, +util::recursive_wrapper >; } diff --git a/src/expression_string.cpp b/src/expression_string.cpp index a1dfa0c87..c1d3a4c22 100644 --- a/src/expression_string.cpp +++ b/src/expression_string.cpp @@ -128,9 +128,13 @@ struct expression_string : util::static_visitor str_ +="')"; } - void operator() (function_call const& fun) const + void operator() (unary_function_call const& call) const { - str_ += "fun()";// FIXME + str_ += "fun(arg)";// FIXME + } + void operator() (binary_function_call const& call) const + { + str_ += "fun(arg1,arg2)";// FIXME } private: std::string & str_;