1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355
|
<?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 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>
|