guard-mthaml 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (341) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +34 -0
  3. data/lib/guard/mthaml.rb +140 -0
  4. data/lib/guard/mthaml/compiler/MtHaml.php +255 -0
  5. data/lib/guard/mthaml/templates/Guardfile +12 -0
  6. data/lib/guard/mthaml/version.rb +5 -0
  7. data/vendor/autoload.php +7 -0
  8. data/vendor/coffeescript/coffeescript/LICENSE +22 -0
  9. data/vendor/coffeescript/coffeescript/README.md +96 -0
  10. data/vendor/coffeescript/coffeescript/composer.json +23 -0
  11. data/vendor/coffeescript/coffeescript/grammar.y +309 -0
  12. data/vendor/coffeescript/coffeescript/make.php +115 -0
  13. data/vendor/coffeescript/coffeescript/src/CoffeeScript/Compiler.php +76 -0
  14. data/vendor/coffeescript/coffeescript/src/CoffeeScript/Error.php +15 -0
  15. data/vendor/coffeescript/coffeescript/src/CoffeeScript/Helpers.php +116 -0
  16. data/vendor/coffeescript/coffeescript/src/CoffeeScript/Init.php +96 -0
  17. data/vendor/coffeescript/coffeescript/src/CoffeeScript/Lexer.php +1356 -0
  18. data/vendor/coffeescript/coffeescript/src/CoffeeScript/Nodes.php +105 -0
  19. data/vendor/coffeescript/coffeescript/src/CoffeeScript/Parser.php +3326 -0
  20. data/vendor/coffeescript/coffeescript/src/CoffeeScript/Rewriter.php +552 -0
  21. data/vendor/coffeescript/coffeescript/src/CoffeeScript/Scope.php +196 -0
  22. data/vendor/coffeescript/coffeescript/src/CoffeeScript/SyntaxError.php +9 -0
  23. data/vendor/coffeescript/coffeescript/src/CoffeeScript/Value.php +20 -0
  24. data/vendor/coffeescript/coffeescript/src/CoffeeScript/yy/Access.php +31 -0
  25. data/vendor/coffeescript/coffeescript/src/CoffeeScript/yy/Arr.php +69 -0
  26. data/vendor/coffeescript/coffeescript/src/CoffeeScript/yy/Assign.php +353 -0
  27. data/vendor/coffeescript/coffeescript/src/CoffeeScript/yy/Base.php +288 -0
  28. data/vendor/coffeescript/coffeescript/src/CoffeeScript/yy/Block.php +294 -0
  29. data/vendor/coffeescript/coffeescript/src/CoffeeScript/yy/Call.php +283 -0
  30. data/vendor/coffeescript/coffeescript/src/CoffeeScript/yy/Class.php +282 -0
  31. data/vendor/coffeescript/coffeescript/src/CoffeeScript/yy/Closure.php +49 -0
  32. data/vendor/coffeescript/coffeescript/src/CoffeeScript/yy/Code.php +203 -0
  33. data/vendor/coffeescript/coffeescript/src/CoffeeScript/yy/Comment.php +39 -0
  34. data/vendor/coffeescript/coffeescript/src/CoffeeScript/yy/Existence.php +42 -0
  35. data/vendor/coffeescript/coffeescript/src/CoffeeScript/yy/Extends.php +26 -0
  36. data/vendor/coffeescript/coffeescript/src/CoffeeScript/yy/For.php +250 -0
  37. data/vendor/coffeescript/coffeescript/src/CoffeeScript/yy/If.php +161 -0
  38. data/vendor/coffeescript/coffeescript/src/CoffeeScript/yy/In.php +99 -0
  39. data/vendor/coffeescript/coffeescript/src/CoffeeScript/yy/Index.php +27 -0
  40. data/vendor/coffeescript/coffeescript/src/CoffeeScript/yy/Literal.php +96 -0
  41. data/vendor/coffeescript/coffeescript/src/CoffeeScript/yy/Obj.php +126 -0
  42. data/vendor/coffeescript/coffeescript/src/CoffeeScript/yy/Op.php +292 -0
  43. data/vendor/coffeescript/coffeescript/src/CoffeeScript/yy/Param.php +119 -0
  44. data/vendor/coffeescript/coffeescript/src/CoffeeScript/yy/Parens.php +45 -0
  45. data/vendor/coffeescript/coffeescript/src/CoffeeScript/yy/Range.php +225 -0
  46. data/vendor/coffeescript/coffeescript/src/CoffeeScript/yy/Return.php +56 -0
  47. data/vendor/coffeescript/coffeescript/src/CoffeeScript/yy/Slice.php +47 -0
  48. data/vendor/coffeescript/coffeescript/src/CoffeeScript/yy/Splat.php +100 -0
  49. data/vendor/coffeescript/coffeescript/src/CoffeeScript/yy/Switch.php +121 -0
  50. data/vendor/coffeescript/coffeescript/src/CoffeeScript/yy/Throw.php +37 -0
  51. data/vendor/coffeescript/coffeescript/src/CoffeeScript/yy/Try.php +79 -0
  52. data/vendor/coffeescript/coffeescript/src/CoffeeScript/yy/Value.php +210 -0
  53. data/vendor/coffeescript/coffeescript/src/CoffeeScript/yy/While.php +112 -0
  54. data/vendor/coffeescript/coffeescript/tests/cases/arrays.coffee +77 -0
  55. data/vendor/coffeescript/coffeescript/tests/cases/assignment.coffee +352 -0
  56. data/vendor/coffeescript/coffeescript/tests/cases/booleans.coffee +21 -0
  57. data/vendor/coffeescript/coffeescript/tests/cases/classes.coffee +681 -0
  58. data/vendor/coffeescript/coffeescript/tests/cases/comments.coffee +207 -0
  59. data/vendor/coffeescript/coffeescript/tests/cases/compilation.coffee +72 -0
  60. data/vendor/coffeescript/coffeescript/tests/cases/comprehensions.coffee +501 -0
  61. data/vendor/coffeescript/coffeescript/tests/cases/control_flow.coffee +430 -0
  62. data/vendor/coffeescript/coffeescript/tests/cases/eval.coffee +29 -0
  63. data/vendor/coffeescript/coffeescript/tests/cases/exception_handling.coffee +102 -0
  64. data/vendor/coffeescript/coffeescript/tests/cases/formatting.coffee +146 -0
  65. data/vendor/coffeescript/coffeescript/tests/cases/function_invocation.coffee +552 -0
  66. data/vendor/coffeescript/coffeescript/tests/cases/functions.coffee +188 -0
  67. data/vendor/coffeescript/coffeescript/tests/cases/helpers.coffee +96 -0
  68. data/vendor/coffeescript/coffeescript/tests/cases/importing.coffee +18 -0
  69. data/vendor/coffeescript/coffeescript/tests/cases/interpolation.coffee +138 -0
  70. data/vendor/coffeescript/coffeescript/tests/cases/javascript_literals.coffee +10 -0
  71. data/vendor/coffeescript/coffeescript/tests/cases/numbers.coffee +76 -0
  72. data/vendor/coffeescript/coffeescript/tests/cases/objects.coffee +271 -0
  73. data/vendor/coffeescript/coffeescript/tests/cases/operators.coffee +277 -0
  74. data/vendor/coffeescript/coffeescript/tests/cases/option_parser.coffee +43 -0
  75. data/vendor/coffeescript/coffeescript/tests/cases/ranges.coffee +88 -0
  76. data/vendor/coffeescript/coffeescript/tests/cases/regexps.coffee +63 -0
  77. data/vendor/coffeescript/coffeescript/tests/cases/scope.coffee +43 -0
  78. data/vendor/coffeescript/coffeescript/tests/cases/slicing_and_splicing.coffee +143 -0
  79. data/vendor/coffeescript/coffeescript/tests/cases/soaks.coffee +134 -0
  80. data/vendor/coffeescript/coffeescript/tests/cases/strict.coffee +155 -0
  81. data/vendor/coffeescript/coffeescript/tests/cases/strings.coffee +107 -0
  82. data/vendor/coffeescript/coffeescript/tests/css/style.css +43 -0
  83. data/vendor/coffeescript/coffeescript/tests/index.php +119 -0
  84. data/vendor/coffeescript/coffeescript/tests/js/lib/coffeescript_1.1.1.js +8 -0
  85. data/vendor/coffeescript/coffeescript/tests/js/lib/coffeescript_1.2.0.js +8 -0
  86. data/vendor/coffeescript/coffeescript/tests/js/lib/coffeescript_1.3.0.js +8 -0
  87. data/vendor/coffeescript/coffeescript/tests/js/lib/coffeescript_1.3.1.js +8 -0
  88. data/vendor/coffeescript/coffeescript/tests/js/lib/diff.js +276 -0
  89. data/vendor/coffeescript/coffeescript/tests/js/main.js +123 -0
  90. data/vendor/coffeescript/coffeescript/vendor/ParserGenerator/LICENSE.txt +10 -0
  91. data/vendor/coffeescript/coffeescript/vendor/ParserGenerator/PHP/Lempar.php +948 -0
  92. data/vendor/coffeescript/coffeescript/vendor/ParserGenerator/PHP/ParserGenerator/Action.php +257 -0
  93. data/vendor/coffeescript/coffeescript/vendor/ParserGenerator/PHP/ParserGenerator/ActionTable.php +299 -0
  94. data/vendor/coffeescript/coffeescript/vendor/ParserGenerator/PHP/ParserGenerator/Config.php +574 -0
  95. data/vendor/coffeescript/coffeescript/vendor/ParserGenerator/PHP/ParserGenerator/Data.php +1857 -0
  96. data/vendor/coffeescript/coffeescript/vendor/ParserGenerator/PHP/ParserGenerator/Parser.php +851 -0
  97. data/vendor/coffeescript/coffeescript/vendor/ParserGenerator/PHP/ParserGenerator/PropagationLink.php +126 -0
  98. data/vendor/coffeescript/coffeescript/vendor/ParserGenerator/PHP/ParserGenerator/Rule.php +144 -0
  99. data/vendor/coffeescript/coffeescript/vendor/ParserGenerator/PHP/ParserGenerator/State.php +283 -0
  100. data/vendor/coffeescript/coffeescript/vendor/ParserGenerator/PHP/ParserGenerator/Symbol.php +288 -0
  101. data/vendor/coffeescript/coffeescript/vendor/ParserGenerator/PHP/ParserGenerator/cli.php +5 -0
  102. data/vendor/coffeescript/coffeescript/vendor/ParserGenerator/ParserGenerator.php +811 -0
  103. data/vendor/composer/ClassLoader.php +383 -0
  104. data/vendor/composer/autoload_classmap.php +9 -0
  105. data/vendor/composer/autoload_namespaces.php +12 -0
  106. data/vendor/composer/autoload_psr4.php +10 -0
  107. data/vendor/composer/autoload_real.php +50 -0
  108. data/vendor/composer/installed.json +166 -0
  109. data/vendor/michelf/php-markdown/License.md +36 -0
  110. data/vendor/michelf/php-markdown/Michelf/Markdown.inc.php +10 -0
  111. data/vendor/michelf/php-markdown/Michelf/Markdown.php +3117 -0
  112. data/vendor/michelf/php-markdown/Michelf/MarkdownExtra.inc.php +11 -0
  113. data/vendor/michelf/php-markdown/Michelf/MarkdownExtra.php +38 -0
  114. data/vendor/michelf/php-markdown/Michelf/MarkdownInterface.inc.php +9 -0
  115. data/vendor/michelf/php-markdown/Michelf/MarkdownInterface.php +37 -0
  116. data/vendor/michelf/php-markdown/Readme.md +305 -0
  117. data/vendor/michelf/php-markdown/Readme.php +31 -0
  118. data/vendor/michelf/php-markdown/composer.json +31 -0
  119. data/vendor/mthaml/mthaml/CHANGELOG +48 -0
  120. data/vendor/mthaml/mthaml/LICENSE +44 -0
  121. data/vendor/mthaml/mthaml/README.markdown +262 -0
  122. data/vendor/mthaml/mthaml/composer.json +45 -0
  123. data/vendor/mthaml/mthaml/docs/Makefile +153 -0
  124. data/vendor/mthaml/mthaml/docs/_static/mthaml.css +30 -0
  125. data/vendor/mthaml/mthaml/docs/_theme/mthaml/theme.conf +4 -0
  126. data/vendor/mthaml/mthaml/docs/conf.py +242 -0
  127. data/vendor/mthaml/mthaml/docs/index.rst +18 -0
  128. data/vendor/mthaml/mthaml/docs/twig-syntax.rst +274 -0
  129. data/vendor/mthaml/mthaml/examples/README.md +5 -0
  130. data/vendor/mthaml/mthaml/examples/autoload.php +8 -0
  131. data/vendor/mthaml/mthaml/examples/example-php.haml +5 -0
  132. data/vendor/mthaml/mthaml/examples/example-php.php +37 -0
  133. data/vendor/mthaml/mthaml/examples/example-twig-noext.twig +11 -0
  134. data/vendor/mthaml/mthaml/examples/example-twig.haml +9 -0
  135. data/vendor/mthaml/mthaml/examples/example-twig.php +60 -0
  136. data/vendor/mthaml/mthaml/examples/example.twig.haml +8 -0
  137. data/vendor/mthaml/mthaml/lib/MtHaml/Autoloader.php +22 -0
  138. data/vendor/mthaml/mthaml/lib/MtHaml/Environment.php +178 -0
  139. data/vendor/mthaml/mthaml/lib/MtHaml/Escaping.php +33 -0
  140. data/vendor/mthaml/mthaml/lib/MtHaml/Exception.php +9 -0
  141. data/vendor/mthaml/mthaml/lib/MtHaml/Exception/SyntaxErrorException.php +9 -0
  142. data/vendor/mthaml/mthaml/lib/MtHaml/Filter/AbstractFilter.php +43 -0
  143. data/vendor/mthaml/mthaml/lib/MtHaml/Filter/Cdata.php +16 -0
  144. data/vendor/mthaml/mthaml/lib/MtHaml/Filter/CoffeeScript.php +33 -0
  145. data/vendor/mthaml/mthaml/lib/MtHaml/Filter/Css.php +26 -0
  146. data/vendor/mthaml/mthaml/lib/MtHaml/Filter/Escaped.php +22 -0
  147. data/vendor/mthaml/mthaml/lib/MtHaml/Filter/FilterInterface.php +15 -0
  148. data/vendor/mthaml/mthaml/lib/MtHaml/Filter/Javascript.php +26 -0
  149. data/vendor/mthaml/mthaml/lib/MtHaml/Filter/Less.php +27 -0
  150. data/vendor/mthaml/mthaml/lib/MtHaml/Filter/Less/LeafoLess.php +20 -0
  151. data/vendor/mthaml/mthaml/lib/MtHaml/Filter/Less/OyejorgeLess.php +23 -0
  152. data/vendor/mthaml/mthaml/lib/MtHaml/Filter/Markdown.php +58 -0
  153. data/vendor/mthaml/mthaml/lib/MtHaml/Filter/Markdown/CebeMarkdown.php +22 -0
  154. data/vendor/mthaml/mthaml/lib/MtHaml/Filter/Markdown/Ciconia.php +21 -0
  155. data/vendor/mthaml/mthaml/lib/MtHaml/Filter/Markdown/MichelfMarkdown.php +21 -0
  156. data/vendor/mthaml/mthaml/lib/MtHaml/Filter/Markdown/Parsedown.php +21 -0
  157. data/vendor/mthaml/mthaml/lib/MtHaml/Filter/Php.php +37 -0
  158. data/vendor/mthaml/mthaml/lib/MtHaml/Filter/Plain.php +24 -0
  159. data/vendor/mthaml/mthaml/lib/MtHaml/Filter/Preserve.php +19 -0
  160. data/vendor/mthaml/mthaml/lib/MtHaml/Filter/Scss.php +37 -0
  161. data/vendor/mthaml/mthaml/lib/MtHaml/Filter/Twig.php +47 -0
  162. data/vendor/mthaml/mthaml/lib/MtHaml/Indentation/Indentation.php +96 -0
  163. data/vendor/mthaml/mthaml/lib/MtHaml/Indentation/IndentationException.php +9 -0
  164. data/vendor/mthaml/mthaml/lib/MtHaml/Indentation/IndentationInterface.php +50 -0
  165. data/vendor/mthaml/mthaml/lib/MtHaml/Indentation/Undefined.php +41 -0
  166. data/vendor/mthaml/mthaml/lib/MtHaml/Node/Comment.php +71 -0
  167. data/vendor/mthaml/mthaml/lib/MtHaml/Node/Doctype.php +96 -0
  168. data/vendor/mthaml/mthaml/lib/MtHaml/Node/EscapableAbstract.php +19 -0
  169. data/vendor/mthaml/mthaml/lib/MtHaml/Node/Filter.php +51 -0
  170. data/vendor/mthaml/mthaml/lib/MtHaml/Node/Insert.php +42 -0
  171. data/vendor/mthaml/mthaml/lib/MtHaml/Node/InterpolatedString.php +73 -0
  172. data/vendor/mthaml/mthaml/lib/MtHaml/Node/NestAbstract.php +117 -0
  173. data/vendor/mthaml/mthaml/lib/MtHaml/Node/NestInterface.php +10 -0
  174. data/vendor/mthaml/mthaml/lib/MtHaml/Node/NodeAbstract.php +77 -0
  175. data/vendor/mthaml/mthaml/lib/MtHaml/Node/ObjectRefClass.php +42 -0
  176. data/vendor/mthaml/mthaml/lib/MtHaml/Node/ObjectRefId.php +42 -0
  177. data/vendor/mthaml/mthaml/lib/MtHaml/Node/Root.php +35 -0
  178. data/vendor/mthaml/mthaml/lib/MtHaml/Node/Run.php +71 -0
  179. data/vendor/mthaml/mthaml/lib/MtHaml/Node/Statement.php +45 -0
  180. data/vendor/mthaml/mthaml/lib/MtHaml/Node/Tag.php +90 -0
  181. data/vendor/mthaml/mthaml/lib/MtHaml/Node/TagAttribute.php +62 -0
  182. data/vendor/mthaml/mthaml/lib/MtHaml/Node/TagAttributeInterpolation.php +24 -0
  183. data/vendor/mthaml/mthaml/lib/MtHaml/Node/TagAttributeList.php +24 -0
  184. data/vendor/mthaml/mthaml/lib/MtHaml/Node/Text.php +37 -0
  185. data/vendor/mthaml/mthaml/lib/MtHaml/NodeVisitor/Autoclose.php +25 -0
  186. data/vendor/mthaml/mthaml/lib/MtHaml/NodeVisitor/Escaping.php +105 -0
  187. data/vendor/mthaml/mthaml/lib/MtHaml/NodeVisitor/MergeAttrs.php +110 -0
  188. data/vendor/mthaml/mthaml/lib/MtHaml/NodeVisitor/Midblock.php +37 -0
  189. data/vendor/mthaml/mthaml/lib/MtHaml/NodeVisitor/NodeVisitorAbstract.php +226 -0
  190. data/vendor/mthaml/mthaml/lib/MtHaml/NodeVisitor/NodeVisitorInterface.php +97 -0
  191. data/vendor/mthaml/mthaml/lib/MtHaml/NodeVisitor/PhpRenderer.php +288 -0
  192. data/vendor/mthaml/mthaml/lib/MtHaml/NodeVisitor/Printer.php +265 -0
  193. data/vendor/mthaml/mthaml/lib/MtHaml/NodeVisitor/RendererAbstract.php +581 -0
  194. data/vendor/mthaml/mthaml/lib/MtHaml/NodeVisitor/TwigRenderer.php +252 -0
  195. data/vendor/mthaml/mthaml/lib/MtHaml/Parser.php +862 -0
  196. data/vendor/mthaml/mthaml/lib/MtHaml/Parser/Buffer.php +147 -0
  197. data/vendor/mthaml/mthaml/lib/MtHaml/Runtime.php +218 -0
  198. data/vendor/mthaml/mthaml/lib/MtHaml/Runtime/AttributeInterpolation.php +16 -0
  199. data/vendor/mthaml/mthaml/lib/MtHaml/Runtime/AttributeList.php +16 -0
  200. data/vendor/mthaml/mthaml/lib/MtHaml/Support/Php/Executor.php +157 -0
  201. data/vendor/mthaml/mthaml/lib/MtHaml/Support/Twig/Extension.php +47 -0
  202. data/vendor/mthaml/mthaml/lib/MtHaml/Support/Twig/Lexer.php +48 -0
  203. data/vendor/mthaml/mthaml/lib/MtHaml/Support/Twig/Loader.php +81 -0
  204. data/vendor/mthaml/mthaml/lib/MtHaml/Target/Php.php +23 -0
  205. data/vendor/mthaml/mthaml/lib/MtHaml/Target/TargetAbstract.php +87 -0
  206. data/vendor/mthaml/mthaml/lib/MtHaml/Target/TargetInterface.php +12 -0
  207. data/vendor/mthaml/mthaml/lib/MtHaml/Target/Twig.php +23 -0
  208. data/vendor/mthaml/mthaml/lib/MtHaml/TreeBuilder.php +100 -0
  209. data/vendor/mthaml/mthaml/lib/MtHaml/TreeBuilderException.php +9 -0
  210. data/vendor/mthaml/mthaml/phpunit.xml +25 -0
  211. data/vendor/mthaml/mthaml/test/MtHaml/Tests/EnvironmentTest.php +59 -0
  212. data/vendor/mthaml/mthaml/test/MtHaml/Tests/HamlSpecTest.php +83 -0
  213. data/vendor/mthaml/mthaml/test/MtHaml/Tests/IndentationTest.php +140 -0
  214. data/vendor/mthaml/mthaml/test/MtHaml/Tests/Node/DoctypeTest.php +51 -0
  215. data/vendor/mthaml/mthaml/test/MtHaml/Tests/Node/NodeTest.php +110 -0
  216. data/vendor/mthaml/mthaml/test/MtHaml/Tests/NodeVisitor/PhpRendererTest.php +113 -0
  217. data/vendor/mthaml/mthaml/test/MtHaml/Tests/NodeVisitor/TwigRendererTest.php +68 -0
  218. data/vendor/mthaml/mthaml/test/MtHaml/Tests/NodeVisitorsTest.php +44 -0
  219. data/vendor/mthaml/mthaml/test/MtHaml/Tests/Parser/BufferTest.php +77 -0
  220. data/vendor/mthaml/mthaml/test/MtHaml/Tests/ParserTest.php +47 -0
  221. data/vendor/mthaml/mthaml/test/MtHaml/Tests/RuntimeTest.php +356 -0
  222. data/vendor/mthaml/mthaml/test/MtHaml/Tests/Support/Php/ExecutorTest.php +83 -0
  223. data/vendor/mthaml/mthaml/test/MtHaml/Tests/Support/Twig/LoaderTest.php +65 -0
  224. data/vendor/mthaml/mthaml/test/MtHaml/Tests/TestCase.php +49 -0
  225. data/vendor/mthaml/mthaml/test/MtHaml/Tests/TestCaseTest.php +50 -0
  226. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/Support/Php/Executor.001.haml +1 -0
  227. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/environment/attr_list_php.test +20 -0
  228. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/environment/attr_list_twig.test +12 -0
  229. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/environment/boolean_attr_php.test +16 -0
  230. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/environment/boolean_attr_twig.test +16 -0
  231. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/environment/bug28_php.test +15 -0
  232. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/environment/bug28_twig.test +15 -0
  233. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/environment/bug42.test +13 -0
  234. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/environment/bug8_twig.test +10 -0
  235. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/environment/coffeescript_filter.test +31 -0
  236. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/environment/comments.test +26 -0
  237. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/environment/cond_cmt.test +25 -0
  238. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/environment/doctype.test +18 -0
  239. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/environment/doctype_html4.test +20 -0
  240. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/environment/doctype_invalid.test +12 -0
  241. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/environment/doctype_invalid_xhtml.test +12 -0
  242. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/environment/doctype_php.test +18 -0
  243. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/environment/doctype_xhtml.test +30 -0
  244. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/environment/filters.test +51 -0
  245. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/environment/insert_non_echo_php.test +11 -0
  246. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/environment/insert_non_echo_twig.test +11 -0
  247. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/environment/interpolation_in_html_attrs_php.test +31 -0
  248. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/environment/interpolation_in_html_attrs_twig.test +31 -0
  249. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/environment/less_filter_leafo.test +33 -0
  250. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/environment/less_filter_oyejorge.test +49 -0
  251. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/environment/markdown_filter_cebemarkdown.test +35 -0
  252. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/environment/markdown_filter_ciconia.test +36 -0
  253. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/environment/markdown_filter_michelf.test +34 -0
  254. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/environment/markdown_filter_parsedown.test +31 -0
  255. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/environment/markdown_optimization_filter_michelf.test +23 -0
  256. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/environment/mergeattrs.test +18 -0
  257. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/environment/nuke_inner_whitespace.test +77 -0
  258. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/environment/nuke_outer_whitespace.test +122 -0
  259. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/environment/object_ref_php.test +14 -0
  260. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/environment/object_ref_twig.test +14 -0
  261. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/environment/php.test +109 -0
  262. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/environment/php_autoescaping.test +22 -0
  263. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/environment/php_autoescaping_once.test +25 -0
  264. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/environment/php_blocks.test +29 -0
  265. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/environment/php_filters.test +42 -0
  266. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/environment/scss_filter.test +32 -0
  267. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/environment/strip_inline_comments_php.test +22 -0
  268. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/environment/test.test +24 -0
  269. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/environment/trailing_semicolon_php.test +14 -0
  270. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/environment/try_catch_php.test +17 -0
  271. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/environment/twig.test +112 -0
  272. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/environment/twig_blocks.test +29 -0
  273. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/environment/twig_filters.test +37 -0
  274. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/environment/twig_whitespace.test +32 -0
  275. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/environment/whitespace.test +63 -0
  276. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/nodevisitors/autoclose.test +30 -0
  277. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/nodevisitors/escaping.test +52 -0
  278. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/nodevisitors/escaping_attr_once.test +52 -0
  279. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/nodevisitors/escaping_html_false.test +52 -0
  280. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/nodevisitors/mergeattrs.test +26 -0
  281. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/nodevisitors/midblock.test +54 -0
  282. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/nodevisitors/midblock_002.test +32 -0
  283. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/parser/attr_list.test +14 -0
  284. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/parser/attrs.test +42 -0
  285. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/parser/attrs_002.test +35 -0
  286. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/parser/attrs_003.test +30 -0
  287. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/parser/attrs_html_linebreak.test +17 -0
  288. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/parser/blocks.test +27 -0
  289. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/parser/blocks_002.test +15 -0
  290. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/parser/boolean_attr.test +19 -0
  291. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/parser/bug28.test +15 -0
  292. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/parser/bug8.test +11 -0
  293. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/parser/cond_cmt.test +23 -0
  294. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/parser/doctype.test +11 -0
  295. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/parser/double_equal.test +7 -0
  296. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/parser/empty_line_after_multiline.test +10 -0
  297. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/parser/errors_001.test +8 -0
  298. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/parser/errors_002.test +8 -0
  299. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/parser/errors_003.test +8 -0
  300. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/parser/errors_004.test +6 -0
  301. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/parser/errors_005.test +5 -0
  302. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/parser/errors_006.test +7 -0
  303. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/parser/errors_007.test +7 -0
  304. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/parser/errors_008.test +7 -0
  305. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/parser/errors_009.test +5 -0
  306. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/parser/errors_010.test +5 -0
  307. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/parser/errors_013.test +5 -0
  308. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/parser/errors_016.test +7 -0
  309. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/parser/errors_017.test +8 -0
  310. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/parser/errors_018.test +6 -0
  311. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/parser/errors_019.test +6 -0
  312. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/parser/errors_020.test +5 -0
  313. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/parser/filters.test +20 -0
  314. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/parser/filters_002.test +19 -0
  315. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/parser/filters_003.test +13 -0
  316. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/parser/filters_004.test +21 -0
  317. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/parser/filters_005.test +22 -0
  318. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/parser/filters_006.test +23 -0
  319. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/parser/insertflags.test +17 -0
  320. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/parser/interpolation.test +36 -0
  321. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/parser/interpolation_in_html_attrs.test +17 -0
  322. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/parser/multiline.test +18 -0
  323. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/parser/multiline_code.test +59 -0
  324. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/parser/multiple_attr_kinds.test +47 -0
  325. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/parser/non_rendered_comment.test +31 -0
  326. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/parser/ns.test +11 -0
  327. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/parser/object_ref.test +22 -0
  328. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/parser/object_ref_error1.test +5 -0
  329. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/parser/object_ref_error2.test +5 -0
  330. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/parser/quotes_in_haml.test +10 -0
  331. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/parser/ruby19_attrs.test +11 -0
  332. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/parser/ruby_attrs_comma.test +23 -0
  333. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/parser/ruby_attrs_comma_errors_001.test +5 -0
  334. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/parser/ruby_attrs_comma_errors_002.test +5 -0
  335. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/parser/ruby_attrs_comma_errors_003.test +5 -0
  336. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/parser/standard.test +114 -0
  337. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/parser/tagflags.test +39 -0
  338. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/runtime/php_filters.test +28 -0
  339. data/vendor/mthaml/mthaml/test/MtHaml/Tests/fixtures/runtime/twig_filters.test +31 -0
  340. data/vendor/mthaml/mthaml/test/bootstrap.php +3 -0
  341. metadata +398 -0
