113481Sgiacomo.travaglini@arm.com 213481Sgiacomo.travaglini@arm.com 313481Sgiacomo.travaglini@arm.com<b>P</b>ump is <b>U</b>seful for <b>M</b>eta <b>P</b>rogramming. 413481Sgiacomo.travaglini@arm.com 513481Sgiacomo.travaglini@arm.com# The Problem # 613481Sgiacomo.travaglini@arm.com 713481Sgiacomo.travaglini@arm.comTemplate and macro libraries often need to define many classes, 813481Sgiacomo.travaglini@arm.comfunctions, or macros that vary only (or almost only) in the number of 913481Sgiacomo.travaglini@arm.comarguments they take. It's a lot of repetitive, mechanical, and 1013481Sgiacomo.travaglini@arm.comerror-prone work. 1113481Sgiacomo.travaglini@arm.com 1213481Sgiacomo.travaglini@arm.comVariadic templates and variadic macros can alleviate the problem. 1313481Sgiacomo.travaglini@arm.comHowever, while both are being considered by the C++ committee, neither 1413481Sgiacomo.travaglini@arm.comis in the standard yet or widely supported by compilers. Thus they 1513481Sgiacomo.travaglini@arm.comare often not a good choice, especially when your code needs to be 1613481Sgiacomo.travaglini@arm.comportable. And their capabilities are still limited. 1713481Sgiacomo.travaglini@arm.com 1813481Sgiacomo.travaglini@arm.comAs a result, authors of such libraries often have to write scripts to 1913481Sgiacomo.travaglini@arm.comgenerate their implementation. However, our experience is that it's 2013481Sgiacomo.travaglini@arm.comtedious to write such scripts, which tend to reflect the structure of 2113481Sgiacomo.travaglini@arm.comthe generated code poorly and are often hard to read and edit. For 2213481Sgiacomo.travaglini@arm.comexample, a small change needed in the generated code may require some 2313481Sgiacomo.travaglini@arm.comnon-intuitive, non-trivial changes in the script. This is especially 2413481Sgiacomo.travaglini@arm.compainful when experimenting with the code. 2513481Sgiacomo.travaglini@arm.com 2613481Sgiacomo.travaglini@arm.com# Our Solution # 2713481Sgiacomo.travaglini@arm.com 2813481Sgiacomo.travaglini@arm.comPump (for Pump is Useful for Meta Programming, Pretty Useful for Meta 2913481Sgiacomo.travaglini@arm.comProgramming, or Practical Utility for Meta Programming, whichever you 3013481Sgiacomo.travaglini@arm.comprefer) is a simple meta-programming tool for C++. The idea is that a 3113481Sgiacomo.travaglini@arm.comprogrammer writes a `foo.pump` file which contains C++ code plus meta 3213481Sgiacomo.travaglini@arm.comcode that manipulates the C++ code. The meta code can handle 3313481Sgiacomo.travaglini@arm.comiterations over a range, nested iterations, local meta variable 3413481Sgiacomo.travaglini@arm.comdefinitions, simple arithmetic, and conditional expressions. You can 3513481Sgiacomo.travaglini@arm.comview it as a small Domain-Specific Language. The meta language is 3613481Sgiacomo.travaglini@arm.comdesigned to be non-intrusive (s.t. it won't confuse Emacs' C++ mode, 3713481Sgiacomo.travaglini@arm.comfor example) and concise, making Pump code intuitive and easy to 3813481Sgiacomo.travaglini@arm.commaintain. 3913481Sgiacomo.travaglini@arm.com 4013481Sgiacomo.travaglini@arm.com## Highlights ## 4113481Sgiacomo.travaglini@arm.com 4213481Sgiacomo.travaglini@arm.com * The implementation is in a single Python script and thus ultra portable: no build or installation is needed and it works cross platforms. 4313481Sgiacomo.travaglini@arm.com * 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. 4413481Sgiacomo.travaglini@arm.com * The format is human-readable and more concise than XML. 4513481Sgiacomo.travaglini@arm.com * The format works relatively well with Emacs' C++ mode. 4613481Sgiacomo.travaglini@arm.com 4713481Sgiacomo.travaglini@arm.com## Examples ## 4813481Sgiacomo.travaglini@arm.com 4913481Sgiacomo.travaglini@arm.comThe following Pump code (where meta keywords start with `$`, `[[` and `]]` are meta brackets, and `$$` starts a meta comment that ends with the line): 5013481Sgiacomo.travaglini@arm.com 5113481Sgiacomo.travaglini@arm.com``` 5213481Sgiacomo.travaglini@arm.com$var n = 3 $$ Defines a meta variable n. 5313481Sgiacomo.travaglini@arm.com$range i 0..n $$ Declares the range of meta iterator i (inclusive). 5413481Sgiacomo.travaglini@arm.com$for i [[ 5513481Sgiacomo.travaglini@arm.com $$ Meta loop. 5613481Sgiacomo.travaglini@arm.com// Foo$i does blah for $i-ary predicates. 5713481Sgiacomo.travaglini@arm.com$range j 1..i 5813481Sgiacomo.travaglini@arm.comtemplate <size_t N $for j [[, typename A$j]]> 5913481Sgiacomo.travaglini@arm.comclass Foo$i { 6013481Sgiacomo.travaglini@arm.com$if i == 0 [[ 6113481Sgiacomo.travaglini@arm.com blah a; 6213481Sgiacomo.travaglini@arm.com]] $elif i <= 2 [[ 6313481Sgiacomo.travaglini@arm.com blah b; 6413481Sgiacomo.travaglini@arm.com]] $else [[ 6513481Sgiacomo.travaglini@arm.com blah c; 6613481Sgiacomo.travaglini@arm.com]] 6713481Sgiacomo.travaglini@arm.com}; 6813481Sgiacomo.travaglini@arm.com 6913481Sgiacomo.travaglini@arm.com]] 7013481Sgiacomo.travaglini@arm.com``` 7113481Sgiacomo.travaglini@arm.com 7213481Sgiacomo.travaglini@arm.comwill be translated by the Pump compiler to: 7313481Sgiacomo.travaglini@arm.com 7413481Sgiacomo.travaglini@arm.com``` 7513481Sgiacomo.travaglini@arm.com// Foo0 does blah for 0-ary predicates. 7613481Sgiacomo.travaglini@arm.comtemplate <size_t N> 7713481Sgiacomo.travaglini@arm.comclass Foo0 { 7813481Sgiacomo.travaglini@arm.com blah a; 7913481Sgiacomo.travaglini@arm.com}; 8013481Sgiacomo.travaglini@arm.com 8113481Sgiacomo.travaglini@arm.com// Foo1 does blah for 1-ary predicates. 8213481Sgiacomo.travaglini@arm.comtemplate <size_t N, typename A1> 8313481Sgiacomo.travaglini@arm.comclass Foo1 { 8413481Sgiacomo.travaglini@arm.com blah b; 8513481Sgiacomo.travaglini@arm.com}; 8613481Sgiacomo.travaglini@arm.com 8713481Sgiacomo.travaglini@arm.com// Foo2 does blah for 2-ary predicates. 8813481Sgiacomo.travaglini@arm.comtemplate <size_t N, typename A1, typename A2> 8913481Sgiacomo.travaglini@arm.comclass Foo2 { 9013481Sgiacomo.travaglini@arm.com blah b; 9113481Sgiacomo.travaglini@arm.com}; 9213481Sgiacomo.travaglini@arm.com 9313481Sgiacomo.travaglini@arm.com// Foo3 does blah for 3-ary predicates. 9413481Sgiacomo.travaglini@arm.comtemplate <size_t N, typename A1, typename A2, typename A3> 9513481Sgiacomo.travaglini@arm.comclass Foo3 { 9613481Sgiacomo.travaglini@arm.com blah c; 9713481Sgiacomo.travaglini@arm.com}; 9813481Sgiacomo.travaglini@arm.com``` 9913481Sgiacomo.travaglini@arm.com 10013481Sgiacomo.travaglini@arm.comIn another example, 10113481Sgiacomo.travaglini@arm.com 10213481Sgiacomo.travaglini@arm.com``` 10313481Sgiacomo.travaglini@arm.com$range i 1..n 10413481Sgiacomo.travaglini@arm.comFunc($for i + [[a$i]]); 10513481Sgiacomo.travaglini@arm.com$$ The text between i and [[ is the separator between iterations. 10613481Sgiacomo.travaglini@arm.com``` 10713481Sgiacomo.travaglini@arm.com 10813481Sgiacomo.travaglini@arm.comwill generate one of the following lines (without the comments), depending on the value of `n`: 10913481Sgiacomo.travaglini@arm.com 11013481Sgiacomo.travaglini@arm.com``` 11113481Sgiacomo.travaglini@arm.comFunc(); // If n is 0. 11213481Sgiacomo.travaglini@arm.comFunc(a1); // If n is 1. 11313481Sgiacomo.travaglini@arm.comFunc(a1 + a2); // If n is 2. 11413481Sgiacomo.travaglini@arm.comFunc(a1 + a2 + a3); // If n is 3. 11513481Sgiacomo.travaglini@arm.com// And so on... 11613481Sgiacomo.travaglini@arm.com``` 11713481Sgiacomo.travaglini@arm.com 11813481Sgiacomo.travaglini@arm.com## Constructs ## 11913481Sgiacomo.travaglini@arm.com 12013481Sgiacomo.travaglini@arm.comWe support the following meta programming constructs: 12113481Sgiacomo.travaglini@arm.com 12213481Sgiacomo.travaglini@arm.com| `$var id = exp` | Defines a named constant value. `$id` is valid util the end of the current meta lexical block. | 12313481Sgiacomo.travaglini@arm.com|:----------------|:-----------------------------------------------------------------------------------------------| 12413481Sgiacomo.travaglini@arm.com| `$range id exp..exp` | Sets the range of an iteration variable, which can be reused in multiple loops later. | 12513481Sgiacomo.travaglini@arm.com| `$for id sep [[ code ]]` | Iteration. The range of `id` must have been defined earlier. `$id` is valid in `code`. | 12613481Sgiacomo.travaglini@arm.com| `$($)` | Generates a single `$` character. | 12713481Sgiacomo.travaglini@arm.com| `$id` | Value of the named constant or iteration variable. | 12813481Sgiacomo.travaglini@arm.com| `$(exp)` | Value of the expression. | 12913481Sgiacomo.travaglini@arm.com| `$if exp [[ code ]] else_branch` | Conditional. | 13013481Sgiacomo.travaglini@arm.com| `[[ code ]]` | Meta lexical block. | 13113481Sgiacomo.travaglini@arm.com| `cpp_code` | Raw C++ code. | 13213481Sgiacomo.travaglini@arm.com| `$$ comment` | Meta comment. | 13313481Sgiacomo.travaglini@arm.com 13413481Sgiacomo.travaglini@arm.com**Note:** To give the user some freedom in formatting the Pump source 13513481Sgiacomo.travaglini@arm.comcode, Pump ignores a new-line character if it's right after `$for foo` 13613481Sgiacomo.travaglini@arm.comor next to `[[` or `]]`. Without this rule you'll often be forced to write 13713481Sgiacomo.travaglini@arm.comvery long lines to get the desired output. Therefore sometimes you may 13813481Sgiacomo.travaglini@arm.comneed to insert an extra new-line in such places for a new-line to show 13913481Sgiacomo.travaglini@arm.comup in your output. 14013481Sgiacomo.travaglini@arm.com 14113481Sgiacomo.travaglini@arm.com## Grammar ## 14213481Sgiacomo.travaglini@arm.com 14313481Sgiacomo.travaglini@arm.com``` 14413481Sgiacomo.travaglini@arm.comcode ::= atomic_code* 14513481Sgiacomo.travaglini@arm.comatomic_code ::= $var id = exp 14613481Sgiacomo.travaglini@arm.com | $var id = [[ code ]] 14713481Sgiacomo.travaglini@arm.com | $range id exp..exp 14813481Sgiacomo.travaglini@arm.com | $for id sep [[ code ]] 14913481Sgiacomo.travaglini@arm.com | $($) 15013481Sgiacomo.travaglini@arm.com | $id 15113481Sgiacomo.travaglini@arm.com | $(exp) 15213481Sgiacomo.travaglini@arm.com | $if exp [[ code ]] else_branch 15313481Sgiacomo.travaglini@arm.com | [[ code ]] 15413481Sgiacomo.travaglini@arm.com | cpp_code 15513481Sgiacomo.travaglini@arm.comsep ::= cpp_code | empty_string 15613481Sgiacomo.travaglini@arm.comelse_branch ::= $else [[ code ]] 15713481Sgiacomo.travaglini@arm.com | $elif exp [[ code ]] else_branch 15813481Sgiacomo.travaglini@arm.com | empty_string 15913481Sgiacomo.travaglini@arm.comexp ::= simple_expression_in_Python_syntax 16013481Sgiacomo.travaglini@arm.com``` 16113481Sgiacomo.travaglini@arm.com 16213481Sgiacomo.travaglini@arm.com## Code ## 16313481Sgiacomo.travaglini@arm.com 16413481Sgiacomo.travaglini@arm.comYou can find the source code of Pump in [scripts/pump.py](../scripts/pump.py). It is still 16513481Sgiacomo.travaglini@arm.comvery unpolished and lacks automated tests, although it has been 16613481Sgiacomo.travaglini@arm.comsuccessfully used many times. If you find a chance to use it in your 16713481Sgiacomo.travaglini@arm.comproject, please let us know what you think! We also welcome help on 16813481Sgiacomo.travaglini@arm.comimproving Pump. 16913481Sgiacomo.travaglini@arm.com 17013481Sgiacomo.travaglini@arm.com## Real Examples ## 17113481Sgiacomo.travaglini@arm.com 17213481Sgiacomo.travaglini@arm.comYou 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`. 17313481Sgiacomo.travaglini@arm.com 17413481Sgiacomo.travaglini@arm.com## Tips ## 17513481Sgiacomo.travaglini@arm.com 17613481Sgiacomo.travaglini@arm.com * 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. 17713481Sgiacomo.travaglini@arm.com * 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