mirror of
https://github.com/boostorg/proto.git
synced 2026-01-28 07:22:31 +00:00
349 lines
17 KiB
XML
349 lines
17 KiB
XML
<?xml version="1.0" encoding="utf-8"?>
|
|
<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 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>
|
|
<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< Data >::type
|
|
::template when< Grammar >
|
|
::template impl< Expr, State, Data ></type></inherit>
|
|
</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);</programlisting>
|
|
</para>
|
|
</description>
|
|
</struct>
|
|
</namespace>
|
|
</namespace>
|
|
</header>
|