filters.rst 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. ===================
  2. Source Code Filters
  3. ===================
  4. .. include:: rstcommon.rst
  5. .. default-role:: code
  6. .. contents::
  7. A `Source Code Filter (SCF)` transforms the input character stream to an in-memory
  8. output stream before parsing. A filter can be used to provide templating
  9. systems or preprocessors.
  10. To use a filter for a source file the `#?` notation is used::
  11. #? stdtmpl(subsChar = '$', metaChar = '#')
  12. #proc generateXML(name, age: string): string =
  13. # result = ""
  14. <xml>
  15. <name>$name</name>
  16. <age>$age</age>
  17. </xml>
  18. As the example shows, passing arguments to a filter can be done
  19. just like an ordinary procedure call with named or positional arguments. The
  20. available parameters depend on the invoked filter. Before version 0.12.0 of
  21. the language `#!` was used instead of `#?`.
  22. **Hint:** With `--hint:codeBegin:on`:option: or `--verbosity:2`:option:
  23. (or higher) while compiling or `nim check`:cmd:, Nim lists the processed code after
  24. each filter application.
  25. Usage
  26. =====
  27. First, put your SCF code in a separate file with filters specified in the first line.
  28. **Note:** You can name your SCF file with any file extension you want, but the
  29. conventional extension is `.nimf`
  30. (it used to be `.tmpl` but that was too generic, for example preventing github to
  31. recognize it as Nim source file).
  32. If we use `generateXML` code shown above and call the SCF file `xmlGen.nimf`
  33. In your `main.nim`:
  34. .. code-block:: nim
  35. include "xmlGen.nimf"
  36. echo generateXML("John Smith","42")
  37. Pipe operator
  38. =============
  39. Filters can be combined with the `|` pipe operator::
  40. #? strip(startswith="<") | stdtmpl
  41. #proc generateXML(name, age: string): string =
  42. # result = ""
  43. <xml>
  44. <name>$name</name>
  45. <age>$age</age>
  46. </xml>
  47. Available filters
  48. =================
  49. Replace filter
  50. --------------
  51. The replace filter replaces substrings in each line.
  52. Parameters and their defaults:
  53. * `sub: string = ""`
  54. the substring that is searched for
  55. * `by: string = ""`
  56. the string the substring is replaced with
  57. Strip filter
  58. ------------
  59. The strip filter simply removes leading and trailing whitespace from
  60. each line.
  61. Parameters and their defaults:
  62. * `startswith: string = ""`
  63. strip only the lines that start with *startswith* (ignoring leading
  64. whitespace). If empty every line is stripped.
  65. * `leading: bool = true`
  66. strip leading whitespace
  67. * `trailing: bool = true`
  68. strip trailing whitespace
  69. StdTmpl filter
  70. --------------
  71. The stdtmpl filter provides a simple templating engine for Nim. The
  72. filter uses a line based parser: Lines prefixed with a *meta character*
  73. (default: `#`) contain Nim code, other lines are verbatim. Because
  74. indentation-based parsing is not suited for a templating engine, control flow
  75. statements need `end X` delimiters.
  76. Parameters and their defaults:
  77. * `metaChar: char = '#'`
  78. prefix for a line that contains Nim code
  79. * `subsChar: char = '$'`
  80. prefix for a Nim expression within a template line
  81. * `conc: string = " & "`
  82. the operation for concatenation
  83. * `emit: string = "result.add"`
  84. the operation to emit a string literal
  85. * `toString: string = "$"`
  86. the operation that is applied to each expression
  87. Example::
  88. #? stdtmpl | standard
  89. #proc generateHTMLPage(title, currentTab, content: string,
  90. # tabs: openArray[string]): string =
  91. # result = ""
  92. <head><title>$title</title></head>
  93. <body>
  94. <div id="menu">
  95. <ul>
  96. #for tab in items(tabs):
  97. #if currentTab == tab:
  98. <li><a id="selected"
  99. #else:
  100. <li><a
  101. #end if
  102. href="${tab}.html">$tab</a></li>
  103. #end for
  104. </ul>
  105. </div>
  106. <div id="content">
  107. $content
  108. A dollar: $$.
  109. </div>
  110. </body>
  111. The filter transforms this into:
  112. .. code-block:: nim
  113. proc generateHTMLPage(title, currentTab, content: string,
  114. tabs: openArray[string]): string =
  115. result = ""
  116. result.add("<head><title>" & $(title) & "</title></head>\n" &
  117. "<body>\n" &
  118. " <div id=\"menu\">\n" &
  119. " <ul>\n")
  120. for tab in items(tabs):
  121. if currentTab == tab:
  122. result.add(" <li><a id=\"selected\" \n")
  123. else:
  124. result.add(" <li><a\n")
  125. #end
  126. result.add(" href=\"" & $(tab) & ".html\">" & $(tab) & "</a></li>\n")
  127. #end
  128. result.add(" </ul>\n" &
  129. " </div>\n" &
  130. " <div id=\"content\">\n" &
  131. " " & $(content) & "\n" &
  132. " A dollar: $.\n" &
  133. " </div>\n" &
  134. "</body>\n")
  135. Each line that does not start with the meta character (ignoring leading
  136. whitespace) is converted to a string literal that is added to `result`.
  137. The substitution character introduces a Nim expression *e* within the
  138. string literal. *e* is converted to a string with the *toString* operation
  139. which defaults to `$`. For strong type checking, set `toString` to the
  140. empty string. *e* must match this PEG pattern::
  141. e <- [a-zA-Z\128-\255][a-zA-Z0-9\128-\255_.]* / '{' x '}'
  142. x <- '{' x+ '}' / [^}]*
  143. To produce a single substitution character it has to be doubled: `$$`
  144. produces `$`.
  145. The template engine is quite flexible. It is easy to produce a procedure that
  146. writes the template code directly to a file::
  147. #? stdtmpl(emit="f.write") | standard
  148. #proc writeHTMLPage(f: File, title, currentTab, content: string,
  149. # tabs: openArray[string]) =
  150. <head><title>$title</title></head>
  151. <body>
  152. <div id="menu">
  153. <ul>
  154. #for tab in items(tabs):
  155. #if currentTab == tab:
  156. <li><a id="selected"
  157. #else:
  158. <li><a
  159. #end if
  160. href="${tab}.html" title = "$title - $tab">$tab</a></li>
  161. #end for
  162. </ul>
  163. </div>
  164. <div id="content">
  165. $content
  166. A dollar: $$.
  167. </div>
  168. </body>