<b>P</b>ump is <b>U</b>seful for <b>M</b>eta <b>P</b>rogramming.
<b>P</b>ump is <b>U</b>seful for <b>M</b>eta <b>P</b>rogramming.
# The Problem #
# The Problem
Template and macro libraries often need to define many classes,
Template and macro libraries often need to define many classes, functions, or
functions, or macros that vary only (or almost only) in the number of
macros that vary only (or almost only) in the number of arguments they take.
arguments they take. It's a lot of repetitive, mechanical, and
It's a lot of repetitive, mechanical, and error-prone work.
error-prone work.
Variadic templates and variadic macros can alleviate the problem.
Variadic templates and variadic macros can alleviate the problem. However, while
However, while both are being considered by the C++ committee, neither
both are being considered by the C++ committee, neither is in the standard yet
is in the standard yet or widely supported by compilers. Thus they
or widely supported by compilers. Thus they are often not a good choice,
are often not a good choice, especially when your code needs to be
especially when your code needs to be portable. And their capabilities are still
portable. And their capabilities are still limited.
limited.
As a result, authors of such libraries often have to write scripts to
As a result, authors of such libraries often have to write scripts to generate
generate their implementation. However, our experience is that it's
their implementation. However, our experience is that it's tedious to write such
tedious to write such scripts, which tend to reflect the structure of
scripts, which tend to reflect the structure of the generated code poorly and
the generated code poorly and are often hard to read and edit. For
are often hard to read and edit. For example, a small change needed in the
example, a small change needed in the generated code may require some
generated code may require some non-intuitive, non-trivial changes in the
non-intuitive, non-trivial changes in the script. This is especially
script. This is especially painful when experimenting with the code.
painful when experimenting with the code.
# Our Solution #
# Our Solution
Pump (for Pump is Useful for Meta Programming, Pretty Useful for Meta
Pump (for Pump is Useful for Meta Programming, Pretty Useful for Meta
Programming, or Practical Utility for Meta Programming, whichever you
Programming, or Practical Utility for Meta Programming, whichever you prefer) is
prefer) is a simple meta-programming tool for C++. The idea is that a
a simple meta-programming tool for C++. The idea is that a programmer writes a
programmer writes a `foo.pump` file which contains C++ code plus meta
`foo.pump` file which contains C++ code plus meta code that manipulates the C++
code that manipulates the C++ code. The meta code can handle
code. The meta code can handle iterations over a range, nested iterations, local
iterations over a range, nested iterations, local meta variable
meta variable definitions, simple arithmetic, and conditional expressions. You
definitions, simple arithmetic, and conditional expressions. You can
can view it as a small Domain-Specific Language. The meta language is designed
view it as a small Domain-Specific Language. The meta language is
to be non-intrusive (s.t. it won't confuse Emacs' C++ mode, for example) and
designed to be non-intrusive (s.t. it won't confuse Emacs' C++ mode,
concise, making Pump code intuitive and easy to maintain.
for example) and concise, making Pump code intuitive and easy to
maintain.
## Highlights
## Highlights ##
* The implementation is in a single Python script and thus ultra portable: no
build or installation is needed and it works cross platforms.
* The implementation is in a single Python script and thus ultra portable: no build or installation is needed and it works cross platforms.
* Pump tries to be smart with respect to
* Pump tries to be smart with respect to [Google's style guide](https://github.com/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.
[Google's style guide](https://github.com/google/styleguide): it breaks long
* The format is human-readable and more concise than XML.
lines (easy to have when they are generated) at acceptable places to fit
* The format works relatively well with Emacs' C++ mode.
within 80 columns and indent the continuation lines correctly.
* The format is human-readable and more concise than XML.
## Examples ##
* The format works relatively well with Emacs' C++ mode.
The following Pump code (where meta keywords start with `$`, `[[` and `]]` are meta brackets, and `$$` starts a meta comment that ends with the line):
## Examples
The following Pump code (where meta keywords start with `$`, `[[` and `]]` are
meta brackets, and `$$` starts a meta comment that ends with the line):
```
```
$var n = 3 $$ Defines a meta variable n.
$var n = 3 $$ Defines a meta variable n.
...
@@ -71,7 +70,7 @@ $if i == 0 [[
...
@@ -71,7 +70,7 @@ $if i == 0 [[
will be translated by the Pump compiler to:
will be translated by the Pump compiler to:
```cpp
```cpp
// Foo0 does blah for 0-ary predicates.
// Foo0 does blah for 0-ary predicates.
template<size_tN>
template<size_tN>
classFoo0{
classFoo0{
...
@@ -105,9 +104,10 @@ Func($for i + [[a$i]]);
...
@@ -105,9 +104,10 @@ Func($for i + [[a$i]]);
$$ The text between i and [[ is the separator between iterations.
$$ The text between i and [[ is the separator between iterations.
```
```
will generate one of the following lines (without the comments), depending on the value of `n`:
will generate one of the following lines (without the comments), depending on
the value of `n`:
```cpp
```cpp
Func();// If n is 0.
Func();// If n is 0.
Func(a1);// If n is 1.
Func(a1);// If n is 1.
Func(a1+a2);// If n is 2.
Func(a1+a2);// If n is 2.
...
@@ -115,32 +115,38 @@ Func(a1 + a2 + a3); // If n is 3.
...
@@ -115,32 +115,38 @@ Func(a1 + a2 + a3); // If n is 3.
// And so on...
// And so on...
```
```
## Constructs ##
## Constructs
We support the following meta programming constructs:
We support the following meta programming constructs:
| `$var id = exp` | Defines a named constant value. `$id` is valid util the end of the current meta lexical block. |
| `$var id = exp` | Defines a named constant value. `$id` is |
You can find the source code of Pump in [scripts/pump.py](../scripts/pump.py). It is still
You can find the source code of Pump in [scripts/pump.py](../scripts/pump.py).
very unpolished and lacks automated tests, although it has been
It is still very unpolished and lacks automated tests, although it has been
successfully used many times. If you find a chance to use it in your
successfully used many times. If you find a chance to use it in your project,
project, please let us know what you think! We also welcome help on
please let us know what you think! We also welcome help on improving Pump.
improving Pump.
## Real Examples ##
## Real Examples
You can find real-world applications of Pump in [Google Test](https://github.com/google/googletest/tree/master/googletest) and [Google Mock](https://github.com/google/googletest/tree/master/googlemock). The source file `foo.h.pump` generates `foo.h`.
You can find real-world applications of Pump in
[Google Test](https://github.com/google/googletest/tree/master/googletest) and
[Google Mock](https://github.com/google/googletest/tree/master/googlemock). The
source file `foo.h.pump` generates `foo.h`.
## Tips ##
## Tips
* 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.
* If a meta variable is followed by a letter or digit, you can separate them
* 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.
using `[[]]`, which inserts an empty string. For example `Foo$j[[]]Helper`
generate `Foo1Helper` when `j` is 1.
* 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