From 3c39a117b8e66b4c0fc93ad7a136015cd70d6d88 Mon Sep 17 00:00:00 2001 From: Zach Laine Date: Tue, 13 Dec 2016 23:39:14 -0600 Subject: [PATCH] Flesh out Transform Matching section. --- doc/concepts.qbk | 6 +-- doc/tutorial.qbk | 63 ++++++++++++++++++++++++++++ doc/yap.qbk | 8 ++++ test/user_expression_transform_3.cpp | 20 +++++++-- 4 files changed, 90 insertions(+), 7 deletions(-) diff --git a/doc/concepts.qbk b/doc/concepts.qbk index 073c1aa..a9c8e47 100644 --- a/doc/concepts.qbk +++ b/doc/concepts.qbk @@ -36,9 +36,9 @@ _kind_ and a _tuple_, results in an _Expr_. [heading Transform] -_xform_ takes a _XForm_ as its second parameter. A _XForm_ is a Callable that -takes expressions and returns values of unconstrained type. There are two -sorts of overloads _XForm_ may use: _ExprXForm_ and _TagXForm_. +_xform_ takes a _XForm_ as its second parameter. A _XForm_ is a _Callable_ +that takes expressions and returns values of unconstrained type. There are +two sorts of overloads _XForm_ may use: _ExprXForm_ and _TagXForm_. A _XForm_ may have nay number of overloads, including none. diff --git a/doc/tutorial.qbk b/doc/tutorial.qbk index f7a2737..a53ccab 100644 --- a/doc/tutorial.qbk +++ b/doc/tutorial.qbk @@ -331,6 +331,69 @@ receive values in their arguments, not _Exprs_. [section Transform Matching] +In _yap_ a _XForm_ is a _Callable_ that has *zero or more* overloads that +model the _ExprXForm_ or _TagXForm_ concepts. + +An _ExprXForm_ overload takes the expression to be transformed: + +[expr_xform] + +_ExprXForms_ are most useful when you want to transform a narrow set of +expression types (perhaps only one). In particular, you can distinguish +between `const` and non-`const`, reference and non-reference, etc., in the +expression and its operands in a way that you have less control over with the +other kind of transform. + +A _TagXForm_ overload takes a tag that indicates the _kind_ of the expression +to be transformed, and then (loosely) the value of each operand of the +epxression to be transformed: + +[tag_xform] + +_TagXForms_ are most useful when the transform needs to match expressions +without regard to whether its operands are _expr_ref_ expressions, or -- if +they are terminals -- whether they contain or refer to their values. +_TagXForms_ tend to be far more concise. + +[heading A More Rigorous Description of TagTransform Parameters] + +That "(loosely)" before probably bothered you, right? Me too. For an +expression `expr`, each parameter is passed to a _TagXForm_ by calling an +operand accessor appropriate to `expr`'s kind, and then calling _value_ on the +result. For example, for a plus expression, the _TagXForm_ on a transform +object `xform` will be called like this: + + xform(plus_tag, value(left(expr)), value(right(expr))) + +The operand accessors (_left_ and _right_ in this example) all dereference +_expr_ref_ expressions before operating on them, and _value_ does the same. +When given a terminal, _value_ also returns the value of the terminal. + +The result of this pattern is that you can effectively ignore the presence of +_expr_ref_ expressions when writing a _TagXForm_. You can also just deal with +the values inside terminals, and not the terminals themselves. Also, you can +match all terminal value qualifiers (`const` or not, lvalue or rvalue) +uniformly with a `T const &` parameter. Finally, you can write _TagXForm_ +parameter types that can catch conversions; for instance, you can match any +negation expression containing terminal of a numeric type convertible to +`double` like this: + + struct xform + { + auto operator() (boost::yap::negate_tag, double x) + { return /* ... */; } + } + +That will match negations of `unsigned int`s, `int`s, `float`s, etc. + +[heading Mixing the Two Kinds of Transforms] + +You can have two overloads in your transform that match an expression, one an +_ExprXForm_ and one a _TagXForm_, and there will not be any ambiguity. The +_TagXForm_ is prefered, except in the case of a call expression, in which case +the _ExprXForm_ is preferred. I know, I know. Save youself some headaches +and mix the two kinds of overloads as little as possible. + [endsect] diff --git a/doc/yap.qbk b/doc/yap.qbk index c08b11e..8269e15 100644 --- a/doc/yap.qbk +++ b/doc/yap.qbk @@ -40,6 +40,7 @@ [import ../example/map_assign.cpp] [import ../example/future_group.cpp] [import ../test/user_expression_transform_2.cpp] +[import ../test/user_expression_transform_3.cpp] [/ Images ] @@ -61,7 +62,11 @@ [def _XForm_ [link boost_yap__proposed_.concepts.transform Transform]] [def _XForms_ [link boost_yap__proposed_.concepts.transform Transforms]] [def _ExprXForm_ [link boost_yap__proposed_.concepts.expressiontransform ExpressionTransform]] +[def _ExprXForms_ [link boost_yap__proposed_.concepts.expressiontransform ExpressionTransforms]] [def _TagXForm_ [link boost_yap__proposed_.concepts.tagtransform TagTransform]] +[def _TagXForms_ [link boost_yap__proposed_.concepts.tagtransform TagTransforms]] +[def _Callable_ [@http://en.cppreference.com/w/cpp/concept/Callable Callable]] +[def _Callables_ [@http://en.cppreference.com/w/cpp/concept/Callable Callables]] [def _expr_ [classref boost::yap::expression `expression<>`]] [def _kind_ [enumref boost::yap::expr_kind `expr_kind`]] @@ -78,6 +83,9 @@ [def _make_term_ [funcref boost::yap::make_terminal `make_terminal()`]] [def _make_expr_ [funcref boost::yap::make_expression `make_expression()`]] [def _make_expr_fn_ [funcref boost::yap::make_expression_function `make_expression_function()`]] +[def _left_ [funcref boost::yap::left `left()`]] +[def _right_ [funcref boost::yap::right `right()`]] +[def _value_ [funcref boost::yap::value `value()`]] [def _unary_member_m_ [macroref BOOST_YAP_USER_UNARY_OPERATOR_MEMBER]] [def _binary_member_m_ [macroref BOOST_YAP_USER_BINARY_OPERATOR_MEMBER]] diff --git a/test/user_expression_transform_3.cpp b/test/user_expression_transform_3.cpp index 38a7404..28df1f0 100644 --- a/test/user_expression_transform_3.cpp +++ b/test/user_expression_transform_3.cpp @@ -221,19 +221,31 @@ namespace user { // ternary transforms +//[ tag_xform struct ternary_to_else_xform_tag { template - decltype(auto) operator() (yap::if_else_tag, Expr const & cond, user::number const & then, user::number const & else_) - { return yap::make_terminal(else_); } + decltype(auto) operator() ( + boost::yap::if_else_tag, + Expr const & cond, + user::number const & then, + user::number const & else_ + ) { return boost::yap::make_terminal(else_); } }; +//] +//[ expr_xform struct ternary_to_else_xform_expr { template - decltype(auto) operator() (yap::expression> const & expr) - { return ::boost::yap::else_(expr); } + decltype(auto) operator() ( + boost::yap::expression< + boost::yap::expr_kind::if_else, + boost::hana::tuple + > const & expr + ) { return ::boost::yap::else_(expr); } }; +//] struct ternary_to_else_xform_both {