Boost logo

Boost-Commit :

From: eric_at_[hidden]
Date: 2008-02-04 21:09:51


Author: eric_niebler
Date: 2008-02-04 21:09:51 EST (Mon, 04 Feb 2008)
New Revision: 43106
URL: http://svn.boost.org/trac/boost/changeset/43106

Log:
fleshing out evaluation.qbk, document transforms of if_, not_, and_ and or_
Text files modified:
   trunk/libs/xpressive/proto/doc/evaluation.qbk | 256 +++++++++++++++++++++++++++++++++++++++
   trunk/libs/xpressive/proto/doc/installation.qbk | 6
   trunk/libs/xpressive/proto/doc/proto.qbk | 65 +++++-----
   trunk/libs/xpressive/proto/doc/protodoc.xml | 2
   trunk/libs/xpressive/proto/doc/transforms.qbk | 175 +++++++++++++++++++++++++++
   5 files changed, 463 insertions(+), 41 deletions(-)

Modified: trunk/libs/xpressive/proto/doc/evaluation.qbk
==============================================================================
--- trunk/libs/xpressive/proto/doc/evaluation.qbk (original)
+++ trunk/libs/xpressive/proto/doc/evaluation.qbk 2008-02-04 21:09:51 EST (Mon, 04 Feb 2008)
@@ -7,12 +7,98 @@
 
 [section:expression_evaluation Expression Evaluation: Imparting Behaviors Within A Context]
 
+Once you have constructed a Proto expression tree, either by using Proto's
+operator overloads or with _make_expr_ and friends, you probably want to
+actually /do/ something with it. The simplest option is to use `proto::eval()`,
+a generic expression evaluator. To use _eval_, you'll need to define a
+/context/ that tells _eval_ how each node should be evaluated. This section
+goes through the nuts and bolts of using _eval_, defining evaluation contexts,
+and using the contexts that Proto provides.
+
+[note `proto::eval()` is a less powerful but easier-to-use evaluation technique
+than Proto transforms, which are covered later. Although very powerful,
+transforms have a steep learning curve and can be more difficult to debug.
+`proto::eval()` is a rather weak tree traversal algorithm. Dan Marsden has
+been working on a more general and powerful tree traversal library. When it is
+ready, I anticipate that it will eliminate the need for `proto::eval()`.]
+
 [/================================================================]
 [section:proto_eval Evaluating An Expression with [^proto::eval()]]
 [/================================================================]
 
+[:[*Synopsis:]]
 
-
+ namespace proto
+ {
+ namespace result_of
+ {
+ // A metafunction for calculating the return
+ // type of proto::eval() given certain Expr
+ // and Context types.
+ template<typename Expr, typename Context>
+ struct eval
+ {
+ typedef
+ typename Context::template eval<Expr>::result_type
+ type;
+ };
+ }
+
+ namespace functional
+ {
+ // A callable function object type for evaluating
+ // a Proto expression with a certain context.
+ struct eval : callable
+ {
+ template<typename Sig>
+ struct result;
+
+ template<typename Expr, typename Context>
+ typename proto::result_of::eval<Expr, Context>::type
+ operator ()(Expr &expr, Context &context) const;
+
+ template<typename Expr, typename Context>
+ typename proto::result_of::eval<Expr, Context>::type
+ operator ()(Expr &expr, Context const &context) const;
+ };
+ }
+
+ functional::eval const eval = {};
+ }
+
+Given an expression and an evaluation context, using _eval_ is quite simple.
+Simply pass the expression and the context to _eval_ and it does the rest and
+returns the result. You can use the `eval<>` metafunction in the
+`proto::result_of` namespace to compute the return type of _eval_. The
+following demonstrates a use of _eval_:
+
+ template<typename Expr>
+ typename proto::result_of::eval<Expr const, MyContext>::type
+ MyEvaluate(Expr const &expr)
+ {
+ // Some user-defined context type
+ MyContext ctx;
+
+ // Evaluate an expression with the context
+ return proto::eval(expr, ctx);
+ }
+
+What _eval_ does is also very simple. It defers most of the work to the
+context itself. Here essentially is the implementation of _eval_:
+
+ // eval() dispatches to a nested "eval<>" function
+ // object within the Context:
+ template<typename Expr, typename Context>
+ typename Context::template eval<Expr>::result_type
+ eval(Expr &expr, Context &ctx)
+ {
+ typename Context::template eval<Expr> eval_fun;
+ return eval_fun(expr, ctx);
+ }
+
+Really, _eval_ is nothing more than a thin wrapper that dispatches to the
+appropriate handler within the context class. In the next section, we'll see
+how to implement a context class from scratch.
 
 [endsect]
 
