Blame googletest/docs/PumpManual.md

Packit bd1cd8
Packit bd1cd8
Packit bd1cd8
Pump is Useful for Meta Programming.
Packit bd1cd8
Packit bd1cd8
# The Problem #
Packit bd1cd8
Packit bd1cd8
Template and macro libraries often need to define many classes,
Packit bd1cd8
functions, or macros that vary only (or almost only) in the number of
Packit bd1cd8
arguments they take. It's a lot of repetitive, mechanical, and
Packit bd1cd8
error-prone work.
Packit bd1cd8
Packit bd1cd8
Variadic templates and variadic macros can alleviate the problem.
Packit bd1cd8
However, while both are being considered by the C++ committee, neither
Packit bd1cd8
is in the standard yet or widely supported by compilers.  Thus they
Packit bd1cd8
are often not a good choice, especially when your code needs to be
Packit bd1cd8
portable. And their capabilities are still limited.
Packit bd1cd8
Packit bd1cd8
As a result, authors of such libraries often have to write scripts to
Packit bd1cd8
generate their implementation. However, our experience is that it's
Packit bd1cd8
tedious to write such scripts, which tend to reflect the structure of
Packit bd1cd8
the generated code poorly and are often hard to read and edit. For
Packit bd1cd8
example, a small change needed in the generated code may require some
Packit bd1cd8
non-intuitive, non-trivial changes in the script. This is especially
Packit bd1cd8
painful when experimenting with the code.
Packit bd1cd8
Packit bd1cd8
# Our Solution #
Packit bd1cd8
Packit bd1cd8
Pump (for Pump is Useful for Meta Programming, Pretty Useful for Meta
Packit bd1cd8
Programming, or Practical Utility for Meta Programming, whichever you
Packit bd1cd8
prefer) is a simple meta-programming tool for C++. The idea is that a
Packit bd1cd8
programmer writes a `foo.pump` file which contains C++ code plus meta
Packit bd1cd8
code that manipulates the C++ code. The meta code can handle
Packit bd1cd8
iterations over a range, nested iterations, local meta variable
Packit bd1cd8
definitions, simple arithmetic, and conditional expressions. You can
Packit bd1cd8
view it as a small Domain-Specific Language. The meta language is
Packit bd1cd8
designed to be non-intrusive (s.t. it won't confuse Emacs' C++ mode,
Packit bd1cd8
for example) and concise, making Pump code intuitive and easy to
Packit bd1cd8
maintain.
Packit bd1cd8
Packit bd1cd8
## Highlights ##
Packit bd1cd8
Packit bd1cd8
  * The implementation is in a single Python script and thus ultra portable: no build or installation is needed and it works cross platforms.
