| <?xml version="1.0" encoding="utf-8"?> |
| <!-- |
| Copyright 2012 Eric Niebler |
| |
| Distributed under the Boost |
| Software License, Version 1.0. (See accompanying |
| file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
| --> |
| <header name="boost/proto/transform/when.hpp"> |
| <para> |
| Definition of the |
| <computeroutput> |
| <classname alt="boost::proto::when">proto::when<></classname> |
| </computeroutput> and |
| <computeroutput> |
| <classname alt="boost::proto::otherwise">proto::otherwise<></classname> |
| </computeroutput> transforms. |
| </para> |
| <namespace name="boost"> |
| <namespace name="proto"> |
| |
| <!-- struct transforms_type --> |
| <struct name="transforms_type"> |
| <purpose> |
| The type used to define the global <code><globalname>proto::transforms</globalname></code>, |
| a key for use when creating and accessing a slot in a transform environment for |
| a set of external transforms. |
| </purpose> |
| <description> |
| <para> |
| The <code>proto::transforms_type</code> type, along with the <code><globalname>proto::transforms</globalname></code> |
| global, are declared using the <code><macroname>BOOST_PROTO_DEFINE_ENV_VAR</macroname>()</code> macro. |
| </para> |
| </description> |
| <method-group name="public member functions"> |
| <overloaded-method name="operator="> |
| <signature cv="const"> |
| <template> |
| <template-type-parameter name="Value"/> |
| </template> |
| <type><classname>env</classname><transforms_type, <replaceable>see-below</replaceable>></type> |
| <parameter name="value"> |
| <paramtype>Value &</paramtype> |
| </parameter> |
| </signature> |
| <signature cv="const"> |
| <template> |
| <template-type-parameter name="Value"/> |
| </template> |
| <type><classname>env</classname><transforms_type, <replaceable>see-below</replaceable>></type> |
| <parameter name="value"> |
| <paramtype>Value const &</paramtype> |
| </parameter> |
| </signature> |
| <description> |
| <para> |
| If <code>Value</code> is a specialization <code>boost::reference_wrapper<T></code>, |
| this function returns <code><classname>env</classname><transforms_type, T &>(value.get())</code>. |
| </para> |
| <para> |
| Else, if the type <code>Value</code> is non-copyable (i.e., a function, an array, abstract, or an ostream), |
| this function returns <code><classname>env</classname><transforms_type, Value <replaceable>cv</replaceable> &>(value)</code>, |
| where <code><replaceable>cv</replaceable></code> is <code>const</code> for the second overload, and empty |
| for the first. |
| </para> |
| <para> |
| Otherwise, this function returns <code><classname>env</classname><transforms_type, Value>(value)</code>. |
| </para> |
| </description> |
| </overloaded-method> |
| </method-group> |
| </struct> |
| |
| <data-member name="transforms"> |
| <description> |
| <para> |
| A key key for use when creating and accessing a slot in a transform environment for |
| a set of external transforms. |
| </para> |
| </description> |
| <type><classname>proto::transforms_type</classname> const</type> |
| </data-member> |
| |
| <struct name="when"> |
| <template> |
| <template-type-parameter name="Grammar"/> |
| <template-type-parameter name="PrimitiveTransform"> |
| <default>Grammar</default> |
| </template-type-parameter> |
| </template> |
| <purpose>A grammar element and a <conceptname>PrimitiveTransform</conceptname> that associates |
| a transform with the grammar.</purpose> |
| <description> |
| <para> |
| Use <computeroutput>proto::when<></computeroutput> to override a grammar's default |
| transform with a custom transform. It is for used when composing larger transforms by |
| associating smaller transforms with individual rules in your grammar, as in the following |
| transform which counts the number of terminals in an expression. |
| <programlisting>// Count the terminals in an expression tree. |
| // Must be invoked with initial state == mpl::int_<0>(). |
| struct CountLeaves : |
| <classname>proto::or_</classname>< |
| proto::when<<classname>proto::terminal</classname><<classname>proto::_</classname>>, mpl::next<<classname>proto::_state</classname>>()>, |
| proto::otherwise<<classname>proto::fold</classname><<classname>proto::_</classname>, <classname>proto::_state</classname>, CountLeaves> > |
| > |
| {};</programlisting> |
| </para> |
| <para> |
| In <computeroutput>proto::when<G, T></computeroutput>, when <computeroutput>T</computeroutput> |
| is a class type it is a <conceptname>PrimitiveTransform</conceptname> and the following equivalencies hold: |
| </para> |
| <itemizedlist> |
| <listitem> |
| <para> |
| <computeroutput>boost::result_of<proto::when<G,T>(E,S,V)>::type</computeroutput> is the same as |
| <computeroutput>boost::result_of<T(E,S,V)>::type</computeroutput>. |
| </para> |
| </listitem> |
| <listitem> |
| <para> |
| <computeroutput>proto::when<G,T>()(e,s,d)</computeroutput> is the same as |
| <computeroutput>T()(e,s,d)</computeroutput>. |
| </para> |
| </listitem> |
| </itemizedlist> |
| </description> |
| <inherit><type>PrimitiveTransform</type></inherit> |
| <typedef name="proto_grammar"> |
| <type>typename Grammar::proto_grammar</type> |
| </typedef> |
| </struct> |
| |
| <struct-specialization name="when"> |
| <template> |
| <template-type-parameter name="Grammar"/> |
| <template-type-parameter name="Fun"/> |
| </template> |
| <specialization> |
| <template-arg>Grammar</template-arg> |
| <template-arg>Fun *</template-arg> |
| </specialization> |
| <inherit><type><classname>proto::when</classname>< Grammar, Fun ></type></inherit> |
| <purpose>A specialization that treats function pointer <conceptname>Transform</conceptname>s as if they |
| were function type <conceptname>Transform</conceptname>s.</purpose> |
| <description> |
| <para> |
| This specialization requires that <computeroutput>Fun</computeroutput> is actually a function type. |
| </para> |
| <para> |
| This specialization is required for nested transforms such as |
| <computeroutput>proto::when<G, T0(T1(_))></computeroutput>. In C++, functions that are used |
| as parameters to other functions automatically decay to funtion pointer types. In other words, the |
| type <computeroutput>T0(T1(_))</computeroutput> is indistinguishable from |
| <computeroutput>T0(T1(*)(_))</computeroutput>. This specialization is required to handle these |
| nested function pointer type transforms properly. |
| </para> |
| </description> |
| </struct-specialization> |
| |
| <struct-specialization name="when"> |
| <template> |
| <template-type-parameter name="Grammar"/> |
| <template-type-parameter name="R"/> |
| <template-type-parameter name="A" pack="1"/> |
| </template> |
| <specialization> |
| <template-arg>Grammar</template-arg> |
| <template-arg>R(A...)</template-arg> |
| </specialization> |
| <inherit><type><classname>proto::transform</classname>< when<Grammar, R(A...)> ></type></inherit> |
| <purpose>A grammar element and a <conceptname>Transform</conceptname> that associates a |
| transform with the grammar. </purpose> |
| <description> |
| <para> |
| Use <computeroutput>proto::when<></computeroutput> to override a grammar's default |
| transform with a custom transform. It is for use when composing larger transforms by associating |
| smaller transforms with individual rules in your grammar. |
| </para> |
| <para> |
| The <computeroutput>when<G, R(A...)></computeroutput> form accepts either a |
| <conceptname>CallableTransform</conceptname> or an <conceptname>ObjectTransform</conceptname> as its |
| second parameter. <computeroutput>proto::when<></computeroutput> uses |
| <computeroutput><classname>proto::is_callable</classname><R>::value</computeroutput> to |
| distinguish between the two, and uses |
| <computeroutput><classname>proto::call<></classname></computeroutput> to evaluate |
| <conceptname>CallableTransform</conceptname>s and |
| <computeroutput><classname>proto::make<></classname></computeroutput> to evaluate |
| <conceptname>ObjectTransform</conceptname>s. |
| </para> |
| </description> |
| <struct name="impl"> |
| <template> |
| <template-type-parameter name="Expr"/> |
| <template-type-parameter name="State"/> |
| <template-type-parameter name="Data"/> |
| </template> |
| <inherit><type><classname>proto::transform_impl</classname>< Expr, State, Data ></type></inherit> |
| <typedef name="call_"> |
| <purpose>For exposition only</purpose> |
| <type><classname>proto::call</classname><R(A...)></type> |
| </typedef> |
| <typedef name="make_"> |
| <purpose>For exposition only</purpose> |
| <type><classname>proto::make</classname><R(A...)></type> |
| </typedef> |
| <typedef name="which"> |
| <purpose>For exposition only</purpose> |
| <type>typename mpl::if_<<classname>proto::is_callable</classname><R>,call_,make_>::type</type> |
| </typedef> |
| <typedef name="result_type"> |
| <type>typename boost::result_of<which(Expr, State, Data)>::type</type> |
| </typedef> |
| <method-group name="public member functions"> |
| <method name="operator()" cv="const"> |
| <type>result_type</type> |
| <parameter name="expr"> |
| <paramtype>typename impl::expr_param</paramtype> |
| <description> |
| <para>The current expression </para> |
| </description> |
| </parameter> |
| <parameter name="state"> |
| <paramtype>typename impl::state_param</paramtype> |
| <description> |
| <para>The current state </para> |
| </description> |
| </parameter> |
| <parameter name="data"> |
| <paramtype>typename impl::data_param</paramtype> |
| <description> |
| <para>An arbitrary data </para> |
| </description> |
| </parameter> |
| <description> |
| <para> |
| Evaluate <computeroutput>R(A...)</computeroutput> as a transform either with |
| <computeroutput><classname>proto::call<></classname></computeroutput> or with |
| <computeroutput><classname>proto::make<></classname></computeroutput> depending |
| on whether <computeroutput><classname>proto::is_callable</classname><R>::value</computeroutput> |
| is <computeroutput>true</computeroutput> or <computeroutput>false</computeroutput>. |
| </para> |
| </description> |
| <requires> |
| <para> |
| <computeroutput><classname>proto::matches</classname><Expr, Grammar>::value</computeroutput> |
| is <computeroutput>true</computeroutput>. |
| </para> |
| </requires> |
| <returns> |
| <para> |
| <computeroutput>which()(expr, state, data)</computeroutput> |
| </para> |
| </returns> |
| </method> |
| </method-group> |
| </struct> |
| <typedef name="proto_grammar"> |
| <type>typename Grammar::proto_grammar</type> |
| </typedef> |
| </struct-specialization> |
| |
| <struct-specialization name="when"> |
| <template> |
| <template-type-parameter name="Grammar"/> |
| <template-type-parameter name="R"/> |
| <template-type-parameter name="A" pack="1"/> |
| </template> |
| <specialization> |
| <template-arg>Grammar</template-arg> |
| <template-arg>R(A..., ...)</template-arg> |
| </specialization> |
| <inherit><type><classname>proto::transform</classname>< when<Grammar, R(A..., ...)> ></type></inherit> |
| <purpose>A grammar element and a <conceptname>Transform</conceptname> that associates a |
| transform with the grammar. </purpose> |
| <description> |
| <para> |
| Use <computeroutput>proto::when<></computeroutput> to override a grammar's default |
| transform with a custom transform. It is for use when composing larger transforms by associating |
| smaller transforms with individual rules in your grammar. |
| </para> |
| <para> |
| The <computeroutput>when<G, R(A..., ...)></computeroutput> form accepts either a |
| <conceptname>CallableTransform</conceptname> or an <conceptname>ObjectTransform</conceptname> as its |
| second parameter. <computeroutput>proto::when<></computeroutput> uses |
| <computeroutput><classname>proto::is_callable</classname><R>::value</computeroutput> to |
| distinguish between the two, and uses |
| <computeroutput><classname>proto::call<></classname></computeroutput> to evaluate |
| <conceptname>CallableTransform</conceptname>s and |
| <computeroutput><classname>proto::make<></classname></computeroutput> to evaluate |
| <conceptname>ObjectTransform</conceptname>s. |
| </para> |
| <para> |
| <emphasis role="bold">Note:</emphasis> In the specialization |
| <computeroutput>when<G, R(A..., ...)></computeroutput>, the first ellipsis denotes a |
| C++11-style variadic template (which is emulated for C++98 compilers). The second ellipsis |
| is a C-style vararg. |
| </para> |
| </description> |
| <struct name="impl"> |
| <template> |
| <template-type-parameter name="Expr"/> |
| <template-type-parameter name="State"/> |
| <template-type-parameter name="Data"/> |
| </template> |
| <inherit><type><classname>proto::transform_impl</classname>< Expr, State, Data ></type></inherit> |
| <typedef name="call_"> |
| <purpose>For exposition only</purpose> |
| <type><classname>proto::call</classname><R(A..., ...)></type> |
| </typedef> |
| <typedef name="make_"> |
| <purpose>For exposition only</purpose> |
| <type><classname>proto::make</classname><R(A..., ...)></type> |
| </typedef> |
| <typedef name="which"> |
| <purpose>For exposition only</purpose> |
| <type>typename mpl::if_<<classname>proto::is_callable</classname><R>,call_,make_>::type</type> |
| </typedef> |
| <typedef name="result_type"> |
| <type>typename boost::result_of<which(Expr, State, Data)>::type</type> |
| </typedef> |
| <method-group name="public member functions"> |
| <method name="operator()" cv="const"> |
| <type>result_type</type> |
| <parameter name="expr"> |
| <paramtype>typename impl::expr_param</paramtype> |
| <description> |
| <para>The current expression </para> |
| </description> |
| </parameter> |
| <parameter name="state"> |
| <paramtype>typename impl::state_param</paramtype> |
| <description> |
| <para>The current state </para> |
| </description> |
| </parameter> |
| <parameter name="data"> |
| <paramtype>typename impl::data_param</paramtype> |
| <description> |
| <para>An arbitrary data </para> |
| </description> |
| </parameter> |
| <description> |
| <para> |
| Evaluate <computeroutput>R(A..., ...)</computeroutput> as a transform either with |
| <computeroutput><classname>proto::call<></classname></computeroutput> or with |
| <computeroutput><classname>proto::make<></classname></computeroutput> depending |
| on whether <computeroutput><classname>proto::is_callable</classname><R>::value</computeroutput> |
| is <computeroutput>true</computeroutput> or <computeroutput>false</computeroutput>. |
| </para> |
| </description> |
| <requires> |
| <para> |
| <computeroutput><classname>proto::matches</classname><Expr, Grammar>::value</computeroutput> |
| is <computeroutput>true</computeroutput>. |
| </para> |
| </requires> |
| <returns> |
| <para> |
| <computeroutput>which()(expr, state, data)</computeroutput> |
| </para> |
| </returns> |
| </method> |
| </method-group> |
| </struct> |
| <typedef name="proto_grammar"> |
| <type>typename Grammar::proto_grammar</type> |
| </typedef> |
| </struct-specialization> |
| |
| <struct-specialization name="when"> |
| <template> |
| <template-type-parameter name="Grammar"/> |
| </template> |
| <specialization> |
| <template-arg>Grammar</template-arg> |
| <template-arg><classname>proto::external_transform</classname></template-arg> |
| </specialization> |
| <inherit><type> |
| <classname>proto::transform</classname>< when<Grammar, <classname>proto::external_transform</classname>> ></type></inherit> |
| <purpose>A grammar element that associates an externally-specified transform with the grammar. |
| The transform is looked up in the Data parameter using the Grammar as a key.</purpose> |
| <description> |
| <para> |
| Use <computeroutput>proto::when<></computeroutput> to override a grammar's default |
| transform with a custom transform. It is for use when composing larger transforms by associating |
| smaller transforms with individual rules in your grammar. |
| </para> |
| <para> |
| The <computeroutput>when<G, <classname>proto::external_transform</classname>></computeroutput> |
| indicates that the associated transform is not yet known. It should be looked up when the transform |
| is about to be applied. It is found by looking it up in the passed-in Data parameter, which |
| behaves like a compile-time map from grammar types to transform types. The map is indexed using |
| <computeroutput>Grammar</computeroutput> as a key. The associated value type is used as the transform |
| to apply. In this way, the same grammar can be used to define multiple evaluating strategies that |
| can be added post-hoc. |
| </para> |
| <para> |
| See <computeroutput><classname>proto::external_transforms</classname></computeroutput> for an example. |
| </para> |
| </description> |
| <struct name="impl"> |
| <template> |
| <template-type-parameter name="Expr"/> |
| <template-type-parameter name="State"/> |
| <template-type-parameter name="Data"/> |
| </template> |
| <inherit><type> |
| boost::remove_reference< |
| typename mpl::eval_if_c< |
| <classname>proto::result_of::has_env_var</classname><Data, <classname>proto::transforms_type</classname>>::value, |
| <classname>proto::result_of::env_var</classname><Data, <classname>proto::transforms_type</classname>>, |
| <classname>proto::result_of::env_var</classname><Data, <classname>proto::data_type</classname>> |
| >::type |
| >::type |
| ::template when< Grammar > |
| ::template impl< Expr, State, Data ></type></inherit> |
| <description> |
| <para> |
| The implementation of the <code>impl</code> struct depends on whether the <code>Data</code> |
| parameter is a transform environment that contains a value corresponding to the |
| <classname>proto::transforms_type</classname> key. If so, that value is treated as a |
| map from rules to transforms. Otherwise, the <code>Data</code> type itself is treated |
| as such a map. |
| </para> |
| </description> |
| </struct> |
| <typedef name="proto_grammar"> |
| <type>typename Grammar::proto_grammar</type> |
| </typedef> |
| </struct-specialization> |
| |
| <struct name="otherwise"> |
| <template> |
| <template-type-parameter name="Fun"/> |
| </template> |
| <inherit><type><classname>proto::when</classname>< <classname>proto::_</classname>, Fun ></type></inherit> |
| <purpose> |
| Syntactic sugar for <computeroutput><classname>proto::when</classname>< <classname>proto::_</classname>, Fun ></computeroutput>, |
| for use in grammars to handle all the cases not yet handled. |
| </purpose> |
| <description> |
| <para> |
| Use <computeroutput>proto::otherwise<T></computeroutput> in your grammars as a synonym for |
| <computeroutput><classname>proto::when</classname>< <classname>proto::_</classname>, Fun ></computeroutput> |
| as in the following transform which counts the number of terminals in an expression. |
| </para> |
| <para> |
| <programlisting>// Count the terminals in an expression tree. |
| // Must be invoked with initial state == mpl::int_<0>(). |
| struct CountLeaves : |
| <classname>proto::or_</classname>< |
| proto::when<<classname>proto::terminal</classname><<classname>proto::_</classname>>, mpl::next<<classname>proto::_state</classname>>()>, |
| proto::otherwise<<classname>proto::fold</classname><<classname>proto::_</classname>, <classname>proto::_state</classname>, CountLeaves> > |
| > |
| {};</programlisting> |
| </para> |
| </description> |
| </struct> |
| |
| <struct name="external_transform"> |
| <purpose>A placeholder for use as the second parameter for <computeroutput><classname>proto::when</classname></computeroutput> |
| to indicate that the rule's transform is specified externally.</purpose> |
| <description> |
| <para> |
| See <computeroutput><classname>proto::external_transforms</classname></computeroutput> for an example. |
| </para> |
| </description> |
| </struct> |
| |
| <struct name="external_transforms"> |
| <template> |
| <template-type-parameter name="When" pack="1"/> |
| </template> |
| <purpose>A map from grammars to transforms, used as a way to externally associate transforms.</purpose> |
| <typedef name="map_type"> |
| <purpose>For exposition only.</purpose> |
| <type>mpl::map< typename to_mpl_pair< When >::type... ></type> |
| </typedef> |
| <struct name="when"> |
| <template> |
| <template-type-parameter name="Grammar"/> |
| </template> |
| <inherit><type><classname>proto::otherwise</classname>< typename mpl::at< map_type, Grammar >::type ></type></inherit> |
| </struct> |
| <description> |
| <para> |
| It is sometimes desirable to define a grammar that can be customized with different sets of transforms. |
| To do that, where you would normally specify a transform within a grammar, you can instead put |
| <computeroutput><classname>proto::external_transform</classname></computeroutput>; for example: |
| <computeroutput>proto::when< some_grammar, proto::external_transform ></computeroutput>. Then, when |
| invoking the grammar, you can pass an approriately-defined instance of <computeroutput>proto::external_transforms</computeroutput> |
| as the Data parameter. When an expression matches <computeroutput>some_grammar</computeroutput>, Proto |
| will look up the approprite transform in the Data parameter using <computeroutput>some_grammar</computeroutput> |
| as a key. |
| </para> |
| <para> |
| <programlisting>struct int_terminal |
| : <classname>proto::terminal</classname><int> |
| {}; |
| |
| struct char_terminal |
| : <classname>proto::terminal</classname><char> |
| {}; |
| |
| struct my_grammar |
| : <classname>proto::or_</classname>< |
| // The next two grammar rules are customization points. |
| // The associated transforms are specified externally |
| // using external_transforms below. |
| <classname>proto::when</classname>< int_terminal, <classname>proto::external_transform</classname> > |
| , <classname>proto::when</classname>< char_terminal, <classname>proto::external_transform</classname> > |
| , <classname>proto::when</classname>< |
| <classname>proto::plus</classname>< my_grammar, my_grammar > |
| , <classname>proto::fold</classname>< <classname>proto::_</classname>, int(), my_grammar > |
| > |
| > |
| {}; |
| |
| // Here is where the transforms are associated with the |
| // grammar rules above. |
| struct my_transforms |
| : proto::external_transforms< |
| <classname>proto::when</classname><int_terminal, print(<classname>proto::_value</classname>)> |
| , <classname>proto::when</classname><char_terminal, print(<classname>proto::_value</classname>)> |
| > |
| {}; |
| |
| // ... |
| |
| <classname>proto::literal</classname><int> i(1); |
| <classname>proto::literal</classname><char> c('a'); |
| my_transforms trx; |
| |
| // Evaluate "i+c" using my_grammar with the specified transforms: |
| my_grammar()(i + c, 0, trx); |
| |
| // If you would also like to pass arbitrary data along with the |
| // transforms, you can use a transform environment, as so: |
| my_grammar()(i + c, 0, (proto::data = 42, proto::transforms = trx));</programlisting> |
| </para> |
| </description> |
| </struct> |
| </namespace> |
| </namespace> |
| </header> |