@@ -20,7 +106,138 @@
 [section:contexts Defining an Evaluation Context]
 [/==============================================]
 
-TODO
+As we saw in the previous section, there is really not much to the _eval_
+function. Rather, all the interesting expression evaluation goes on within
+a context class. This sections shows how to implement one from scratch.
+
+All context classes have roughly the following form:
+
+ // A prototypical user-defined context.
+ struct MyContext
+ {
+ // A nested eval<> class template
+ template<
+ typename Expr
+ , typename Tag = typename Expr::proto_tag
+ >
+ struct eval;
+
+ // Handle terminal nodes here...
+ template<typename Expr>
+ struct eval<Expr, proto::tag::terminal>
+ {
+ // Must have a nested result_type typedef.
+ typedef ... result_type;
+
+ // Must have a function call operator that takes
+ // an expression and the context.
+ result_type operator()(Expr &expr, MyContext &ctx) const
+ {
+ return ...;
+ }
+ };
+
+ // ... other specializations of struct eval<> ...
+ };
+
+Context classes are nothing more than a collection of specializations of a
+nested `eval<>` class template. Each specialization handles a different
+expression type.
+
+In the [link boost_proto.users_guide.hello_calculator Hello Calculator]
+section, we saw an example of a user-defined context class for evaluating
+calculator expressions. That context class was implemented with the help
+of Proto's _callable_context_. If we were to implement it from scratch, it
+would look something like this:
+
+ // The calculator_contest from the "Hello Calculator" section,
+ // implemented from scratch.
+ struct calculator_context
+ {
+ // The values for the _1 and _2 placeholders are
+ // passed to the calculator_context constructor.
+ calculator_context(double d1, double d2)
+ : d1_(d1), d2_(d2)
+ {}
+
+ template<
+ typename Expr
+ // defaulted template parameters, so we can
+ // specialize on the expressions that need
+ // special handling.
+ , typename Tag = typename tag_of<Expr>::type
+ , typename Arg0 = typename arg_c<Expr, 0>::type
+ >
+ struct eval;
+
+ // Handle placeholder1 terminals here...
+ template<typename Expr>
+ struct eval<Expr, proto::tag::terminal, placeholder1>
+ {
+ typedef double result_type;
+
+ result_type operator()(Expr &, MyContext &ctx) const
+ {
+ // replaces _1 with the value in ctx.d1_
+ return ctx.d1_;
+ }
+ };
+
+ // Handle placeholder2 terminals here...
+ template<typename Expr>
+ struct eval<Expr, proto::tag::terminal, placeholder2>
+ {
+ typedef double result_type;
+
+ result_type operator()(Expr &, MyContext &ctx) const
+ {
+ // replaces _1 with the value in ctx.d2_
+ return ctx.d2_;
+ }
+ };
+
+ // Handle other terminals here...
+ template<typename Expr, typename Arg0>
+ struct eval<Expr, proto::tag::terminal, Arg0>
+ {
+ typedef double result_type;
+
+ result_type operator()(Expr &expr, MyContext &) const
+ {
+ return proto::arg(expr);
+ }
+ };
+
+ // Handle addition here...
+ template<typename Expr, typename Arg0>
+ struct eval<Expr, proto::tag::plus, Arg0>
+ {
+ typedef double result_type;
+
+ result_type operator()(Expr &expr, MyContext &ctx) const
+ {
+ return proto::eval(proto::left(expr), ctx)
+ + proto::eval(proto::right(expr), ctx);
+ }
+ };
+
+ // ... other eval<> specializations for other node types ...
+
+ double d1_, d2_;
+ };
+
+Now we can use _eval_ with the context class above to evaluate calculator
+expressions as follows:
+
+ // Evaluate an expression with a calculator_context
+ double d = proto::eval(_1 + _2, calculator_context(5, 6));
+ assert(11 == d);
+
+Defining a context from scratch this way is tedious and verbose, but it gives
+you complete control over how the expression is evaluated. The context class in
+the [link boost_proto.users_guide.hello_calculator Hello Calculator] example
+was much simpler. In the next section we'll see the helper class Proto provides
+to ease the job of implementing context classes.
 
 [endsect]
 
