You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

190 lines
6.9 KiB

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