1 2 3<b>P</b>ump is <b>U</b>seful for <b>M</b>eta <b>P</b>rogramming. 4 5# The Problem # 6 7Template and macro libraries often need to define many classes, 8functions, or macros that vary only (or almost only) in the number of 9arguments they take. It's a lot of repetitive, mechanical, and 10error-prone work. 11 12Variadic templates and variadic macros can alleviate the problem. 13However, while both are being considered by the C++ committee, neither 14is in the standard yet or widely supported by compilers. Thus they 15are often not a good choice, especially when your code needs to be 16portable. And their capabilities are still limited. 17 18As a result, authors of such libraries often have to write scripts to 19generate their implementation. However, our experience is that it's 20tedious to write such scripts, which tend to reflect the structure of 21the generated code poorly and are often hard to read and edit. For 22example, a small change needed in the generated code may require some 23non-intuitive, non-trivial changes in the script. This is especially 24painful when experimenting with the code. 25 26# Our Solution # 27 28Pump (for Pump is Useful for Meta Programming, Pretty Useful for Meta 29Programming, or Practical Utility for Meta Programming, whichever you 30prefer) is a simple meta-programming tool for C++. The idea is that a 31programmer writes a `foo.pump` file which contains C++ code plus meta 32code that manipulates the C++ code. The meta code can handle 33iterations over a range, nested iterations, local meta variable 34definitions, simple arithmetic, and conditional expressions. You can 35view it as a small Domain-Specific Language. The meta language is 36designed to be non-intrusive (s.t. it won't confuse Emacs' C++ mode, 37for example) and concise, making Pump code intuitive and easy to 38maintain. 39 40## Highlights ## 41 42 * The implementation is in a single Python script and thus ultra portable: no build or installation is needed and it works cross platforms. 43 * 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. 44 * The format is human-readable and more concise than XML. 45 * The format works relatively well with Emacs' C++ mode. 46 47## Examples ## 48 49The following Pump code (where meta keywords start with `$`, `[[` and `]]` are meta brackets, and `$$` starts a meta comment that ends with the line): 50 51``` 52$var n = 3 $$ Defines a meta variable n. 53$range i 0..n $$ Declares the range of meta iterator i (inclusive). 54$for i [[ 55 $$ Meta loop. 56// Foo$i does blah for $i-ary predicates. 57$range j 1..i 58template <size_t N $for j [[, typename A$j]]> 59class Foo$i { 60$if i == 0 [[ 61 blah a; 62]] $elif i <= 2 [[ 63 blah b; 64]] $else [[ 65 blah c; 66]] 67}; 68 69]] 70``` 71 72will be translated by the Pump compiler to: 73 74``` cpp 75// Foo0 does blah for 0-ary predicates. 76template <size_t N> 77class Foo0 { 78 blah a; 79}; 80 81// Foo1 does blah for 1-ary predicates. 82template <size_t N, typename A1> 83class Foo1 { 84 blah b; 85}; 86 87// Foo2 does blah for 2-ary predicates. 88template <size_t N, typename A1, typename A2> 89class Foo2 { 90 blah b; 91}; 92 93// Foo3 does blah for 3-ary predicates. 94template <size_t N, typename A1, typename A2, typename A3> 95class Foo3 { 96 blah c; 97}; 98``` 99 100In another example, 101 102``` 103$range i 1..n 104Func($for i + [[a$i]]); 105$$ The text between i and [[ is the separator between iterations. 106``` 107 108will generate one of the following lines (without the comments), depending on the value of `n`: 109 110``` cpp 111Func(); // If n is 0. 112Func(a1); // If n is 1. 113Func(a1 + a2); // If n is 2. 114Func(a1 + a2 + a3); // If n is 3. 115// And so on... 116``` 117 118## Constructs ## 119 120We support the following meta programming constructs: 121 122| `$var id = exp` | Defines a named constant value. `$id` is valid util the end of the current meta lexical block. | 123|:----------------|:-----------------------------------------------------------------------------------------------| 124| `$range id exp..exp` | Sets the range of an iteration variable, which can be reused in multiple loops later. | 125| `$for id sep [[ code ]]` | Iteration. The range of `id` must have been defined earlier. `$id` is valid in `code`. | 126| `$($)` | Generates a single `$` character. | 127| `$id` | Value of the named constant or iteration variable. | 128| `$(exp)` | Value of the expression. | 129| `$if exp [[ code ]] else_branch` | Conditional. | 130| `[[ code ]]` | Meta lexical block. | 131| `cpp_code` | Raw C++ code. | 132| `$$ comment` | Meta comment. | 133 134**Note:** To give the user some freedom in formatting the Pump source 135code, Pump ignores a new-line character if it's right after `$for foo` 136or next to `[[` or `]]`. Without this rule you'll often be forced to write 137very long lines to get the desired output. Therefore sometimes you may 138need to insert an extra new-line in such places for a new-line to show 139up in your output. 140 141## Grammar ## 142 143``` ebnf 144code ::= atomic_code* 145atomic_code ::= $var id = exp 146 | $var id = [[ code ]] 147 | $range id exp..exp 148 | $for id sep [[ code ]] 149 | $($) 150 | $id 151 | $(exp) 152 | $if exp [[ code ]] else_branch 153 | [[ code ]] 154 | cpp_code 155sep ::= cpp_code | empty_string 156else_branch ::= $else [[ code ]] 157 | $elif exp [[ code ]] else_branch 158 | empty_string 159exp ::= simple_expression_in_Python_syntax 160``` 161 162## Code ## 163 164You can find the source code of Pump in [scripts/pump.py](../scripts/pump.py). It is still 165very unpolished and lacks automated tests, although it has been 166successfully used many times. If you find a chance to use it in your 167project, please let us know what you think! We also welcome help on 168improving Pump. 169 170## Real Examples ## 171 172You 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`. 173 174## Tips ## 175 176 * 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. 177 * 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. 178