]>
Commit | Line | Data |
---|---|---|
31f18b77 FG |
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 | ||
7 | Template and macro libraries often need to define many classes, | |
8 | functions, or macros that vary only (or almost only) in the number of | |
9 | arguments they take. It's a lot of repetitive, mechanical, and | |
10 | error-prone work. | |
11 | ||
12 | Variadic templates and variadic macros can alleviate the problem. | |
13 | However, while both are being considered by the C++ committee, neither | |
14 | is in the standard yet or widely supported by compilers. Thus they | |
15 | are often not a good choice, especially when your code needs to be | |
16 | portable. And their capabilities are still limited. | |
17 | ||
18 | As a result, authors of such libraries often have to write scripts to | |
19 | generate their implementation. However, our experience is that it's | |
20 | tedious to write such scripts, which tend to reflect the structure of | |
21 | the generated code poorly and are often hard to read and edit. For | |
22 | example, a small change needed in the generated code may require some | |
23 | non-intuitive, non-trivial changes in the script. This is especially | |
24 | painful when experimenting with the code. | |
25 | ||
26 | # Our Solution # | |
27 | ||
28 | Pump (for Pump is Useful for Meta Programming, Pretty Useful for Meta | |
29 | Programming, or Practical Utility for Meta Programming, whichever you | |
30 | prefer) is a simple meta-programming tool for C++. The idea is that a | |
31 | programmer writes a `foo.pump` file which contains C++ code plus meta | |
32 | code that manipulates the C++ code. The meta code can handle | |
33 | iterations over a range, nested iterations, local meta variable | |
34 | definitions, simple arithmetic, and conditional expressions. You can | |
35 | view it as a small Domain-Specific Language. The meta language is | |
36 | designed to be non-intrusive (s.t. it won't confuse Emacs' C++ mode, | |
37 | for example) and concise, making Pump code intuitive and easy to | |
38 | maintain. | |
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](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. | |
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 | ||
49 | The 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 | |
58 | template <size_t N $for j [[, typename A$j]]> | |
59 | class 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 | ||
72 | will be translated by the Pump compiler to: | |
73 | ||
74 | ``` | |
75 | // Foo0 does blah for 0-ary predicates. | |
76 | template <size_t N> | |
77 | class Foo0 { | |
78 | blah a; | |
79 | }; | |
80 | ||
81 | // Foo1 does blah for 1-ary predicates. | |
82 | template <size_t N, typename A1> | |
83 | class Foo1 { | |
84 | blah b; | |
85 | }; | |
86 | ||
87 | // Foo2 does blah for 2-ary predicates. | |
88 | template <size_t N, typename A1, typename A2> | |
89 | class Foo2 { | |
90 | blah b; | |
91 | }; | |
92 | ||
93 | // Foo3 does blah for 3-ary predicates. | |
94 | template <size_t N, typename A1, typename A2, typename A3> | |
95 | class Foo3 { | |
96 | blah c; | |
97 | }; | |
98 | ``` | |
99 | ||
100 | In another example, | |
101 | ||
102 | ``` | |
103 | $range i 1..n | |
104 | Func($for i + [[a$i]]); | |
105 | $$ The text between i and [[ is the separator between iterations. | |
106 | ``` | |
107 | ||
108 | will generate one of the following lines (without the comments), depending on the value of `n`: | |
109 | ||
110 | ``` | |
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 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 | |
135 | code, Pump ignores a new-line character if it's right after `$for foo` | |
136 | or next to `[[` or `]]`. Without this rule you'll often be forced to write | |
137 | very long lines to get the desired output. Therefore sometimes you may | |
138 | need to insert an extra new-line in such places for a new-line to show | |
139 | up in your output. | |
140 | ||
141 | ## Grammar ## | |
142 | ||
143 | ``` | |
144 | code ::= atomic_code* | |
145 | atomic_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 | |
155 | sep ::= cpp_code | empty_string | |
156 | else_branch ::= $else [[ code ]] | |
157 | | $elif exp [[ code ]] else_branch | |
158 | | empty_string | |
159 | exp ::= simple_expression_in_Python_syntax | |
160 | ``` | |
161 | ||
162 | ## Code ## | |
163 | ||
164 | You can find the source code of Pump in [scripts/pump.py](../scripts/pump.py). It is still | |
165 | very unpolished and lacks automated tests, although it has been | |
166 | successfully used many times. If you find a chance to use it in your | |
167 | project, please let us know what you think! We also welcome help on | |
168 | improving Pump. | |
169 | ||
170 | ## Real Examples ## | |
171 | ||
172 | 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`. | |
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. |