@@ -28,11 +245,35 @@
 [section:canned_contexts Canned Contexts]
 [/======================================]
 
+Proto provides some ready-made context classes that you can use as-is, or that
+you can use to help while implementing your own contexts. They are:
+
+[variablelist
+ [ [[link boost_proto.users_guide.expression_evaluation.canned_contexts.default_context [^default_context]]]
+ [An evaluation context that assigns the usual C++ meanings to all the
+ operators. For example, addition nodes are handled by evaluating the
+ left and right children and then adding the results. The _default_context_
+ uses Boost.Typeof to deduce the types of the expressions it evaluates.] ]
+ [ [[link boost_proto.users_guide.expression_evaluation.canned_contexts.null_context [^null_context]]]
+ [A simple context that recursively evaluates children but does not combine
+ the results in any way and returns void.] ]
+ [ [[link boost_proto.users_guide.expression_evaluation.canned_contexts.callable_context [^callable_context<>]]]
+ [A helper that simplifies the job of writing context classes. Rather than
+ writing template specializations, with _callable_context_ you write a
+ function object with an overloaded function call operator. Any expressions
+ not handled by an overload are automatically dispatched to a default
+ evaluation context that you can specify.] ]
+]
+
 [/=========================================]
 [section:default_context [^default_context]]
 [/=========================================]
 
-TODO
+The _default_context_ is an evaluation context that assigns the usual C++
+meanings to all the operators. For example, addition nodes are handled by
+evaluating the left and right children and then adding the results. The
+_default_context_ uses Boost.Typeof to deduce the types of the expressions it
+evaluates.
 
 [endsect]
 
@@ -40,7 +281,8 @@
 [section:null_context [^null_context]]
 [/===================================]
 
-TODO
+The _null_context_ is a simple context that recursively evaluates children
+but does not combine the results in any way and returns void.
 
 [endsect]
 
@@ -48,7 +290,11 @@
 [section:callable_context [^callable_context<>]]
 [/=============================================]
 
-TODO
+The _callable_context_ is a helper that simplifies the job of writing context
+classes. Rather than writing template specializations, with _callable_context_
+you write a function object with an overloaded function call operator. Any
+expressions not handled by an overload are automatically dispatched to a
+default evaluation context that you can specify.
 
 [endsect]
 

Modified: trunk/libs/xpressive/proto/doc/installation.qbk
==============================================================================
--- trunk/libs/xpressive/proto/doc/installation.qbk (original)
+++ trunk/libs/xpressive/proto/doc/installation.qbk 2008-02-04 21:09:51 EST (Mon, 04 Feb 2008)
@@ -9,8 +9,10 @@
 
 [heading Getting Proto]
 