Packit bd1cd8
  * Pump tries to be smart with respect to [Google's style guide](http://code.google.com/p/google-styleguide/): it breaks long lines (easy to have when they are generated) at acceptable places to fit within 80 columns and indent the continuation lines correctly.
Packit bd1cd8
  * The format is human-readable and more concise than XML.
Packit bd1cd8
  * The format works relatively well with Emacs' C++ mode.
Packit bd1cd8
Packit bd1cd8
## Examples ##
Packit bd1cd8
Packit bd1cd8
The following Pump code (where meta keywords start with `$`, `[[` and `]]` are meta brackets, and `$$` starts a meta comment that ends with the line):
Packit bd1cd8
Packit bd1cd8
```
Packit bd1cd8
$var n = 3     $$ Defines a meta variable n.
Packit bd1cd8
$range i 0..n  $$ Declares the range of meta iterator i (inclusive).
Packit bd1cd8
$for i [[
Packit bd1cd8
               $$ Meta loop.
Packit bd1cd8
// Foo$i does blah for $i-ary predicates.
Packit bd1cd8
$range j 1..i
Packit bd1cd8
template <size_t N $for j [[, typename A$j]]>
Packit bd1cd8
class Foo$i {
Packit bd1cd8
$if i == 0 [[
Packit bd1cd8
  blah a;
Packit bd1cd8
]] $elif i <= 2 [[
Packit bd1cd8
  blah b;
Packit bd1cd8
]] $else [[
Packit bd1cd8
  blah c;
Packit bd1cd8
]]
Packit bd1cd8
};
Packit bd1cd8
Packit bd1cd8
]]
Packit bd1cd8
```
Packit bd1cd8
Packit bd1cd8
will be translated by the Pump compiler to:
Packit bd1cd8
Packit bd1cd8
```
Packit bd1cd8
// Foo0 does blah for 0-ary predicates.
Packit bd1cd8
template <size_t N>
Packit bd1cd8
class Foo0 {
Packit bd1cd8
  blah a;
Packit bd1cd8
};
Packit bd1cd8
Packit bd1cd8
// Foo1 does blah for 1-ary predicates.
Packit bd1cd8
template <size_t N, typename A1>
Packit bd1cd8
class Foo1 {
Packit bd1cd8
  blah b;
Packit bd1cd8
};
Packit bd1cd8
Packit bd1cd8
// Foo2 does blah for 2-ary predicates.
Packit bd1cd8
template <size_t N, typename A1, typename A2>
Packit bd1cd8
class Foo2 {
Packit bd1cd8
  blah b;
Packit bd1cd8
};
Packit bd1cd8
Packit bd1cd8
// Foo3 does blah for 3-ary predicates.
Packit bd1cd8
template <size_t N, typename A1, typename A2, typename A3>
Packit bd1cd8
class Foo3 {
Packit bd1cd8
  blah c;
Packit bd1cd8
};
Packit bd1cd8
```
Packit bd1cd8
Packit bd1cd8
In another example,
Packit bd1cd8
Packit bd1cd8
```
Packit bd1cd8
$range i 1..n
Packit bd1cd8
Func($for i + [[a$i]]);
Packit bd1cd8
$$ The text between i and [[ is the separator between iterations.
Packit bd1cd8
```
Packit bd1cd8
Packit bd1cd8
will generate one of the following lines (without the comments), depending on the value of `n`:
Packit bd1cd8
Packit bd1cd8
```
Packit bd1cd8
Func();              // If n is 0.
Packit bd1cd8
Func(a1);            // If n is 1.
Packit bd1cd8
Func(a1 + a2);       // If n is 2.
Packit bd1cd8
Func(a1 + a2 + a3);  // If n is 3.
Packit bd1cd8
// And so on...
Packit bd1cd8
```
Packit bd1cd8
Packit bd1cd8
## Constructs ##
Packit bd1cd8
Packit bd1cd8
We support the following meta programming constructs:
Packit bd1cd8
Packit bd1cd8
| `$var id = exp` | Defines a named constant value. `$id` is valid util the end of the current meta lexical block. |
Packit bd1cd8
|:----------------|:-----------------------------------------------------------------------------------------------|
Packit bd1cd8
| `$range id exp..exp` | Sets the range of an iteration variable, which can be reused in multiple loops later.          |
Packit bd1cd8
| `$for id sep [[ code ]]` | Iteration. The range of `id` must have been defined earlier. `$id` is valid in `code`.         |
Packit bd1cd8
| `$($)`          | Generates a single `$` character.                                                              |
Packit bd1cd8
| `$id`           | Value of the named constant or iteration variable.                                             |
Packit bd1cd8
| `$(exp)`        | Value of the expression.                                                                       |
Packit bd1cd8
| `$if exp [[ code ]] else_branch` | Conditional.                                                                                   |
Packit bd1cd8
| `[[ code ]]`    | Meta lexical block.                                                                            |
Packit bd1cd8
| `cpp_code`      | Raw C++ code.                                                                                  |
Packit bd1cd8
| `$$ comment`    | Meta comment.                                                                                  |
Packit bd1cd8
Packit bd1cd8
**Note:** To give the user some freedom in formatting the Pump source
Packit bd1cd8
code, Pump ignores a new-line character if it's right after `$for foo`
Packit bd1cd8
or next to `[[` or `]]`. Without this rule you'll often be forced to write
Packit bd1cd8
very long lines to get the desired output. Therefore sometimes you may
Packit bd1cd8
need to insert an extra new-line in such places for a new-line to show
Packit bd1cd8
up in your output.
Packit bd1cd8
Packit bd1cd8
## Grammar ##
Packit bd1cd8
Packit bd1cd8
```
Packit bd1cd8
code ::= atomic_code*
Packit bd1cd8
atomic_code ::= $var id = exp
Packit bd1cd8
    | $var id = [[ code ]]
Packit bd1cd8
    | $range id exp..exp
Packit bd1cd8
    | $for id sep [[ code ]]
Packit bd1cd8
    | $($)
Packit bd1cd8
    | $id
Packit bd1cd8
    | $(exp)
Packit bd1cd8
    | $if exp [[ code ]] else_branch
Packit bd1cd8
    | [[ code ]]
Packit bd1cd8
    | cpp_code
Packit bd1cd8
sep ::= cpp_code | empty_string
Packit bd1cd8
else_branch ::= $else [[ code ]]
Packit bd1cd8
    | $elif exp [[ code ]] else_branch
Packit bd1cd8
    | empty_string
Packit bd1cd8
exp ::= simple_expression_in_Python_syntax
Packit bd1cd8
```
Packit bd1cd8
Packit bd1cd8
## Code ##
Packit bd1cd8
Packit bd1cd8
You can find the source code of Pump in [scripts/pump.py](../scripts/pump.py). It is still
Packit bd1cd8
very unpolished and lacks automated tests, although it has been
Packit bd1cd8
successfully used many times. If you find a chance to use it in your
Packit bd1cd8
project, please let us know what you think!  We also welcome help on
Packit bd1cd8
improving Pump.
Packit bd1cd8
Packit bd1cd8
## Real Examples ##
Packit bd1cd8
Packit bd1cd8
You can find real-world applications of Pump in [Google Test](http://www.google.com/codesearch?q=file%3A\.pump%24+package%3Ahttp%3A%2F%2Fgoogletest\.googlecode\.com) and [Google Mock](http://www.google.com/codesearch?q=file%3A\.pump%24+package%3Ahttp%3A%2F%2Fgooglemock\.googlecode\.com).  The source file `foo.h.pump` generates `foo.h`.
Packit bd1cd8
Packit bd1cd8
## Tips ##
Packit bd1cd8
Packit bd1cd8
  * If a meta variable is followed by a letter or digit, you can separate them using `[[]]`, which inserts an empty string. For example `Foo$j[[]]Helper` generate `Foo1Helper` when `j` is 1.
Packit bd1cd8
  * To avoid extra-long Pump source lines, you can break a line anywhere you want by inserting `[[]]` followed by a new line. Since any new-line character next to `[[` or `]]` is ignored, the generated code won't contain this new line.