parsanol 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of parsanol might be problematic. Click here for more details.

Files changed (336) hide show
  1. checksums.yaml +7 -0
  2. data/HISTORY.txt +25 -0
  3. data/LICENSE +23 -0
  4. data/README.adoc +643 -0
  5. data/Rakefile +189 -0
  6. data/example/balanced-parens/basic.rb +42 -0
  7. data/example/balanced-parens/basic.rb.md +86 -0
  8. data/example/balanced-parens/parens.rb +42 -0
  9. data/example/balanced-parens/ruby_transform.rb +162 -0
  10. data/example/big.erb +73 -0
  11. data/example/boolean-algebra/basic.rb +70 -0
  12. data/example/boolean-algebra/basic.rb.md +108 -0
  13. data/example/boolean-algebra/ruby_transform.rb +263 -0
  14. data/example/calculator/basic.rb +153 -0
  15. data/example/calculator/basic.rb.md +120 -0
  16. data/example/calculator/pattern.rb +153 -0
  17. data/example/calculator/ruby_transform.rb +156 -0
  18. data/example/calculator/ruby_transform.rb.md +32 -0
  19. data/example/calculator/serialized.rb +257 -0
  20. data/example/calculator/serialized.rb.md +32 -0
  21. data/example/calculator/transform.rb +153 -0
  22. data/example/calculator/zero_copy.rb +269 -0
  23. data/example/calculator/zero_copy.rb.md +36 -0
  24. data/example/capture/basic.rb +49 -0
  25. data/example/capture/basic.rb.md +106 -0
  26. data/example/capture/example.json +39 -0
  27. data/example/comments/basic.rb +35 -0
  28. data/example/comments/basic.rb.md +110 -0
  29. data/example/csv/ruby_transform.rb +148 -0
  30. data/example/csv/ruby_transform.rb.md +131 -0
  31. data/example/csv/serialized.rb +201 -0
  32. data/example/csv/serialized.rb.md +31 -0
  33. data/example/csv/zero_copy.rb +276 -0
  34. data/example/csv/zero_copy.rb.md +36 -0
  35. data/example/custom_atoms/indent_atom.rb +79 -0
  36. data/example/deepest-errors/basic.rb +131 -0
  37. data/example/deepest-errors/basic.rb.md +152 -0
  38. data/example/documentation/basic.rb +18 -0
  39. data/example/documentation/basic.rb.md +97 -0
  40. data/example/email/basic.rb +55 -0
  41. data/example/email/basic.rb.md +102 -0
  42. data/example/email/ruby_transform.rb +106 -0
  43. data/example/empty/basic.rb +13 -0
  44. data/example/empty/basic.rb.md +73 -0
  45. data/example/empty/example.json +38 -0
  46. data/example/erb/basic.rb +47 -0
  47. data/example/erb/basic.rb.md +103 -0
  48. data/example/erb/optimized.rb +42 -0
  49. data/example/error-reporting/basic.rb +132 -0
  50. data/example/error-reporting/basic.rb.md +122 -0
  51. data/example/expression-evaluator/basic.rb +284 -0
  52. data/example/expression-evaluator/basic.rb.md +138 -0
  53. data/example/ini/basic.rb +154 -0
  54. data/example/ini/basic.rb.md +129 -0
  55. data/example/ini/ruby_transform.rb +154 -0
  56. data/example/ip-address/basic.rb +125 -0
  57. data/example/ip-address/basic.rb.md +139 -0
  58. data/example/iso-6709/basic.rb +231 -0
  59. data/example/iso-6709/basic.rb.md +143 -0
  60. data/example/iso-8601/basic.rb +275 -0
  61. data/example/iso-8601/basic.rb.md +149 -0
  62. data/example/json/basic.rb +128 -0
  63. data/example/json/basic.rb.md +121 -0
  64. data/example/json/pattern.rb +128 -0
  65. data/example/json/ruby_transform.rb +200 -0
  66. data/example/json/ruby_transform.rb.md +32 -0
  67. data/example/json/serialized.rb +233 -0
  68. data/example/json/serialized.rb.md +31 -0
  69. data/example/json/transform.rb +128 -0
  70. data/example/json/zero_copy.rb +316 -0
  71. data/example/json/zero_copy.rb.md +36 -0
  72. data/example/local/basic.rb +34 -0
  73. data/example/local/basic.rb.md +91 -0
  74. data/example/local/example.json +38 -0
  75. data/example/markdown/basic.rb +287 -0
  76. data/example/markdown/basic.rb.md +160 -0
  77. data/example/markup/basic.rb +173 -0
  78. data/example/markup/basic.rb.md +118 -0
  79. data/example/mathn/basic.rb +47 -0
  80. data/example/mathn/basic.rb.md +96 -0
  81. data/example/mathn/example.json +39 -0
  82. data/example/minilisp/basic.rb +94 -0
  83. data/example/minilisp/basic.rb.md +133 -0
  84. data/example/modularity/basic.rb +47 -0
  85. data/example/modularity/basic.rb.md +152 -0
  86. data/example/nested-errors/basic.rb +132 -0
  87. data/example/nested-errors/basic.rb.md +157 -0
  88. data/example/output/boolean_algebra.out +4 -0
  89. data/example/output/calc.out +1 -0
  90. data/example/output/capture.out +3 -0
  91. data/example/output/comments.out +8 -0
  92. data/example/output/deepest_errors.out +54 -0
  93. data/example/output/documentation.err +4 -0
  94. data/example/output/documentation.out +1 -0
  95. data/example/output/email_parser.out +2 -0
  96. data/example/output/empty.err +1 -0
  97. data/example/output/erb.out +7 -0
  98. data/example/output/ignore.out +1 -0
  99. data/example/output/ignore_whitespace.out +1 -0
  100. data/example/output/ip_address.out +9 -0
  101. data/example/output/json.out +5 -0
  102. data/example/output/local.out +3 -0
  103. data/example/output/mathn.out +4 -0
  104. data/example/output/minilisp.out +5 -0
  105. data/example/output/modularity.out +0 -0
  106. data/example/output/nested_errors.out +54 -0
  107. data/example/output/optimized_erb.out +1 -0
  108. data/example/output/parens.out +8 -0
  109. data/example/output/prec_calc.out +5 -0
  110. data/example/output/readme.out +1 -0
  111. data/example/output/scopes.out +1 -0
  112. data/example/output/seasons.out +28 -0
  113. data/example/output/sentence.out +1 -0
  114. data/example/output/simple_xml.out +2 -0
  115. data/example/output/string_parser.out +3 -0
  116. data/example/prec-calc/basic.rb +71 -0
  117. data/example/prec-calc/basic.rb.md +114 -0
  118. data/example/readme/basic.rb +30 -0
  119. data/example/readme/basic.rb.md +80 -0
  120. data/example/scopes/basic.rb +15 -0
  121. data/example/scopes/basic.rb.md +73 -0
  122. data/example/scopes/example.json +38 -0
  123. data/example/seasons/basic.rb +46 -0
  124. data/example/seasons/basic.rb.md +117 -0
  125. data/example/seasons/example.json +40 -0
  126. data/example/sentence/basic.rb +36 -0
  127. data/example/sentence/basic.rb.md +81 -0
  128. data/example/sexp/ruby_transform.rb +180 -0
  129. data/example/sexp/ruby_transform.rb.md +143 -0
  130. data/example/simple-xml/basic.rb +54 -0
  131. data/example/simple-xml/basic.rb.md +125 -0
  132. data/example/simple.lit +3 -0
  133. data/example/string-literal/basic.rb +77 -0
  134. data/example/string-literal/basic.rb.md +128 -0
  135. data/example/test.lit +4 -0
  136. data/example/toml/basic.rb +226 -0
  137. data/example/toml/basic.rb.md +173 -0
  138. data/example/url/basic.rb +219 -0
  139. data/example/url/basic.rb.md +142 -0
  140. data/example/url/ruby_transform.rb +219 -0
  141. data/example/yaml/basic.rb +216 -0
  142. data/example/yaml/basic.rb.md +148 -0
  143. data/ext/parsanol_native/extconf.rb +4 -0
  144. data/lib/parsanol/accelerator/application.rb +62 -0
  145. data/lib/parsanol/accelerator/engine.rb +112 -0
  146. data/lib/parsanol/accelerator.rb +162 -0
  147. data/lib/parsanol/ast_visitor.rb +122 -0
  148. data/lib/parsanol/atoms/alternative.rb +97 -0
  149. data/lib/parsanol/atoms/base.rb +214 -0
  150. data/lib/parsanol/atoms/can_flatten.rb +192 -0
  151. data/lib/parsanol/atoms/capture.rb +41 -0
  152. data/lib/parsanol/atoms/context.rb +351 -0
  153. data/lib/parsanol/atoms/context_optimized.rb +42 -0
  154. data/lib/parsanol/atoms/custom.rb +110 -0
  155. data/lib/parsanol/atoms/cut.rb +62 -0
  156. data/lib/parsanol/atoms/dsl.rb +130 -0
  157. data/lib/parsanol/atoms/dynamic.rb +33 -0
  158. data/lib/parsanol/atoms/entity.rb +55 -0
  159. data/lib/parsanol/atoms/ignored.rb +28 -0
  160. data/lib/parsanol/atoms/infix.rb +121 -0
  161. data/lib/parsanol/atoms/lookahead.rb +64 -0
  162. data/lib/parsanol/atoms/named.rb +50 -0
  163. data/lib/parsanol/atoms/re.rb +61 -0
  164. data/lib/parsanol/atoms/repetition.rb +241 -0
  165. data/lib/parsanol/atoms/scope.rb +28 -0
  166. data/lib/parsanol/atoms/sequence.rb +157 -0
  167. data/lib/parsanol/atoms/str.rb +90 -0
  168. data/lib/parsanol/atoms/visitor.rb +91 -0
  169. data/lib/parsanol/atoms.rb +36 -0
  170. data/lib/parsanol/buffer.rb +130 -0
  171. data/lib/parsanol/builder_callbacks.rb +353 -0
  172. data/lib/parsanol/cause.rb +101 -0
  173. data/lib/parsanol/context.rb +23 -0
  174. data/lib/parsanol/convenience.rb +35 -0
  175. data/lib/parsanol/edit_tracker.rb +107 -0
  176. data/lib/parsanol/error_reporter/contextual.rb +122 -0
  177. data/lib/parsanol/error_reporter/deepest.rb +106 -0
  178. data/lib/parsanol/error_reporter/tree.rb +68 -0
  179. data/lib/parsanol/error_reporter.rb +98 -0
  180. data/lib/parsanol/export.rb +163 -0
  181. data/lib/parsanol/expression/treetop.rb +94 -0
  182. data/lib/parsanol/expression.rb +51 -0
  183. data/lib/parsanol/fast_mode.rb +145 -0
  184. data/lib/parsanol/first_set.rb +75 -0
  185. data/lib/parsanol/grammar_builder.rb +177 -0
  186. data/lib/parsanol/graphviz.rb +97 -0
  187. data/lib/parsanol/incremental_parser.rb +179 -0
  188. data/lib/parsanol/interval_tree.rb +215 -0
  189. data/lib/parsanol/lazy_result.rb +178 -0
  190. data/lib/parsanol/lexer.rb +146 -0
  191. data/lib/parsanol/native/parser.rb +630 -0
  192. data/lib/parsanol/native/serializer.rb +245 -0
  193. data/lib/parsanol/native/transformer.rb +438 -0
  194. data/lib/parsanol/native/types.rb +41 -0
  195. data/lib/parsanol/native.rb +217 -0
  196. data/lib/parsanol/optimizer.rb +86 -0
  197. data/lib/parsanol/optimizers/choice_optimizer.rb +78 -0
  198. data/lib/parsanol/optimizers/cut_inserter.rb +175 -0
  199. data/lib/parsanol/optimizers/lookahead_optimizer.rb +58 -0
  200. data/lib/parsanol/optimizers/quantifier_optimizer.rb +62 -0
  201. data/lib/parsanol/optimizers/sequence_optimizer.rb +97 -0
  202. data/lib/parsanol/options/ruby_transform.rb +109 -0
  203. data/lib/parsanol/options/serialized.rb +94 -0
  204. data/lib/parsanol/options/zero_copy.rb +130 -0
  205. data/lib/parsanol/options.rb +20 -0
  206. data/lib/parsanol/parallel.rb +133 -0
  207. data/lib/parsanol/parsanol_native.bundle +0 -0
  208. data/lib/parsanol/parser.rb +151 -0
  209. data/lib/parsanol/parslet.rb +148 -0
  210. data/lib/parsanol/parslet_native.bundle +0 -0
  211. data/lib/parsanol/pattern/binding.rb +49 -0
  212. data/lib/parsanol/pattern.rb +115 -0
  213. data/lib/parsanol/pool.rb +220 -0
  214. data/lib/parsanol/pools/array_pool.rb +75 -0
  215. data/lib/parsanol/pools/buffer_pool.rb +173 -0
  216. data/lib/parsanol/pools/position_pool.rb +92 -0
  217. data/lib/parsanol/pools/slice_pool.rb +64 -0
  218. data/lib/parsanol/position.rb +89 -0
  219. data/lib/parsanol/result.rb +44 -0
  220. data/lib/parsanol/result_builder.rb +208 -0
  221. data/lib/parsanol/result_stream.rb +262 -0
  222. data/lib/parsanol/rig/rspec.rb +52 -0
  223. data/lib/parsanol/rope.rb +78 -0
  224. data/lib/parsanol/scope.rb +42 -0
  225. data/lib/parsanol/slice.rb +172 -0
  226. data/lib/parsanol/source/line_cache.rb +99 -0
  227. data/lib/parsanol/source.rb +171 -0
  228. data/lib/parsanol/source_location.rb +164 -0
  229. data/lib/parsanol/streaming_parser.rb +124 -0
  230. data/lib/parsanol/string_view.rb +192 -0
  231. data/lib/parsanol/transform.rb +267 -0
  232. data/lib/parsanol/version.rb +5 -0
  233. data/lib/parsanol/wasm/README.md +80 -0
  234. data/lib/parsanol/wasm/package.json +51 -0
  235. data/lib/parsanol/wasm/parsanol.js +252 -0
  236. data/lib/parsanol/wasm/parslet.d.ts +129 -0
  237. data/lib/parsanol/wasm_parser.rb +239 -0
  238. data/lib/parsanol.rb +408 -0
  239. data/parsanol-ruby.gemspec +56 -0
  240. data/spec/acceptance/examples_spec.rb +96 -0
  241. data/spec/acceptance/infix_parser_spec.rb +145 -0
  242. data/spec/acceptance/mixing_parsers_spec.rb +74 -0
  243. data/spec/acceptance/regression_spec.rb +329 -0
  244. data/spec/acceptance/repetition_and_maybe_spec.rb +44 -0
  245. data/spec/acceptance/unconsumed_input_spec.rb +21 -0
  246. data/spec/benchmark/comparative/runner_spec.rb +105 -0
  247. data/spec/integration/array_pooling_spec.rb +193 -0
  248. data/spec/integration/buffer_allocation_spec.rb +324 -0
  249. data/spec/integration/position_pooling_spec.rb +184 -0
  250. data/spec/integration/result_builder_spec.rb +282 -0
  251. data/spec/integration/rope_stringview_integration_spec.rb +188 -0
  252. data/spec/integration/slice_pooling_spec.rb +63 -0
  253. data/spec/integration/string_view_integration_spec.rb +125 -0
  254. data/spec/lexer_spec.rb +231 -0
  255. data/spec/parsanol/atom_results_spec.rb +39 -0
  256. data/spec/parsanol/atoms/alternative_spec.rb +26 -0
  257. data/spec/parsanol/atoms/base_spec.rb +127 -0
  258. data/spec/parsanol/atoms/capture_spec.rb +21 -0
  259. data/spec/parsanol/atoms/combinations_spec.rb +5 -0
  260. data/spec/parsanol/atoms/custom_spec.rb +79 -0
  261. data/spec/parsanol/atoms/dsl_spec.rb +7 -0
  262. data/spec/parsanol/atoms/entity_spec.rb +77 -0
  263. data/spec/parsanol/atoms/ignored_spec.rb +15 -0
  264. data/spec/parsanol/atoms/infix_spec.rb +5 -0
  265. data/spec/parsanol/atoms/lookahead_spec.rb +22 -0
  266. data/spec/parsanol/atoms/named_spec.rb +4 -0
  267. data/spec/parsanol/atoms/re_spec.rb +14 -0
  268. data/spec/parsanol/atoms/repetition_spec.rb +24 -0
  269. data/spec/parsanol/atoms/scope_spec.rb +26 -0
  270. data/spec/parsanol/atoms/sequence_spec.rb +28 -0
  271. data/spec/parsanol/atoms/str_spec.rb +15 -0
  272. data/spec/parsanol/atoms/visitor_spec.rb +101 -0
  273. data/spec/parsanol/atoms_spec.rb +488 -0
  274. data/spec/parsanol/auto_optimize_spec.rb +334 -0
  275. data/spec/parsanol/buffer_spec.rb +219 -0
  276. data/spec/parsanol/builder_callbacks_spec.rb +377 -0
  277. data/spec/parsanol/choice_optimizer_spec.rb +231 -0
  278. data/spec/parsanol/convenience_spec.rb +54 -0
  279. data/spec/parsanol/cut_inserter_spec.rb +248 -0
  280. data/spec/parsanol/cut_spec.rb +66 -0
  281. data/spec/parsanol/edit_tracker_spec.rb +218 -0
  282. data/spec/parsanol/error_reporter/contextual_spec.rb +122 -0
  283. data/spec/parsanol/error_reporter/deepest_spec.rb +82 -0
  284. data/spec/parsanol/error_reporter/tree_spec.rb +7 -0
  285. data/spec/parsanol/export_spec.rb +67 -0
  286. data/spec/parsanol/expression/treetop_spec.rb +75 -0
  287. data/spec/parsanol/first_set_spec.rb +298 -0
  288. data/spec/parsanol/interval_tree_spec.rb +205 -0
  289. data/spec/parsanol/lazy_result_spec.rb +288 -0
  290. data/spec/parsanol/lookahead_optimizer_spec.rb +252 -0
  291. data/spec/parsanol/minilisp.citrus +29 -0
  292. data/spec/parsanol/minilisp.tt +29 -0
  293. data/spec/parsanol/optimizer_spec.rb +459 -0
  294. data/spec/parsanol/options/parslet_compat_spec.rb +166 -0
  295. data/spec/parsanol/options/ruby_transform_spec.rb +70 -0
  296. data/spec/parsanol/options/serialized_spec.rb +69 -0
  297. data/spec/parsanol/options/zero_copy_spec.rb +230 -0
  298. data/spec/parsanol/parser_spec.rb +36 -0
  299. data/spec/parsanol/parslet_spec.rb +38 -0
  300. data/spec/parsanol/pattern_spec.rb +272 -0
  301. data/spec/parsanol/pool_spec.rb +392 -0
  302. data/spec/parsanol/pools/array_pool_spec.rb +356 -0
  303. data/spec/parsanol/pools/buffer_pool_spec.rb +365 -0
  304. data/spec/parsanol/pools/position_pool_spec.rb +118 -0
  305. data/spec/parsanol/pools/slice_pool_spec.rb +262 -0
  306. data/spec/parsanol/position_spec.rb +14 -0
  307. data/spec/parsanol/result_builder_spec.rb +391 -0
  308. data/spec/parsanol/rig/rspec_spec.rb +54 -0
  309. data/spec/parsanol/rope_spec.rb +207 -0
  310. data/spec/parsanol/scope_spec.rb +45 -0
  311. data/spec/parsanol/slice_spec.rb +249 -0
  312. data/spec/parsanol/source/line_cache_spec.rb +74 -0
  313. data/spec/parsanol/source_spec.rb +207 -0
  314. data/spec/parsanol/string_view_spec.rb +345 -0
  315. data/spec/parsanol/transform/context_spec.rb +56 -0
  316. data/spec/parsanol/transform_spec.rb +183 -0
  317. data/spec/parsanol/tree_memoization_spec.rb +149 -0
  318. data/spec/parslet_compatibility/expressir_edge_cases_spec.rb +153 -0
  319. data/spec/parslet_compatibility/minimal_reproduction.rb +199 -0
  320. data/spec/parslet_compatibility_spec.rb +399 -0
  321. data/spec/parslet_imported/atom_spec.rb +93 -0
  322. data/spec/parslet_imported/combinator_spec.rb +161 -0
  323. data/spec/parslet_imported/spec_helper.rb +73 -0
  324. data/spec/performance/batch_parsing_benchmark.rb +129 -0
  325. data/spec/performance/complete_optimization_summary.rb +143 -0
  326. data/spec/performance/grammar_caching_analysis.rb +121 -0
  327. data/spec/performance/grammar_caching_benchmark.rb +80 -0
  328. data/spec/performance/native_benchmark_spec.rb +230 -0
  329. data/spec/performance/phase5_benchmark.rb +144 -0
  330. data/spec/performance/profiling_benchmark.rb +131 -0
  331. data/spec/performance/ruby_improvements_benchmark.rb +171 -0
  332. data/spec/performance_spec.rb +374 -0
  333. data/spec/spec_helper.rb +79 -0
  334. data/spec/support/opal.rb +8 -0
  335. data/spec/support/opal.rb.erb +14 -0
  336. metadata +485 -0
@@ -0,0 +1,152 @@
1
+ # Grammar Modularity - Ruby Implementation
2
+
3
+ ## How to Run
4
+
5
+ ```bash
6
+ cd parsanol-ruby/example/modularity
7
+ ruby basic.rb
8
+ ```
9
+
10
+ ## Code Walkthrough
11
+
12
+ ### Module Mixins
13
+
14
+ Ruby modules can be mixed into parser classes:
15
+
16
+ ```ruby
17
+ module ALanguage
18
+ include Parsanol::Parslet
19
+
20
+ rule(:a_language) { str('aaa') }
21
+ end
22
+ ```
23
+
24
+ `include Parsanol::Parslet` makes the module a grammar container.
25
+
26
+ ### Parser as Atom
27
+
28
+ Parser instances are valid atoms:
29
+
30
+ ```ruby
31
+ class BLanguage < Parsanol::Parser
32
+ root :blang
33
+
34
+ rule(:blang) { str('bbb') }
35
+ end
36
+ ```
37
+
38
+ Use `BLanguage.new` directly in other parsers' rules.
39
+
40
+ ### Passing Atoms
41
+
42
+ Atoms are Ruby values that can be passed around:
43
+
44
+ ```ruby
45
+ c_language = Parsanol.str('ccc')
46
+
47
+ class Language < Parsanol::Parser
48
+ def initialize(c_language)
49
+ @c_language = c_language
50
+ super()
51
+ end
52
+
53
+ rule(:root) { str('c(') >> @c_language >> str(')') }
54
+ end
55
+ ```
56
+
57
+ Constructor injection enables dynamic grammar composition.
58
+
59
+ ### Combined Root Rule
60
+
61
+ The root combines all module entry points:
62
+
63
+ ```ruby
64
+ rule(:root) {
65
+ str('a(') >> a_language >> str(')') >> space |
66
+ str('b(') >> BLanguage.new >> str(')') >> space |
67
+ str('c(') >> @c_language >> str(')') >> space
68
+ }
69
+ ```
70
+
71
+ Each alternative invokes a different module.
72
+
73
+ ### Using the Composed Parser
74
+
75
+ ```ruby
76
+ Language.new(c_language).parse('a(aaa)') # => matches
77
+ Language.new(c_language).parse('b(bbb)') # => matches
78
+ Language.new(c_language).parse('c(ccc)') # => matches
79
+ ```
80
+
81
+ Single parser instance handles all module syntaxes.
82
+
83
+ ## Design Patterns
84
+
85
+ ### Include Pattern
86
+
87
+ ```ruby
88
+ module CommonExpressions
89
+ include Parsanol::Parslet
90
+
91
+ rule(:integer) { match('[0-9]').repeat(1) }
92
+ rule(:identifier) { match('[a-z]').repeat(1) }
93
+ end
94
+
95
+ class MyParser < Parsanol::Parser
96
+ include CommonExpressions
97
+ include WhitespaceRules
98
+
99
+ rule(:expr) { integer | identifier }
100
+ end
101
+ ```
102
+
103
+ Multiple modules combine via include.
104
+
105
+ ### Delegation Pattern
106
+
107
+ ```ruby
108
+ class JsonParser < Parsanol::Parser
109
+ rule(:value) { StringParser.new | NumberParser.new | ObjectParser.new }
110
+ end
111
+ ```
112
+
113
+ Each sub-parser handles one JSON type.
114
+
115
+ ### Prefix Pattern
116
+
117
+ ```ruby
118
+ module ExpressionParser
119
+ def expr_with_prefix(prefix)
120
+ prefix >> expr
121
+ end
122
+ end
123
+ ```
124
+
125
+ Modules can provide parameterized rules.
126
+
127
+ ## Output
128
+
129
+ ```ruby
130
+ # All three module syntaxes parse
131
+ Language.new(c_language).parse('a(aaa)')
132
+ Language.new(c_language).parse('b(bbb)')
133
+ Language.new(c_language).parse('c(ccc)')
134
+ ```
135
+
136
+ ## Design Decisions
137
+
138
+ ### Why Include for Modules?
139
+
140
+ Ruby's include provides clean namespace integration. Rules become methods on the parser class.
141
+
142
+ ### Why Parser as Atom?
143
+
144
+ Parsers being atoms enables composition without special syntax. Just instantiate and chain.
145
+
146
+ ### Why Constructor Injection?
147
+
148
+ Dynamic composition allows runtime grammar modification. Same parser class with different sub-grammars.
149
+
150
+ ### Why Not Class Inheritance?
151
+
152
+ Composition (include/instance) is more flexible than inheritance. Multiple modules can be combined in any order.
@@ -0,0 +1,132 @@
1
+ $:.unshift File.dirname(__FILE__) + "/../lib"
2
+
3
+ require 'parsanol/parslet'
4
+ require 'parsanol/convenience'
5
+
6
+ # This example demonstrates tree error reporting in a real life example.
7
+ # Originally contributed to Parslet, ported to Parsanol as an example.
8
+
9
+ def prettify(str)
10
+ puts " "*3 + " "*4 + "." + " "*4 + "10" + " "*3 + "." + " "*4 + "20"
11
+ str.lines.each_with_index do |line, index|
12
+ printf "%02d %s\n",
13
+ index+1,
14
+ line.chomp
15
+ end
16
+ end
17
+
18
+ class Parser < Parsanol::Parser
19
+
20
+ # commons
21
+
22
+ rule(:space) { match('[ \t]').repeat(1) }
23
+ rule(:space?) { space.maybe }
24
+
25
+ rule(:newline) { match('[\r\n]') }
26
+
27
+ rule(:comment) { str('#') >> match('[^\r\n]').repeat }
28
+
29
+ rule(:line_separator) {
30
+ (space? >> ((comment.maybe >> newline) | str(';')) >> space?).repeat(1)
31
+ }
32
+
33
+ rule(:blank) { line_separator | space }
34
+ rule(:blank?) { blank.maybe }
35
+
36
+ rule(:identifier) { match('[a-zA-Z0-9_]').repeat(1) }
37
+
38
+ # res_statement
39
+
40
+ rule(:reference) {
41
+ (str('@').repeat(1,2) >> identifier).as(:reference)
42
+ }
43
+
44
+ rule(:res_action_or_link) {
45
+ str('.').as(:dot) >> (identifier >> str('?').maybe ).as(:name) >> str('()')
46
+ }
47
+
48
+ rule(:res_actions) {
49
+ (
50
+ reference
51
+ ).as(:resources) >>
52
+ (
53
+ res_action_or_link.as(:res_action)
54
+ ).repeat(0).as(:res_actions)
55
+ }
56
+
57
+ rule(:res_statement) {
58
+ res_actions >>
59
+ (str(':') >> identifier.as(:name)).maybe.as(:res_field)
60
+ }
61
+
62
+ # expression
63
+
64
+ rule(:expression) {
65
+ res_statement
66
+ }
67
+
68
+ # body
69
+
70
+ rule(:body) {
71
+ (line_separator >> (block | expression)).repeat(1).as(:body) >>
72
+ line_separator
73
+ }
74
+
75
+ # blocks
76
+
77
+ rule(:begin_block) {
78
+ (str('concurrent').as(:type) >> space).maybe.as(:pre) >>
79
+ str('begin').as(:begin) >>
80
+ body >>
81
+ str('end')
82
+ }
83
+
84
+ rule(:define_block) {
85
+ str('define').as(:define) >> space >>
86
+ identifier.as(:name) >> str('()') >>
87
+ body >>
88
+ str('end')
89
+ }
90
+
91
+ rule(:block) {
92
+ define_block | begin_block
93
+ }
94
+
95
+ # root
96
+
97
+ rule(:radix) {
98
+ line_separator.maybe >> block >> line_separator.maybe
99
+ }
100
+
101
+ root(:radix)
102
+ end
103
+
104
+
105
+ ds = [
106
+ %{
107
+ define f()
108
+ @res.name
109
+ end
110
+ },
111
+ %{
112
+ define f()
113
+ begin
114
+ @res.name
115
+ end
116
+ end
117
+ }
118
+ ]
119
+
120
+ ds.each do |d|
121
+
122
+ puts '-' * 80
123
+ prettify(d)
124
+
125
+ parser = Parser.new
126
+
127
+ begin
128
+ parser.parse_with_debug(d)
129
+ end
130
+ end
131
+
132
+ puts '-' * 80
@@ -0,0 +1,157 @@
1
+ # Nested Error Reporting - Ruby Implementation
2
+
3
+ ## How to Run
4
+
5
+ ```bash
6
+ cd parsanol-ruby/example/nested-errors
7
+ ruby basic.rb
8
+ ```
9
+
10
+ ## Code Walkthrough
11
+
12
+ ### parse_with_debug Output
13
+
14
+ The debug method shows full error information:
15
+
16
+ ```ruby
17
+ parser.parse_with_debug(input)
18
+ ```
19
+
20
+ This automatically formats and displays the error tree.
21
+
22
+ ### Error Tree Structure
23
+
24
+ Parslet errors form a tree:
25
+
26
+ ```
27
+ - Failed to parse sequence
28
+ - Expected "end" at line 3
29
+ - In block body
30
+ - Expected expression
31
+ - Expected "begin"
32
+ ```
33
+
34
+ Each indentation represents a nested failure context.
35
+
36
+ ### Helper Formatting
37
+
38
+ The example provides line-numbered output:
39
+
40
+ ```ruby
41
+ def prettify(str)
42
+ puts " "*3 + " "*4 + "." + " "*4 + "10" + " "*3 + "." + " "*4 + "20"
43
+ str.lines.each_with_index do |line, index|
44
+ printf "%02d %s\n", index+1, line.chomp
45
+ end
46
+ end
47
+ ```
48
+
49
+ Column ruler helps locate errors visually.
50
+
51
+ ### Complex Grammar for Testing
52
+
53
+ The example uses a realistic grammar:
54
+
55
+ ```ruby
56
+ rule(:reference) {
57
+ (str('@').repeat(1,2) >> identifier).as(:reference)
58
+ }
59
+
60
+ rule(:res_action_or_link) {
61
+ str('.').as(:dot) >>
62
+ (identifier >> str('?').maybe).as(:name) >>
63
+ str('()')
64
+ }
65
+ ```
66
+
67
+ Multiple rules create multiple failure points.
68
+
69
+ ### Block Structure
70
+
71
+ Nested blocks create deep error trees:
72
+
73
+ ```ruby
74
+ rule(:begin_block) {
75
+ (str('concurrent').as(:type) >> space).maybe.as(:pre) >>
76
+ str('begin').as(:begin) >>
77
+ body >>
78
+ str('end')
79
+ }
80
+
81
+ rule(:define_block) {
82
+ str('define').as(:define) >> space >>
83
+ identifier.as(:name) >> str('()') >>
84
+ body >>
85
+ str('end')
86
+ }
87
+ ```
88
+
89
+ Each block type has its own error context.
90
+
91
+ ### Test Cases
92
+
93
+ ```ruby
94
+ ds = [
95
+ %{
96
+ define f()
97
+ @res.name
98
+ end
99
+ },
100
+ %{
101
+ define f()
102
+ begin
103
+ @res.name
104
+ end
105
+ end
106
+ }
107
+ ]
108
+
109
+ ds.each do |d|
110
+ puts '-' * 80
111
+ prettify(d)
112
+ parser.parse_with_debug(d)
113
+ end
114
+ ```
115
+
116
+ Each case demonstrates different error scenarios.
117
+
118
+ ## Output Types
119
+
120
+ Successful parse:
121
+ ```
122
+ 01
123
+ 02 define f()
124
+ 03 @res.name
125
+ 04 end
126
+
127
+ {:define=>"define"@..., :name=>"f"@..., :body=>[...]}
128
+ ```
129
+
130
+ Failed parse with tree:
131
+ ```
132
+ 01
133
+ 02 define f()
134
+ 03 @res.name(
135
+ 04 end
136
+
137
+ Failed to match sequence
138
+ `- Expected ")" at line 3, column 12
139
+ ```
140
+
141
+ ## Design Decisions
142
+
143
+ ### Why parse_with_debug?
144
+
145
+ It handles error formatting automatically. For production use, catch `Parsanol::ParseFailed` and format custom messages.
146
+
147
+ ### Why Multiple Test Cases?
148
+
149
+ Different constructs fail differently. Multiple cases show the full error reporting capability.
150
+
151
+ ### Why Prettify Helper?
152
+
153
+ Line numbers help users find errors in their input. The column ruler aids visual scanning.
154
+
155
+ ### Why Block-Structured Grammar?
156
+
157
+ Simple grammars have shallow error trees. Block-structured grammars demonstrate nested error contexts.
@@ -0,0 +1,4 @@
1
+ {:and=>
2
+ {:left=>{:var=>"1"@3},
3
+ :right=>{:or=>{:left=>{:var=>"2"@13}, :right=>{:var=>"3"@21}}}}}
4
+ [["1", "2"], ["1", "3"]]
@@ -0,0 +1 @@
1
+ 123*2 (command line): -> 246
@@ -0,0 +1,3 @@
1
+ [{:line=>"Text1\n"@9},
2
+ {:doc=>[{:line=>"Text3\n"@23}, {:line=>"Text4\n"@29}]},
3
+ {:line=>"\nText2\n"@41}]
@@ -0,0 +1,8 @@
1
+ [{:exp=>{:a=>"a"@3}},
2
+ {:line=>"// line comment"@7},
3
+ {:exp=>{:a=>"a"@25}},
4
+ {:exp=>{:a=>"a"@27}},
5
+ {:exp=>[{:a=>"a"@29}, {:line=>"// line comment"@31}]},
6
+ {:exp=>[{:a=>"a"@49}, {:multi=>"/* inline comment */"@51}]},
7
+ {:exp=>{:a=>"a"@72}},
8
+ {:multi=>"/* multiline\n comment */"@77}]
@@ -0,0 +1,54 @@
1
+ --------------------------------------------------------------------------------
2
+ . 10 . 20
3
+ 01
4
+ 02 define f()
5
+ 03 @res.name
6
+ 04 end
7
+ 05
8
+ Failed to match sequence (LINE_SEPARATOR? BLOCK LINE_SEPARATOR?) at line 2 char 5.
9
+ `- Expected one of [DEFINE_BLOCK, BEGIN_BLOCK] at line 2 char 5.
10
+ |- Failed to match sequence (define:'define' SPACE name:IDENTIFIER '()' BODY 'end') at line 2 char 15.
11
+ | `- Failed to match sequence (body:((LINE_SEPARATOR (BLOCK / EXPRESSION)){1, }) LINE_SEPARATOR) at line 3 char 11.
12
+ | `- Expected at least 1 of SPACE? (COMMENT? NEWLINE / ';') SPACE? at line 3 char 11.
13
+ | `- Failed to match sequence (SPACE? (COMMENT? NEWLINE / ';') SPACE?) at line 3 char 11.
14
+ | `- Expected one of [COMMENT? NEWLINE, ';'] at line 3 char 11.
15
+ | |- Failed to match sequence (COMMENT? NEWLINE) at line 3 char 11.
16
+ | | `- Expected "()", but got "\n " at line 3 char 16.
17
+ | `- Expected "()", but got "\n " at line 3 char 16.
18
+ `- Failed to match sequence (pre:((type:'concurrent' SPACE)?) begin:'begin' BODY 'end') at line 2 char 5.
19
+ `- Expected "()", but got "\n " at line 3 char 16.
20
+ --------------------------------------------------------------------------------
21
+ . 10 . 20
22
+ 01
23
+ 02 define f()
24
+ 03 begin
25
+ 04 @res.name
26
+ 05 end
27
+ 06 end
28
+ 07
29
+ Failed to match sequence (LINE_SEPARATOR? BLOCK LINE_SEPARATOR?) at line 2 char 5.
30
+ `- Expected one of [DEFINE_BLOCK, BEGIN_BLOCK] at line 2 char 5.
31
+ |- Failed to match sequence (define:'define' SPACE name:IDENTIFIER '()' BODY 'end') at line 2 char 15.
32
+ | `- Failed to match sequence (body:((LINE_SEPARATOR (BLOCK / EXPRESSION)){1, }) LINE_SEPARATOR) at line 2 char 15.
33
+ | `- Expected at least 1 of LINE_SEPARATOR (BLOCK / EXPRESSION) at line 2 char 15.
34
+ | `- Failed to match sequence (LINE_SEPARATOR (BLOCK / EXPRESSION)) at line 3 char 7.
35
+ | `- Expected one of [BLOCK, EXPRESSION] at line 3 char 7.
36
+ | |- Expected one of [DEFINE_BLOCK, BEGIN_BLOCK] at line 3 char 7.
37
+ | | |- Failed to match sequence (define:'define' SPACE name:IDENTIFIER '()' BODY 'end') at line 3 char 7.
38
+ | | | `- Expected "define", but got "begin\n" at line 3 char 7.
39
+ | | `- Failed to match sequence (pre:((type:'concurrent' SPACE)?) begin:'begin' BODY 'end') at line 3 char 12.
40
+ | | `- Failed to match sequence (body:((LINE_SEPARATOR (BLOCK / EXPRESSION)){1, }) LINE_SEPARATOR) at line 4 char 13.
41
+ | | `- Expected at least 1 of SPACE? (COMMENT? NEWLINE / ';') SPACE? at line 4 char 13.
42
+ | | `- Failed to match sequence (SPACE? (COMMENT? NEWLINE / ';') SPACE?) at line 4 char 13.
43
+ | | `- Expected one of [COMMENT? NEWLINE, ';'] at line 4 char 13.
44
+ | | |- Failed to match sequence (COMMENT? NEWLINE) at line 4 char 13.
45
+ | | | `- Expected "()", but got "\n " at line 4 char 18.
46
+ | | `- Expected "()", but got "\n " at line 4 char 18.
47
+ | `- Failed to match sequence (RES_ACTIONS res_field:((':' name:IDENTIFIER)?)) at line 3 char 7.
48
+ | `- Failed to match sequence (resources:REFERENCE res_actions:(res_action:RES_ACTION_OR_LINK{0, })) at line 3 char 7.
49
+ | `- Failed to match sequence ('@'{1, 2} IDENTIFIER) at line 3 char 7.
50
+ | `- Expected at least 1 of '@' at line 3 char 7.
51
+ | `- Expected "()", but got "\n " at line 4 char 18.
52
+ `- Failed to match sequence (pre:((type:'concurrent' SPACE)?) begin:'begin' BODY 'end') at line 2 char 5.
53
+ `- Expected "()", but got "\n " at line 4 char 18.
54
+ --------------------------------------------------------------------------------
@@ -0,0 +1,4 @@
1
+ /Users/kaspar/git_work/own/parslet/lib/parslet/atoms/base.rb:326:in `parse_failed': Don't know what to do with bbbb at line 1 char 1. (Parslet::ParseFailed)
2
+ from /Users/kaspar/git_work/own/parslet/lib/parslet/atoms/base.rb:55:in `parse'
3
+ from example/documentation.rb:13:in `parse'
4
+ from example/documentation.rb:18:in `<main>'
@@ -0,0 +1 @@
1
+ "aaaa"@0
@@ -0,0 +1,2 @@
1
+ since you haven't specified any EMAIL_ADDR, for testing purposes we're using a.b.c.d@gmail.com
2
+ "a.b.c.d@gmail.com"
@@ -0,0 +1 @@
1
+ example/empty.rb:13:in `<main>': rule(:empty) { ... } returns nil. Still not implemented, but already used? (NotImplementedError)
@@ -0,0 +1,7 @@
1
+ {:text=>[{:text=>"The value of x is "@0}, {:expression=>{:ruby=>" x "@21}}, {:text=>"."@26}]}
2
+ {:text=>[{:code=>{:ruby=>" 1 + 2 "@2}}]}
3
+ {:text=>[{:comment=>{:ruby=>" commented "@3}}]}
4
+ The not printed result of "a = 2".
5
+ The not printed non-evaluated comment "a = 1", see the value of a below.
6
+ The nicely printed result.
7
+ The value of a is 2, and b is 3.
@@ -0,0 +1 @@
1
+ "ac"@0
@@ -0,0 +1 @@
1
+ [{:a=>"a"@0}, {:a=>"a"@1}, {:a=>"a"@5}, {:a=>"a"@7}]
@@ -0,0 +1,9 @@
1
+ 0.0.0.0 -> {:ipv4=>"0.0.0.0"@0}
2
+ 255.255.255.255 -> {:ipv4=>"255.255.255.255"@0}
3
+ 255.255.255 -> Failed: Expected one of [IPV4, IPV6] at line 1 char 1.
4
+ 1:2:3:4:5:6:7:8 -> {:ipv6=>"1:2:3:4:5:6:7:8"@0}
5
+ 12AD:34FC:A453:1922:: -> {:ipv6=>"12AD:34FC:A453:1922::"@0}
6
+ 12AD::34FC -> {:ipv6=>"12AD::34FC"@0}
7
+ 12AD:: -> {:ipv6=>"12AD::"@0}
8
+ :: -> {:ipv6=>"::"@0}
9
+ 1:2 -> Failed: Expected one of [IPV4, IPV6] at line 1 char 1.
@@ -0,0 +1,5 @@
1
+
2
+ {:array=>[{:number=>"1"@5}, {:number=>"2"@8}, {:number=>"3"@11}, {:null=>"null"@14}, {:string=>"asdfasdf asdfds"@25}, {:object=>{:entry=>{:key=>{:string=>"a"@46}, :val=>{:number=>"-1.2"@50}}}}, {:object=>[{:entry=>{:key=>{:string=>"b"@61}, :val=>{:true=>"true"@65}}}, {:entry=>{:key=>{:string=>"c"@72}, :val=>{:false=>"false"@76}}}]}, {:number=>"0.1e24"@89}, {:true=>"true"@97}, {:false=>"false"@103}, {:array=>{:number=>"1"@112}}]}
3
+
4
+ [1, 2, 3, nil, "asdfasdf asdfds", {"a"=>-1.2}, {"b"=>true, "c"=>false}, 1.0e+23, true, false, [1]]
5
+
@@ -0,0 +1,3 @@
1
+ {:e=>"a"@0, :rec=>{:e=>"a"@1, :rec=>{:e=>"a"@2, :rec=>{:e=>"a"@3, :rec=>nil}}}}
2
+ e2:'aa' !. / e1:'a' rec:B
3
+ {:e1=>"a"@0, :rec=>{:e1=>"a"@1, :rec=>{:e2=>"aa"@2}}}
@@ -0,0 +1,4 @@
1
+ it terminates before we require mathn
2
+ requiring mathn now
3
+ and trying again (will hang without the fix)
4
+ okay!
@@ -0,0 +1,5 @@
1
+ [:define,
2
+ :test,
3
+ [:lambda,
4
+ [],
5
+ [:begin, [:display, "something"@54], [:display, 1], [:display, 3.08]]]]
File without changes
@@ -0,0 +1,54 @@
1
+ --------------------------------------------------------------------------------
2
+ . 10 . 20
3
+ 01
4
+ 02 define f()
5
+ 03 @res.name
6
+ 04 end
7
+ 05
8
+ Failed to match sequence (LINE_SEPARATOR? BLOCK LINE_SEPARATOR?) at line 2 char 5.
9
+ `- Expected one of [DEFINE_BLOCK, BEGIN_BLOCK] at line 2 char 5.
10
+ |- Failed to match sequence (define:'define' SPACE name:IDENTIFIER '()' BODY 'end') at line 2 char 15.
11
+ | `- Failed to match sequence (body:((LINE_SEPARATOR (BLOCK / EXPRESSION)){1, }) LINE_SEPARATOR) at line 3 char 11.
12
+ | `- Expected at least 1 of SPACE? (COMMENT? NEWLINE / ';') SPACE? at line 3 char 11.
13
+ | `- Failed to match sequence (SPACE? (COMMENT? NEWLINE / ';') SPACE?) at line 3 char 11.
14
+ | `- Expected one of [COMMENT? NEWLINE, ';'] at line 3 char 11.
15
+ | |- Failed to match sequence (COMMENT? NEWLINE) at line 3 char 11.
16
+ | | `- Failed to match [\\r\\n] at line 3 char 11.
17
+ | `- Expected ";", but got "." at line 3 char 11.
18
+ `- Failed to match sequence (pre:((type:'concurrent' SPACE)?) begin:'begin' BODY 'end') at line 2 char 5.
19
+ `- Expected "begin", but got "defin" at line 2 char 5.
20
+ --------------------------------------------------------------------------------
21
+ . 10 . 20
22
+ 01
23
+ 02 define f()
24
+ 03 begin
25
+ 04 @res.name
26
+ 05 end
27
+ 06 end
28
+ 07
29
+ Failed to match sequence (LINE_SEPARATOR? BLOCK LINE_SEPARATOR?) at line 2 char 5.
30
+ `- Expected one of [DEFINE_BLOCK, BEGIN_BLOCK] at line 2 char 5.
31
+ |- Failed to match sequence (define:'define' SPACE name:IDENTIFIER '()' BODY 'end') at line 2 char 15.
32
+ | `- Failed to match sequence (body:((LINE_SEPARATOR (BLOCK / EXPRESSION)){1, }) LINE_SEPARATOR) at line 2 char 15.
33
+ | `- Expected at least 1 of LINE_SEPARATOR (BLOCK / EXPRESSION) at line 2 char 15.
34
+ | `- Failed to match sequence (LINE_SEPARATOR (BLOCK / EXPRESSION)) at line 3 char 7.
35
+ | `- Expected one of [BLOCK, EXPRESSION] at line 3 char 7.
36
+ | |- Expected one of [DEFINE_BLOCK, BEGIN_BLOCK] at line 3 char 7.
37
+ | | |- Failed to match sequence (define:'define' SPACE name:IDENTIFIER '()' BODY 'end') at line 3 char 7.
38
+ | | | `- Expected "define", but got "begin\n" at line 3 char 7.
39
+ | | `- Failed to match sequence (pre:((type:'concurrent' SPACE)?) begin:'begin' BODY 'end') at line 3 char 12.
40
+ | | `- Failed to match sequence (body:((LINE_SEPARATOR (BLOCK / EXPRESSION)){1, }) LINE_SEPARATOR) at line 4 char 13.
41
+ | | `- Expected at least 1 of SPACE? (COMMENT? NEWLINE / ';') SPACE? at line 4 char 13.
42
+ | | `- Failed to match sequence (SPACE? (COMMENT? NEWLINE / ';') SPACE?) at line 4 char 13.
43
+ | | `- Expected one of [COMMENT? NEWLINE, ';'] at line 4 char 13.
44
+ | | |- Failed to match sequence (COMMENT? NEWLINE) at line 4 char 13.
45
+ | | | `- Failed to match [\\r\\n] at line 4 char 13.
46
+ | | `- Expected ";", but got "." at line 4 char 13.
47
+ | `- Failed to match sequence (RES_ACTIONS res_field:((':' name:IDENTIFIER)?)) at line 3 char 7.
48
+ | `- Failed to match sequence (resources:REFERENCE res_actions:(res_action:RES_ACTION_OR_LINK{0, })) at line 3 char 7.
49
+ | `- Failed to match sequence ('@'{1, 2} IDENTIFIER) at line 3 char 7.
50
+ | `- Expected at least 1 of '@' at line 3 char 7.
51
+ | `- Expected "@", but got "b" at line 3 char 7.
52
+ `- Failed to match sequence (pre:((type:'concurrent' SPACE)?) begin:'begin' BODY 'end') at line 2 char 5.
53
+ `- Expected "begin", but got "defin" at line 2 char 5.
54
+ --------------------------------------------------------------------------------
@@ -0,0 +1 @@
1
+ {:text=>[{:text=>"Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\n"@0}, {:expression=>{:ruby=>" erb tag "@2685}}, {:text=>"\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n"@2696}]}
@@ -0,0 +1,8 @@
1
+ (): {:l=>"("@0, :m=>nil, :r=>")"@1} (1 parens)
2
+
3
+ (()): {:l=>"("@0, :m=>{:l=>"("@1, :m=>nil, :r=>")"@2}, :r=>")"@3} (2 parens)
4
+
5
+ ((((())))): {:l=>"("@0, :m=>{:l=>"("@1, :m=>{:l=>"("@2, :m=>{:l=>"("@3, :m=>{:l=>"("@4, :m=>nil, :r=>")"@5}, :r=>")"@6}, :r=>")"@7}, :r=>")"@8}, :r=>")"@9} (5 parens)
6
+
7
+ ((()): Failed to match sequence (l:'(' m:(BALANCED?) r:')') at line 1 char 6.
8
+
@@ -0,0 +1,5 @@
1
+ a = 1
2
+ b = 2
3
+ c = 3 * 25
4
+ d = 100 + 3*4
5
+ {:a=>1, :b=>2, :c=>75, :d=>112}
@@ -0,0 +1 @@
1
+ String contents: This is a \"String\" in which you can escape stuff