-Currently the only way to get Proto is through SVN via the boost project on
-SourceForge.net. Just go to [@http://svn.boost.org/trac/boost/wiki/BoostSubversion]
+You can get Proto by downloading [^proto.zip] from
+[@http://www.boost-consulting.com/vault/index.php?directory=Template%20Metaprogramming]
+or by accessing Boost's SVN repository on SourceForge.net. Just go to
+[@http://svn.boost.org/trac/boost/wiki/BoostSubversion]
 and follow the instructions there for anonymous SVN access.
 
 [heading Building with Proto]

Modified: trunk/libs/xpressive/proto/doc/proto.qbk
==============================================================================
--- trunk/libs/xpressive/proto/doc/proto.qbk (original)
+++ trunk/libs/xpressive/proto/doc/proto.qbk 2008-02-04 21:09:51 EST (Mon, 04 Feb 2008)
@@ -38,38 +38,39 @@
 [def _spirit_fx_ [@http://spirit.sourceforge.net Spirit Parser Framework]]
 [def _spirit_ [@http://spirit.sourceforge.net Spirit]]
 [def _xpressive_ [@../../../libs/xpressive/doc/index.html Boost.Xpressive]]
-[def _expr_ [classref boost::proto::exprns_::expr<Tag,Args,1> `expr<>`]]
-[def _ref_ [classref boost::proto::refns_::ref_ `ref_<>`]]
-[def _unref_ [classref boost::proto::functional::unref `unref()`]]
-[def _deep_copy_ [classref boost::proto::functional::deep_copy `deep_copy()`]]
-[def _extends_ [classref boost::proto::exprns_::extends `extends<>`]]
-[def _as_expr_ [classref boost::proto::functional::as_expr `as_expr()`]]
-[def _as_arg_ [classref boost::proto::functional::as_arg `as_arg()`]]
-[def _make_expr_ [funcref boost::proto::make_expr `make_expr()`]]
-[def _unpack_expr_ [funcref boost::proto::unpack_expr `unpack_expr()`]]
-[def _matches_ [classref boost::proto::result_of::matches `matches<>`]]
-[def _or_ [classref boost::proto::control::or_ `or_<>`]]
-[def _and_ [classref boost::proto::control::and_ `and_<>`]]
-[def _if_ [classref boost::proto::control::if_ `if_<>`]]
-[def _not_ [classref boost::proto::control::not_ `not_<>`]]
-[def _exact_ [classref boost::proto::control::exact `exact<>`]]
-[def _convertible_to_ [classref boost::proto::control::convertible_to `convertible_to<>`]]
-[def _is_expr_ [classref boost::proto::result_if::is_expr `is_expr<>`]]
-[def _tag_of_ [classref boost::proto::result_if::tag_of `tag_of<>`]]
-[def _arg_ [funcref boost::proto::arg `arg()`]]
-[def _arg_c_ [funcref boost::proto::arg_c `arg_c()`]]
-[def _eval_ [classref boost::proto::functional::eval `eval()`]]
-[def _left_ [classref boost::proto::functional::left `left()`]]
-[def _right_ [classref boost::proto::functional::right `right()`]]
-[def _terminal_ [classref boost::proto::op::terminal `terminal<>`]]
-[def _unary_expr_ [classref boost::proto::op::unary_expr `unary_expr<>`]]
-[def _binary_expr_ [classref boost::proto::op::binary_expr `binary_expr<>`]]
-[def _literal_ [classref boost::proto::utility::literal `literal<>`]]
-[def _lit_ [funcref boost::proto::lit `lit()`]]
-[def _vararg_ [classref boost::proto::control::vararg `vararg<>`]]
-[def _default_context_ [classref boost::proto::context::default_context `default_context`]]
-[def _callable_context_ [classref boost::proto::context::callable_context `callable_context<>`]]
-[def _when_ [classref boost::proto::transform::when `when<>`]]
+[def _expr_ [classref boost::proto::exprns_::expr<Tag,Args,1> `expr<>`]]
+[def _ref_ [classref boost::proto::refns_::ref_ `ref_<>`]]
+[def _unref_ [classref boost::proto::functional::unref `unref()`]]
+[def _deep_copy_ [classref boost::proto::functional::deep_copy `deep_copy()`]]
+[def _extends_ [classref boost::proto::exprns_::extends `extends<>`]]
+[def _as_expr_ [funcref boost::proto::as_expr `as_expr()`]]
+[def _as_arg_ [funcref boost::proto::as_arg `as_arg()`]]
+[def _make_expr_ [funcref boost::proto::make_expr `make_expr()`]]
+[def _unpack_expr_ [funcref boost::proto::unpack_expr `unpack_expr()`]]
+[def _matches_ [classref boost::proto::result_of::matches `matches<>`]]
+[def _or_ [classref boost::proto::control::or_ `or_<>`]]
+[def _and_ [classref boost::proto::control::and_ `and_<>`]]
+[def _if_ [classref boost::proto::control::if_ `if_<>`]]
+[def _not_ [classref boost::proto::control::not_ `not_<>`]]
+[def _exact_ [classref boost::proto::control::exact `exact<>`]]
+[def _convertible_to_ [classref boost::proto::control::convertible_to `convertible_to<>`]]
+[def _is_expr_ [classref boost::proto::result_if::is_expr `is_expr<>`]]
+[def _tag_of_ [classref boost::proto::result_if::tag_of `tag_of<>`]]
+[def _arg_ [funcref boost::proto::arg `arg()`]]
+[def _arg_c_ [funcref boost::proto::arg_c `arg_c()`]]
+[def _eval_ [memberref boost::proto::eval `eval()`]]
+[def _left_ [classref boost::proto::functional::left `left()`]]
+[def _right_ [classref boost::proto::functional::right `right()`]]
+[def _terminal_ [classref boost::proto::op::terminal `terminal<>`]]
+[def _unary_expr_ [classref boost::proto::op::unary_expr `unary_expr<>`]]
+[def _binary_expr_ [classref boost::proto::op::binary_expr `binary_expr<>`]]
+[def _literal_ [classref boost::proto::utility::literal `literal<>`]]
+[def _lit_ [funcref boost::proto::lit `lit()`]]
+[def _vararg_ [classref boost::proto::control::vararg `vararg<>`]]
+[def _default_context_ [classref boost::proto::context::default_context `default_context`]]
+[def _callable_context_ [classref boost::proto::context::callable_context `callable_context<>`]]
+[def _null_context_ [classref boost::proto::context::null_context `null_context<>`]]
+[def _when_ [classref boost::proto::transform::when `when<>`]]
 
 [include preface.qbk]
 

Modified: trunk/libs/xpressive/proto/doc/protodoc.xml
==============================================================================
--- trunk/libs/xpressive/proto/doc/protodoc.xml (original)
+++ trunk/libs/xpressive/proto/doc/protodoc.xml 2008-02-04 21:09:51 EST (Mon, 04 Feb 2008)
@@ -303,7 +303,7 @@
           <template-type-parameter name="Context"/>
         </template><parameter name="expr"><paramtype>Expr &amp;</paramtype></parameter><parameter name="context"><paramtype>Context &amp;</paramtype></parameter><purpose>Evaluate a given Proto expression with a given context. </purpose><description><para>
 
-</para></description><notes><para>This function is equivalent to <computeroutput>typename Context::template eval&lt;Expr&gt;()(expr, context)</computeroutput>. </para></notes></method><method name="operator()" cv="const"><type><classname>proto::result_of::eval</classname>&lt; Expr, Context &gt;::type</type><template>
+</para></description><returns><para><computeroutput>typename Context::template eval&lt;Expr&gt;()(expr, context)</computeroutput> </para></returns></method><method name="operator()" cv="const"><type><classname>proto::result_of::eval</classname>&lt; Expr, Context &gt;::type</type><template>
           <template-type-parameter name="Expr"/>
           <template-type-parameter name="Context"/>
         </template><parameter name="expr"><paramtype>Expr &amp;</paramtype></parameter><parameter name="context"><paramtype>Context const &amp;</paramtype></parameter><description><para>This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts. </para></description></method></method-group></struct></namespace><namespace name="result_of"><struct name="eval"><template>

Modified: trunk/libs/xpressive/proto/doc/transforms.qbk
==============================================================================
--- trunk/libs/xpressive/proto/doc/transforms.qbk (original)
+++ trunk/libs/xpressive/proto/doc/transforms.qbk 2008-02-04 21:09:51 EST (Mon, 04 Feb 2008)
@@ -457,6 +457,179 @@
 
 [endsect]
 
+[section:if [^if_<>]]
+
+ namespace boost { namespace proto
+ {
+ namespace control
+ {
+ template<
+ typename If
+ , typename Then = _
+ , typename Else = not_<_>
+ >
+ struct if_;
+ }
+
+ using control::if_;
+ }}
+
+We've already seen the _if_ template in the context of grammars, but
+_if_ can also be used as a transform. It can be used to conditionally
+apply one transform or another based on some condition. The three
+template parameters are Proto transforms. The result of applying the
+first transform should be a compile-time Boolean. If it is true, then
+the first transform is applied. The second is applied otherwise.
+
+[table
+ [ [Expression]
+ [Returns]
+ ]
+ [ [``control::if_<If, Then, Else>
+ ::result<void(Expr, State, Visitor)>::type``]
+ [``typedef
+ mpl::if_<
+ when<_, If>::result<void(Expr, State, Visitor)>::type
+ , when<_, Then>
+ , when<_, Else>
+ >::type
+branch;
+
+typedef branch::result<void(Expr, State, Visitor)>::type type;``]
+ ]
+ [ [`control::if_<If, Then, Else>()(expr, state, visitor)`]
+ [``typedef ... branch; // Same as above
+branch()(expr, state, visitor);``]
+ ]
+]
+
+Example:
+
+ // Match a terminal. If size of the terminal
+ // argument is less than or equal to 4, make
+ // a new terminal that stores the argument by
+ // value. Otherwise, store the argument by
+ // reference.
+ struct ByValOrRef
+ : when<
+ terminal<_>
+ , if_<
+ mpl::less_equal<
+ mpl::sizeof_<_arg>
+ , mpl::size_t<4>
+ >()
+ , _make_terminal(_arg)
+ , _make_terminal(_ref(_arg))
+ >
+ >
+ {};
+
+[endsect]
+
+[section:and_or_not [^and_<>], [^or_<>], and [^not_<>]]
+
+ namespace boost { namespace proto
+ {
+ namespace control
+ {
+ template<typename... T>
+ struct and_;
+
+ template<typename... T>
+ struct or_;
+
+ template<typename T>
+ struct not_;
+ }
+
+ using control::and_;
+ using control::or_;
+ using control::not_;
+ }}
+
+As with _if_, the grammar elements _and_, _or_, and _not_ can
+also be used as transforms. At a high level, here is what the
+transforms do:
+
+[variablelist
+[ [`and_<T0,T1,...,Tn>`]
+ [Apply the transform `Tn`.] ]
+[ [`or_<T0,T1,...,Tn>`]
+ [Apply the transform `Tx` where `x` is the lowest number
+ such that `matches<Expr,Tx>::value` is `true`.] ]
+[ [`not_<T>`] [Return the current expression unchanged.] ]
+]
+
+The following table specifies the behaviors described above more
+precisely.
+
+[table
+ [ [Expression]
+ [Returns]
+ ]
+ [ [``control::and_<A,B,C>
+ ::result<void(Expr, State, Visitor)>::type``]
+ [`C::result<void(Expr, State, Visitor)>::type`]
+ ]
+ [ [`control::and_<A,B,C>()(expr, state, visitor)`]
+ [`C()(expr, state, visitor)`]
+ ]
+ [ [``control::or_<A,B,C>
+ ::result<void(Expr, State, Visitor)>::type``]
+ [``typedef mpl::if_<
+ matches<Expr, A>
+ , A
+ , mpl::if_<
+ matches<Expr, B>
+ , B
+ , C
+ >::type
+>::type which;
+
+typedef which::result<void(Expr, State, Visitor)>::type type;``]
+ ]
+ [ [`control::or_<A,B,C>()(expr, state, visitor)`]
+ [``typedef ... which; // Same as above
+which()(expr, state, visitor);``]
+ ]
+ [ [``control::not_<A>
+ ::result<void(Expr, State, Visitor)>::type``]
+ [`Expr`]
+ ]
+ [ [`control::not_<A>()(expr, state, visitor)`]
+ [`expr`]
+ ]
+]
+
+Example:
+
+ // A transform that matches any expression and
+ // unwraps any reference_wrapped terminals it
+ // finds.
+ struct UnwrapReference
+ : or_<
+ // Pass through terminals that are not
+ // reference_wrappers unchanged:
+ and_<
+ terminal<_>
+ , not_<if_<is_reference_wrapper<_arg>()> >
+ >
+ // For other terminals (i.e., reference_wrapper
+ // terminals), unwrap the reference:
+ , when<
+ terminal<_>
+ , terminal<unwrap_reference<_arg> >(_arg)
+ >
+ // Otherwise, match non-terminals and
+ // recurse.
+ , when<
+ nary_expr<_, vararg<UnwrapReference> >
+ >
+ >
+ {};
+
+[endsect]
+
 [section:call [^call<>]]
 
     namespace boost { namespace proto
@@ -1065,7 +1238,7 @@
             // Function call operator that actually
             // executes the transform.
             template<typename Expr, typename State, typename Visitor>
- typename proto::result_of::arg_c<Expr, I>::type
+ typename proto::result_of::arg_c<Expr, I>::const_reference
             operator ()(Expr const &expr, State const &, Visitor &) const
             {
                 return proto::arg_c<I>(expr);


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk