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