@@ -0,0 +1,252 @@
1
+ <?php
2
+
3
+ namespace MtHaml\NodeVisitor;
4
+
5
+ use MtHaml\Node\Filter;
6
+ use MtHaml\Node\Insert;
7
+ use MtHaml\Node\Run;
8
+ use MtHaml\Node\InterpolatedString;
9
+ use MtHaml\Node\Tag;
10
+ use MtHaml\Node\ObjectRefClass;
11
+ use MtHaml\Node\ObjectRefId;
12
+ use MtHaml\Node\NodeAbstract;
13
+ use MtHaml\Node\TagAttributeInterpolation;
14
+ use MtHaml\Node\TagAttributeList;
15
+
16
+ class TwigRenderer extends RendererAbstract
17
+ {
18
+ protected function escapeLanguage($string, $context)
19
+ {
20
+ // If there is a '%' or '{' at the begining of the string, it could
21
+ // become '{%' or '{{' when concatenated with previous output. So we
22
+ // need to escape '{' and '%' when appearing at the begining of the
23
+ // string, unless we know that previous output doesn't end with '{'.
24
+ $re = '~(^[{%][{%]?|\{[{%])~';
25
+
26
+ // when context is empty, consider that we don't know what's before
27
+ if (0 < strlen($context)) {
28
+ $len = strlen($context);
29
+ $char = $context[$len-1];
30
+ if ('{' !== $char) {
31
+ $re = '~(\{[{%])~';
32
+ }
33
+ }
34
+
35
+ return preg_replace($re, "{{ '\\1' }}", $string);
36
+ }
37
+
38
+ protected function stringLiteral($string)
39
+ {
40
+ return var_export((string) $string, true);
41
+ }
42
+
43
+ public function enterInterpolatedString(InterpolatedString $node)
44
+ {
45
+ if (!$this->isEchoMode() && 1 < count($node->getChilds())) {
46
+ $this->raw('(');
47
+ }
48
+ }
49
+
50
+ public function betweenInterpolatedStringChilds(InterpolatedString $node)
51
+ {
52
+ if (!$this->isEchoMode()) {
53
+ $this->raw(' ~ ');
54
+ }
55
+ }
56
+
57
+ public function leaveInterpolatedString(InterpolatedString $node)
58
+ {
59
+ if (!$this->isEchoMode() && 1 < count($node->getChilds())) {
60
+ $this->raw(')');
61
+ }
62
+ }
63
+
64
+ public function enterInsert(Insert $node)
65
+ {
66
+ if ($this->isEchoMode()) {
67
+ $escaping = $node->getEscaping()->isEnabled();
68
+ if (true === $escaping) {
69
+ $fmt = '{{ (%s)|escape }}';
70
+ } elseif (false === $escaping) {
71
+ $fmt = '{{ (%s)|raw }}';
72
+ } else {
73
+ $fmt = '{{ %s }}';
74
+ }
75
+ $this->addDebugInfos($node);
76
+ $this->raw(sprintf($fmt, $node->getContent()));
77
+ } else {
78
+ $content = $node->getContent();
79
+ if (!preg_match('~^[a-zA-Z0-9_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$~', $content)) {
80
+ $this->raw('(' . $node->getContent() . ')');
81
+ } else {
82
+ $this->raw($node->getContent());
83
+ }
84
+ }
85
+ }
86
+
87
+ public function enterTopblock(Run $node)
88
+ {
89
+ $this->renderBlockTop($node);
90
+ }
91
+
92
+ public function enterMidblock(Run $node)
93
+ {
94
+ $this->renderBlockTop($node);
95
+ }
96
+
97
+ public function leaveTopBlock(Run $node)
98
+ {
99
+ if ($node->isBlock()) {
100
+ if (preg_match('~^(?:-\s*)?(\w+)~', $node->getContent(), $match)) {
101
+ $this->write($this->renderTag('end'.$match[1]));
102
+ }
103
+ }
104
+ }
105
+
106
+ protected function renderBlockTop(Run $node)
107
+ {
108
+ $this->addDebugInfos($node);
109
+ $this->write($this->renderTag($node->getContent()));
110
+ }
111
+
112
+ public function enterObjectRefClass(ObjectRefClass $node)
113
+ {
114
+ if ($this->isEchoMode()) {
115
+ $this->raw('{{ ');
116
+ }
117
+ $this->raw('mthaml_object_ref_class(');
118
+
119
+ $this->pushEchoMode(false);
120
+ }
121
+
122
+ public function leaveObjectRefClass(ObjectRefClass $node)
123
+ {
124
+ $this->raw(')');
125
+
126
+ $this->popEchoMode(true);
127
+ if ($this->isEchoMode()) {
128
+ $this->raw(' }}');
129
+ }
130
+ }
131
+
132
+ public function enterObjectRefId(ObjectRefId $node)
133
+ {
134
+ if ($this->isEchoMode()) {
135
+ $this->raw('{{ ');
136
+ }
137
+ $this->raw('mthaml_object_ref_id(');
138
+
139
+ $this->pushEchoMode(false);
140
+ }
141
+
142
+ public function leaveObjectRefId(ObjectRefId $node)
143
+ {
144
+ $this->raw(')');
145
+
146
+ $this->popEchoMode(true);
147
+ if ($this->isEchoMode()) {
148
+ $this->raw(' }}');
149
+ }
150
+ }
151
+
152
+ public function enterObjectRefPrefix(NodeAbstract $node)
153
+ {
154
+ $this->raw(', ');
155
+ }
156
+
157
+ public function enterFilter(Filter $node)
158
+ {
159
+ $filter = $this->env->getFilter($node->getFilter());
160
+
161
+ if (!$filter->isOptimizable($this, $node, $this->env->getOptions())) {
162
+ $this->write('{% filter mthaml_'.$node->getFilter().' %}', true, false);
163
+ $this->savedIndent[] = $this->indent;
164
+ $this->indent = 0;
165
+ }
166
+ }
167
+
168
+ public function leaveFilter(Filter $node)
169
+ {
170
+ $filter = $this->env->getFilter($node->getFilter());
171
+
172
+ if (!$filter->isOptimizable($this, $node, $this->env->getOptions())) {
173
+ $this->write('{% endfilter %}');
174
+ $this->indent = $this->popSavedIndent();
175
+ }
176
+ }
177
+
178
+ protected function renderTag($content)
179
+ {
180
+ $prefix = ' ';
181
+ $suffix = ' ';
182
+
183
+ if (preg_match('/^-/', $content)) {
184
+ $prefix = '';
185
+ }
186
+ if (preg_match('/-$/', $content)) {
187
+ $suffix = '';
188
+ }
189
+
190
+ return sprintf('{%%%s%s%s%%}', $prefix, $content, $suffix);
191
+ }
192
+
193
+ protected function writeDebugInfos($lineno)
194
+ {
195
+ $infos = sprintf('{%% line %d %%}', $lineno);
196
+ $this->raw($infos);
197
+ }
198
+
199
+ protected function renderDynamicAttributes(Tag $tag)
200
+ {
201
+ $this->raw(' ');
202
+
203
+ foreach ($tag->getAttributes() as $attr) {
204
+ $this->addDebugInfos($attr);
205
+ break;
206
+ }
207
+
208
+ $this->raw('{{ mthaml_attributes([');
209
+
210
+ $this->setEchoMode(false);
211
+
212
+ foreach (array_values($tag->getAttributes()) as $i => $attr) {
213
+
214
+ if (0 !== $i) {
215
+ $this->raw(', ');
216
+ }
217
+
218
+ if ($attr instanceof TagAttributeInterpolation) {
219
+ $this->raw('mthaml_attribute_interpolation(');
220
+ $attr->getValue()->accept($this);
221
+ $this->raw(')');
222
+ } elseif ($attr instanceof TagAttributeList) {
223
+ $this->raw('mthaml_attribute_list(');
224
+ $attr->getValue()->accept($this);
225
+ $this->raw(')');
226
+ } else {
227
+ $this->raw('[');
228
+ $attr->getName()->accept($this);
229
+ $this->raw(', ');
230
+ if ($attr->getValue()) {
231
+ $attr->getValue()->accept($this);
232
+ } else {
233
+ $this->raw('true');
234
+ }
235
+ $this->raw(']');
236
+ }
237
+ }
238
+
239
+ $this->raw(']');
240
+
241
+ $this->setEchoMode(true);
242
+
243
+ $this->raw(', ');
244
+ $this->raw($this->stringLiteral($this->env->getOption('format')));
245
+ $this->raw(', ');
246
+ $this->raw($this->stringLiteral($this->charset));
247
+ $this->raw( ($this->env->getOption('enable_escaper') && $this->env->getOption('escape_attrs'))?
248
+ '' : ', false');
249
+
250
+ $this->raw(')|raw }}');
251
+ }
252
+ }
@@ -0,0 +1,862 @@
1
+ <?php
2
+
3
+ namespace MtHaml;
4
+
5
+ use MtHaml\Exception\SyntaxErrorException;
6
+ use MtHaml\Node\NodeAbstract;
7
+ use MtHaml\Parser\Buffer;
8
+ use MtHaml\Node\Doctype;
9
+ use MtHaml\Node\Tag;
10
+ use MtHaml\Node\TagAttribute;
11
+ use MtHaml\Node\Comment;
12
+ use MtHaml\Node\Insert;
13
+ use MtHaml\Node\Text;
14
+ use MtHaml\Node\InterpolatedString;
15
+ use MtHaml\Node\Run;
16
+ use MtHaml\Node\Statement;
17
+ use MtHaml\Node\Filter;
18
+ use MtHaml\Node\ObjectRefClass;
19
+ use MtHaml\Node\ObjectRefId;
20
+ use MtHaml\Node\TagAttributeInterpolation;
21
+ use MtHaml\Node\TagAttributeList;
22
+ use MtHaml\Indentation\IndentationException;
23
+ use MtHaml\TreeBuilder;
24
+
25
+ /**
26
+ * MtHaml Parser
27
+ */
28
+ class Parser
29
+ {
30
+ protected $filename;
31
+ protected $column;
32
+ protected $lineno;
33
+
34
+ /**
35
+ * @var \MtHaml\Indentation\IndentationInterface
36
+ */
37
+ private $prevIndent;
38
+
39
+ /**
40
+ * @var \MtHaml\Indentation\IndentationInterface
41
+ */
42
+ private $indent;
43
+
44
+ /**
45
+ * @var \MtHaml\TreeBuilder
46
+ */
47
+ private $treeBuilder;
48
+
49
+ public function __construct()
50
+ {
51
+ $this->treeBuilder = new TreeBuilder;
52
+ $this->indent = new Indentation\Undefined();
53
+ $this->prevIndent = $this->indent;
54
+ }
55
+
56
+ /**
57
+ * Updates the indentation state
58
+ *
59
+ * @param Buffer $buf
60
+ * @param string $indent The indentation characters of the current line
61
+ */
62
+ private function updateIndent(Buffer $buf, $indent)
63
+ {
64
+ $this->prevIndent = $this->indent;
65
+
66
+ try {
67
+ $this->indent = $this->indent->newLevel($indent);
68
+ } catch (IndentationException $e) {
69
+ throw $this->syntaxError($buf, $e->getMessage());
70
+ }
71
+
72
+ if (!$this->treeBuilder->hasStatements() && 0 < $this->indent->getLevel()) {
73
+ throw $this->syntaxError($buf, 'Indenting at the beginning of the document is illegal');
74
+ }
75
+ }
76
+
77
+ /**
78
+ * Processes a statement
79
+ *
80
+ * Inserts a new $node in the tree
81
+ *
82
+ * @param Buffer $buf
83
+ * @param NodeAbstract $node Node to insert in the tree
84
+ */
85
+ public function processStatement(Buffer $buf, NodeAbstract $node)
86
+ {
87
+ $level = $this->indent->getLevel() - $this->prevIndent->getLevel();
88
+
89
+ try {
90
+ $this->treeBuilder->addChild($level, $node);
91
+ } catch(TreeBuilderException $e) {
92
+ throw $this->syntaxError($buf, $e->getMessage());
93
+ }
94
+ }
95
+
96
+ /**
97
+ * Parses a HAML document
98
+ *
99
+ * @param string $string A HAML document
100
+ * @param string $fileaname Filename to report in error messages
101
+ * @param string $lineno Line number of the first line of $string in
102
+ * $filename (for error messages)
103
+ */
104
+ public function parse($string, $filename, $lineno = 1)
105
+ {
106
+ $this->filename = $filename;
107
+
108
+ $buf = new Buffer($string, $lineno);
109
+ while ($buf->nextLine()) {
110
+ $this->handleMultiline($buf);
111
+ $this->parseLine($buf);
112
+ }
113
+
114
+ return $this->treeBuilder->getRoot();
115
+ }
116
+
117
+ /**
118
+ * Handles HAML multiline syntax
119
+ *
120
+ * Any line terminated by ` |` is concatenated with the following lines
121
+ * also terminated by ` |`. Empty or whitespace-only lines are ignored. The
122
+ * current line is replaced by the resulting line in $buf.
123
+ *
124
+ * @param Buffer $buf
125
+ */
126
+ public function handleMultiline(Buffer $buf)
127
+ {
128
+ $line = $buf->getLine();
129
+
130
+ if (!$this->isMultiline($line)) {
131
+ return;
132
+ }
133
+
134
+ $line = substr(rtrim($line), 0, -1);
135
+
136
+ while ($next = $buf->peekLine()) {
137
+ if (trim($next) == '') {
138
+ $buf->nextLine();
139
+ continue;
140
+ }
141
+ if (!$this->isMultiline($next)) break;
142
+ $line .= substr(trim($next), 0, -1);
143
+ $buf->nextLine();
144
+ }
145
+
146
+ $buf->replaceLine($line);
147
+ }
148
+
149
+ public function isMultiline($string)
150
+ {
151
+ return ' |' === substr(rtrim($string), -2);
152
+ }
153
+
154
+ /**
155
+ * Parses a HAML line
156
+ */
157
+ protected function parseLine(Buffer $buf)
158
+ {
159
+ if ('' === trim($buf->getLine())) {
160
+ return;
161
+ }
162
+
163
+ $buf->match('/[ \t]*/A', $match);
164
+ $indent = $match[0];
165
+ $this->updateIndent($buf, $indent);
166
+
167
+ if (null === $node = $this->parseStatement($buf)) {
168
+ throw $this->syntaxErrorExpected($buf, 'statement');
169
+ }
170
+ $this->processStatement($buf, $node);
171
+ }
172
+
173
+ protected function parseStatement(Buffer $buf)
174
+ {
175
+ if (null !== $node = $this->parseTag($buf)) {
176
+ return $node;
177
+
178
+ } elseif (null !== $node = $this->parseFilter($buf)) {
179
+ return $node;
180
+
181
+ } elseif (null !== $comment = $this->parseComment($buf)) {
182
+ return $comment;
183
+
184
+ } else if (null !== $run = $this->parseRun($buf)) {
185
+ return $run;
186
+
187
+ } elseif (null !== $doctype = $this->parseDoctype($buf)) {
188
+ return $doctype;
189
+
190
+ } else {
191
+ if (null !== $node = $this->parseNestableStatement($buf)) {
192
+ return new Statement($node->getPosition(), $node);
193
+ }
194
+ }
195
+ }
196
+
197
+ protected function parseDoctype(Buffer $buf)
198
+ {
199
+ $doctypeRegex = '/
200
+ !!! # start of doctype decl
201
+ (?:
202
+ \s(?P<type>[^\s]+) # optional doctype id
203
+ (?:\s(?P<options>.*))? # doctype options (e.g. charset, for
204
+ # xml decls)
205
+ )?$/Ax';
206
+
207
+ if ($buf->match($doctypeRegex, $match)) {
208
+
209
+ $type = empty($match['type']) ? null : $match['type'];
210
+ $options = empty($match['options']) ? null : $match['options'];
211
+ $node = new Doctype($match['pos'][0], $type, $options);
212
+
213
+ return $node;
214
+ }
215
+ }
216
+
217
+ protected function parseComment(Buffer $buf)
218
+ {
219
+ if ($buf->match('!(-#|/)\s*!A', $match)) {
220
+ $pos = $match['pos'][0];
221
+ $rendered = '/' === $match[1];
222
+ $condition = null;
223
+
224
+ if ($rendered) {
225
+ // IE conditional comments
226
+ // example: [if IE lte 8]
227
+ //
228
+ // matches nested [...]
229
+ if ($buf->match('!(\[ ( [^\[\]]+ | (?1) )+ \])$!Ax', $match)) {
230
+ $condition = $match[0];
231
+ }
232
+ }
233
+
234
+ $node = new Comment($pos, $rendered, $condition);
235
+
236
+ if ('' !== $line = trim($buf->getLine())) {
237
+ $content = new Text($buf->getPosition(), $line);
238
+ $node->setContent($content);
239
+ }
240
+
241
+ if (!$rendered) {
242
+
243
+ while (null !== $next = $buf->peekLine()) {
244
+
245
+ $indent = '';
246
+
247
+ if ('' !== trim($next)) {
248
+ $indent = $this->indent->getString(1, $next);
249
+ if ('' === $indent) {
250
+ break;
251
+ }
252
+ if (strpos($next, $indent) !== 0) {
253
+ break;
254
+ }
255
+ }
256
+
257
+ $buf->nextLine();
258
+
259
+ if ('' !== trim($next)) {
260
+ $buf->eatChars(strlen($indent));
261
+ $str = new Text($buf->getPosition(), $buf->getLine());
262
+ $node->addChild(new Statement($str->getPosition(), $str));
263
+ }
264
+ }
265
+ }
266
+
267
+ return $node;
268
+ }
269
+ }
270
+
271
+ protected function getMultilineCode(Buffer $buf)
272
+ {
273
+ $code = $buf->getLine();
274
+ while (preg_match('/,\s*$/', $code)) {
275
+ $buf->nextLine();
276
+ $line = trim($buf->getLine());
277
+ if ('' !== $line) {
278
+ $code .= ' ' . $line;
279
+ }
280
+ }
281
+ return $code;
282
+ }
283
+
284
+ protected function parseRun(Buffer $buf)
285
+ {
286
+ if ($buf->match('/-(?!#)/A', $match)) {
287
+ $buf->skipWs();
288
+ $code = $this->getMultilineCode($buf);
289
+ return new Run($match['pos'][0], $code);
290
+ }
291
+ }
292
+
293
+ protected function parseTag(Buffer $buf)
294
+ {
295
+ $tagRegex = '/
296
+ %(?P<tag_name>[\w:-]+) # explicit tag name ( %tagname )
297
+ | (?=[.#][\w-]) # implicit div followed by class or id
298
+ # ( .class or #id )
299
+ /xA';
300
+
301
+ if ($buf->match($tagRegex, $match)) {
302
+ $tag_name = empty($match['tag_name']) ? 'div' : $match['tag_name'];
303
+
304
+ $attributes = $this->parseTagAttributes($buf);
305
+
306
+ $flags = $this->parseTagFlags($buf);
307
+
308
+ $node = new Tag($match['pos'][0], $tag_name, $attributes, $flags);
309
+
310
+ $buf->skipWs();
311
+
312
+ if (null !== $nested = $this->parseNestableStatement($buf)) {
313
+
314
+ if ($flags & Tag::FLAG_SELF_CLOSE) {
315
+ $msg = 'Illegal nesting: nesting within a self-closing tag is illegal';
316
+ throw $this->syntaxError($buf, $msg);
317
+ }
318
+
319
+ $node->setContent($nested);
320
+ }
321
+
322
+ return $node;
323
+ }
324
+ }
325
+
326
+ protected function parseTagFlags(Buffer $buf)
327
+ {
328
+ $flags = 0;
329
+ while (null !== $char = $buf->peekChar()) {
330
+ switch ($char) {
331
+ case '<':
332
+ $flags |= Tag::FLAG_REMOVE_INNER_WHITESPACES;
333
+ $buf->eatChar();
334
+ break;
335
+ case '>':
336
+ $flags |= Tag::FLAG_REMOVE_OUTER_WHITESPACES;
337
+ $buf->eatChar();
338
+ break;
339
+ case '/':
340
+ $flags |= Tag::FLAG_SELF_CLOSE;
341
+ $buf->eatChar();
342
+ break;
343
+ default:
344
+ break 2;
345
+ }
346
+ }
347
+
348
+ return $flags;
349
+ }
350
+
351
+ protected function parseTagAttributes(Buffer $buf)
352
+ {
353
+ $attrs = array();
354
+
355
+ // short notation for classes and ids
356
+
357
+ while ($buf->match('/(?P<type>[#.])(?P<name>[\w-]+)/A', $match)) {
358
+ if ($match['type'] == '#') {
359
+ $name = 'id';
360
+ } else {
361
+ $name = 'class';
362
+ }
363
+ $name = new Text($match['pos'][0], $name);
364
+ $value = new Text($match['pos'][1], $match['name']);
365
+ $attr = new TagAttribute($match['pos'][0], $name, $value);
366
+ $attrs[] = $attr;
367
+ }
368
+
369
+ $hasRubyAttrs = false;
370
+ $hasHtmlAttrs = false;
371
+ $hasObjectRef = false;
372
+
373
+ // accept ruby-attrs, html-attrs, and object-ref in any order,
374
+ // but only one of each
375
+
376
+ while (true) {
377
+ switch ($buf->peekChar()) {
378
+ case '{':
379
+ if ($hasRubyAttrs) {
380
+ break 2;
381
+ }
382
+ $hasRubyAttrs = true;
383
+ $newAttrs = $this->parseTagAttributesRuby($buf);
384
+ $attrs = array_merge($attrs, $newAttrs);
385
+ break;
386
+ case '(':
387
+ if ($hasHtmlAttrs) {
388
+ break 2;
389
+ }
390
+ $hasHtmlAttrs = true;
391
+ $newAttrs = $this->parseTagAttributesHtml($buf);
392
+ $attrs = array_merge($attrs, $newAttrs);
393
+ break;
394
+ case '[':
395
+ if ($hasObjectRef) {
396
+ break 2;
397
+ }
398
+ $hasObjectRef = true;
399
+ $newAttrs = $this->parseTagAttributesObject($buf);
400
+ $attrs = array_merge($attrs, $newAttrs);
401
+ break;
402
+ default:
403
+ break 2;
404
+ }
405
+ }
406
+
407
+ return $attrs;
408
+ }
409
+
410
+ protected function parseTagAttributesRuby(Buffer $buf)
411
+ {
412
+ $attrs = array();
413
+
414
+ if ($buf->match('/\{\s*/')) {
415
+ do {
416
+ $attrs[] = $this->parseTagAttributeRuby($buf);
417
+
418
+ $buf->skipWs();
419
+
420
+ if ($buf->match('/}/A')) {
421
+ break;
422
+ }
423
+
424
+ $buf->skipWs();
425
+ if (!$buf->match('/,\s*/A')) {
426
+ throw $this->syntaxErrorExpected($buf, "',' or '}'");
427
+ }
428
+ // allow line break after comma
429
+ if ($buf->isEol()) {
430
+ $buf->nextLine();
431
+ $buf->skipWs();
432
+ }
433
+ } while (true);
434
+ }
435
+
436
+ return $attrs;
437
+ }
438
+
439
+ protected function parseTagAttributeRuby(Buffer $buf)
440
+ {
441
+ if ($expr = $this->parseInterpolation($buf)) {
442
+ return new TagAttributeInterpolation($expr->getPosition(), $expr);
443
+ }
444
+
445
+ list ($name, $ruby19) = $this->parseTagAttributeNameRuby($buf);
446
+
447
+ $buf->skipWs();
448
+
449
+ if (!$ruby19 && !$buf->match('/=>\s*/A')) {
450
+ return new TagAttributeList($name->getPosition(), $name);
451
+ }
452
+
453
+ $value = $this->parseTagAttributeValueRuby($buf);
454
+
455
+ return new TagAttribute($name->getPosition(), $name, $value);
456
+ }
457
+
458
+ protected function parseTagAttributeNameRuby(Buffer $buf)
459
+ {
460
+ try {
461
+ if ($name = $this->parseTagAttributeNameRuby19($buf)) {
462
+ return array($name, true);
463
+ }
464
+
465
+ return array($this->parseAttrExpression($buf, '=,'), false);
466
+ } catch (SyntaxErrorException $e) {
467
+ // Allow line break after comma
468
+ if ($buf->match('/,\s*$/', $match, false) && $buf->hasNextLine()) {
469
+ $buf->mergeNextLine();
470
+ return $this->parseTagAttributeNameRuby($buf);
471
+ } else {
472
+ throw $e;
473
+ }
474
+ }
475
+ }
476
+
477
+ protected function parseTagAttributeNameRuby19(Buffer $buf)
478
+ {
479
+ if ($buf->match('/(\w+):/A', $match)) {
480
+ return new Text($match['pos'][0], $match[1]);
481
+ }
482
+ }
483
+
484
+ protected function parseTagAttributeValueRuby(Buffer $buf)
485
+ {
486
+ try {
487
+ return $this->parseAttrExpression($buf, ',');
488
+ } catch (SyntaxErrorException $e) {
489
+ // Allow line break after comma
490
+ if ($buf->match('/,\s*$/', $match, false) && $buf->hasNextLine()) {
491
+ $buf->mergeNextLine();
492
+ return $this->parseTagAttributeValueRuby($buf);
493
+ } else {
494
+ throw $e;
495
+ }
496
+ }
497
+ }
498
+
499
+ protected function parseTagAttributesHtml(Buffer $buf)
500
+ {
501
+ if (!$buf->match('/\(\s*/A')) {
502
+ return null;
503
+ }
504
+
505
+ $attrs = array();
506
+
507
+ do {
508
+
509
+ $attrs[] = $this->parseTagAttributeHtml($buf);
510
+
511
+ if ($buf->match('/\s*\)/A')) {
512
+ break;
513
+ }
514
+
515
+ if (!$buf->match('/\s+/A')) {
516
+ if (!$buf->isEol()) {
517
+ throw $this->syntaxErrorExpected($buf, "' ', ')' or end of line");
518
+ }
519
+ }
520
+
521
+ // allow line break
522
+ if ($buf->isEol()) {
523
+ $buf->nextLine();
524
+ $buf->skipWs();
525
+ }
526
+
527
+ } while (true);
528
+
529
+ return $attrs;
530
+ }
531
+
532
+ private function parseTagAttributeHtml(Buffer $buf)
533
+ {
534
+ if ($expr = $this->parseInterpolation($buf)) {
535
+ return new TagAttributeInterpolation($expr->getPosition(), $expr);
536
+ }
537
+
538
+ if ($buf->match('/[\w+:-]+/A', $match)) {
539
+ $name = new Text($match['pos'][0], $match[0]);
540
+
541
+ if (!$buf->match('/\s*=\s*/A')) {
542
+ $value = null;
543
+ } else {
544
+ $value = $this->parseAttrExpression($buf, ' ');
545
+ }
546
+
547
+ return new TagAttribute($name->getPosition(), $name, $value);
548
+ }
549
+
550
+ throw $this->syntaxErrorExpected($buf, 'html attribute name or #{interpolation}');
551
+ }
552
+
553
+ protected function parseTagAttributesObject(Buffer $buf)
554
+ {
555
+ $nodes = array();
556
+ $attrs = array();
557
+
558
+ if (!$buf->match('/\[\s*/A', $match)) {
559
+ return $attrs;
560
+ }
561
+
562
+ $pos = $match['pos'][0];
563
+
564
+ do {
565
+ if ($buf->match('/\s*\]\s*/A')) {
566
+ break;
567
+ }
568
+
569
+ list($expr, $pos) = $this->parseExpression($buf, ',\\]');
570
+ $nodes[] = new Insert($pos, $expr);
571
+
572
+ if ($buf->match('/\s*\]\s*/A')) {
573
+ break;
574
+ } elseif (!$buf->match('/\s*,\s*/A')) {
575
+ throw $this->syntaxErrorExpected($buf, "',' or ']'");
576
+ }
577
+
578
+ } while (true);
579
+
580
+ list ($object, $prefix) = array_pad($nodes, 2, null);
581
+
582
+ if (!$object) {
583
+ return $attrs;
584
+ }
585
+
586
+ $class = new ObjectRefClass($pos, $object, $prefix);
587
+ $id = new ObjectRefId($pos, $object, $prefix);
588
+
589
+ $name = new Text($pos, 'class');
590
+ $attrs[] = new TagAttribute($pos, $name, $class);
591
+
592
+ $name = new Text($pos, 'id');
593
+ $attrs[] = new TagAttribute($pos, $name, $id);
594
+
595
+ return $attrs;
596
+ }
597
+
598
+ protected function parseAttrExpression(Buffer $buf, $delims)
599
+ {
600
+ $sub = clone $buf;
601
+
602
+ list($expr, $pos) = $this->parseExpression($buf, $delims);
603
+
604
+ // hack to return a parsed string or symbol instead of an expression
605
+ // if the whole expression can be parsed as string or symbol.
606
+
607
+ if (preg_match('/"/A', $expr)) {
608
+ try {
609
+ $string = $this->parseInterpolatedString($sub);
610
+ if ($sub->getColumn() >= $buf->getColumn()) {
611
+ $buf->eatChars($sub->getColumn() - $buf->getColumn());
612
+
613
+ return $string;
614
+ }
615
+ } catch (SyntaxErrorException $e) {
616
+ }
617
+ } elseif (preg_match('/:/A', $expr)) {
618
+ try {
619
+ $sym = $this->parseSymbol($sub);
620
+ if ($sub->getColumn() >= $buf->getColumn()) {
621
+ $buf->eatChars($sub->getColumn() - $buf->getColumn());
622
+
623
+ return $sym;
624
+ }
625
+ } catch (SyntaxErrorException $e) {
626
+ }
627
+ }
628
+
629
+ return new Insert($pos, $expr);
630
+ }
631
+
632
+ protected function parseExpression(Buffer $buf, $delims)
633
+ {
634
+ // matches everything until a delimiter is found
635
+ // delimiters are allowed inside quoted strings,
636
+ // {}, and () (recursive)
637
+
638
+ $re = "/(?P<expr>(?:
639
+
640
+ # anything except \", ', (), {}, []
641
+ (?:[^(){}\[\]\"\'\\\\$delims]+(?=(?P>expr)))
642
+ |(?:[^(){}\[\]\"\'\\\\ $delims]+)
643
+
644
+ # double quoted string
645
+ | \"(?: [^\"\\\\]+ | \\\\[\#\"\\\\] )*\"
646
+
647
+ # single quoted string
648
+ | '(?: [^'\\\\]+ | \\\\[\#'\\\\] )*'
649
+
650
+ # { ... } pair
651
+ | \{ (?: (?P>expr) | [ $delims] )* \}
652
+
653
+ # ( ... ) pair
654
+ | \( (?: (?P>expr) | [ $delims] )* \)
655
+
656
+ # [ ... ] pair
657
+ | \[ (?: (?P>expr) | [ $delims] )* \]
658
+ )+)/xA";
659
+
660
+ if ($buf->match($re, $match)) {
661
+ return array($match[0], $match['pos'][0]);
662
+ }
663
+
664
+ throw $this->syntaxErrorExpected($buf, 'target language expression');
665
+ }
666
+
667
+ protected function parseSymbol(Buffer $buf)
668
+ {
669
+ if (!$buf->match('/:(\w+)/A', $match)) {
670
+ throw $this->syntaxErrorExpected($buf, 'symbol');
671
+ }
672
+
673
+ return new Text($match['pos'][0], $match[1]);
674
+ }
675
+
676
+ protected function parseInterpolatedString(Buffer $buf, $quoted = true)
677
+ {
678
+ if ($quoted && !$buf->match('/"/A', $match)) {
679
+ throw $this->syntaxErrorExpected($buf, 'double quoted string');
680
+ }
681
+
682
+ $node = new InterpolatedString($buf->getPosition());
683
+
684
+ if ($quoted) {
685
+ $stringRegex = '/(
686
+ [^\#"\\\\]+ # anything without hash or " or \
687
+ |\\\\(?:["\\\\]|\#\{) # or escaped quote slash or hash followed by {
688
+ |\#(?!\{) # or hash, but not followed by {
689
+ )+/Ax';
690
+ } else {
691
+ $stringRegex = '/(
692
+ [^\#\\\\]+ # anything without hash or \
693
+ |\\\\(?:\#\{|[^\#]) # or escaped hash followed by { or anything without hash
694
+ |\#(?!\{) # or hash, but not followed by {
695
+ )+/Ax';
696
+ }
697
+
698
+ do {
699
+ if ($buf->match($stringRegex, $match)) {
700
+ $text = $match[0];
701
+ if ($quoted) {
702
+ // strip slashes
703
+ $text = preg_replace('/\\\\(["\\\\])/', '\\1', $match[0]);
704
+ }
705
+ // strip back slash before hash followed by {
706
+ $text = preg_replace('/\\\\\#\{/', '#{', $text);
707
+ $text = new Text($match['pos'][0], $text);
708
+ $node->addChild($text);
709
+ } elseif ($expr = $this->parseInterpolation($buf)) {
710
+ $node->addChild($expr);
711
+ } elseif ($quoted && $buf->match('/"/A')) {
712
+ break;
713
+ } elseif (!$quoted && $buf->match('/$/A')) {
714
+ break;
715
+ } else {
716
+ throw $this->syntaxErrorExpected($buf, 'string or #{...}');
717
+ }
718
+ } while (true);
719
+
720
+ // ensure that the InterpolatedString has at least one child
721
+ if (0 === count($node->getChilds())) {
722
+ $text = new Text($buf->getPosition(), '');
723
+ $node->addChild($text);
724
+ }
725
+
726
+ return $node;
727
+ }
728
+
729
+ protected function parseInterpolation(Buffer $buf)
730
+ {
731
+ // This matches an interpolation:
732
+ // #{ expr... }
733
+ $exprRegex = '/
734
+ \#\{(?P<insert>(?P<expr>
735
+ # do not allow {}"\' in expr
736
+ [^\{\}"\']+
737
+ # allow balanced {}
738
+ | \{ (?P>expr)* \}
739
+ # allow balanced \'
740
+ | \'([^\'\\\\]+|\\\\[\'\\\\])*\'
741
+ # allow balanced "
742
+ | "([^"\\\\]+|\\\\["\\\\])*"
743
+ )+)\}
744
+ /AxU';
745
+
746
+ if ($buf->match($exprRegex, $match)) {
747
+ return new Insert($match['pos']['insert'], $match['insert']);
748
+ }
749
+ }
750
+
751
+ protected function parseNestableStatement(Buffer $buf)
752
+ {
753
+ if ($insert = $this->parseInsert($buf)) {
754
+ return $insert;
755
+ }
756
+
757
+ if (null !== $comment = $this->parseComment($buf)) {
758
+ return $comment;
759
+ }
760
+
761
+ if ('\\' === $buf->peekChar()) {
762
+ $buf->eatChar();
763
+ }
764
+
765
+ if (strlen(trim($buf->getLine())) > 0) {
766
+ return $this->parseInterpolatedString($buf, false);
767
+ }
768
+ }
769
+
770
+ protected function parseInsert(Buffer $buf)
771
+ {
772
+ if ($buf->match('/([&!]?)(==?|~)\s*/A', $match)) {
773
+
774
+ if ($match[2] == '==') {
775
+ $node = $this->parseInterpolatedString($buf, false);
776
+ } else {
777
+ $code = $this->getMultilineCode($buf);
778
+ $node = new Insert($match['pos'][0], $code);
779
+ }
780
+
781
+ if ($match[1] == '&') {
782
+ $node->getEscaping()->setEnabled(true);
783
+ } elseif ($match[1] == '!') {
784
+ $node->getEscaping()->setEnabled(false);
785
+ }
786
+
787
+ $buf->skipWs();
788
+
789
+ return $node;
790
+ }
791
+ }
792
+
793
+ protected function parseFilter(Buffer $buf)
794
+ {
795
+ if (!$buf->match('/:(.*)/A', $match)) {
796
+ return null;
797
+ }
798
+
799
+ $node = new Filter($match['pos'][0], $match[1]);
800
+
801
+ while (null !== $next = $buf->peekLine()) {
802
+
803
+ $indent = '';
804
+
805
+ if ('' !== trim($next)) {
806
+ $indent = $this->indent->getString(1, $next);
807
+ if ('' === $indent) {
808
+ break;
809
+ }
810
+ if (strpos($next, $indent) !== 0) {
811
+ break;
812
+ }
813
+ }
814
+
815
+ $buf->nextLine();
816
+ $buf->eatChars(strlen($indent));
817
+ $str = $this->parseInterpolatedString($buf, false);
818
+ $node->addChild(new Statement($str->getPosition(), $str));
819
+ }
820
+
821
+ return $node;
822
+ }
823
+
824
+ protected function syntaxErrorExpected(Buffer $buf, $expected)
825
+ {
826
+ $unexpected = $buf->peekChar();
827
+ if ($unexpected) {
828
+ $unexpected = "'$unexpected'";
829
+ } else {
830
+ $unexpected = 'end of line';
831
+ }
832
+ $msg = sprintf("Unexpected %s, expected %s", $unexpected, $expected);
833
+ return $this->syntaxError($buf, $msg);
834
+ }
835
+
836
+ protected function syntaxError(Buffer $buf, $msg)
837
+ {
838
+ $this->column = $buf->getColumn();
839
+ $this->lineno = $buf->getLineno();
840
+
841
+ $msg = sprintf('%s in %s on line %d, column %d',
842
+ $msg, $this->filename, $this->lineno, $this->column);
843
+
844
+ return new SyntaxErrorException($msg);
845
+ }
846
+
847
+ public function getColumn()
848
+ {
849
+ return $this->column;
850
+ }
851
+
852
+ public function getLineno()
853
+ {
854
+ return $this->lineno;
855
+ }
856
+
857
+ public function getFilename()
858
+ {
859
+ return $this->filename;
860
+ }
861
+
862
+ }