plurimath-parslet 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.
Files changed (148) hide show
  1. checksums.yaml +7 -0
  2. data/HISTORY.txt +284 -0
  3. data/LICENSE +23 -0
  4. data/README.adoc +454 -0
  5. data/Rakefile +71 -0
  6. data/lib/parslet/accelerator/application.rb +62 -0
  7. data/lib/parslet/accelerator/engine.rb +112 -0
  8. data/lib/parslet/accelerator.rb +162 -0
  9. data/lib/parslet/atoms/alternative.rb +53 -0
  10. data/lib/parslet/atoms/base.rb +157 -0
  11. data/lib/parslet/atoms/can_flatten.rb +137 -0
  12. data/lib/parslet/atoms/capture.rb +38 -0
  13. data/lib/parslet/atoms/context.rb +103 -0
  14. data/lib/parslet/atoms/dsl.rb +112 -0
  15. data/lib/parslet/atoms/dynamic.rb +32 -0
  16. data/lib/parslet/atoms/entity.rb +45 -0
  17. data/lib/parslet/atoms/ignored.rb +26 -0
  18. data/lib/parslet/atoms/infix.rb +115 -0
  19. data/lib/parslet/atoms/lookahead.rb +52 -0
  20. data/lib/parslet/atoms/named.rb +32 -0
  21. data/lib/parslet/atoms/re.rb +41 -0
  22. data/lib/parslet/atoms/repetition.rb +87 -0
  23. data/lib/parslet/atoms/scope.rb +26 -0
  24. data/lib/parslet/atoms/sequence.rb +48 -0
  25. data/lib/parslet/atoms/str.rb +42 -0
  26. data/lib/parslet/atoms/visitor.rb +89 -0
  27. data/lib/parslet/atoms.rb +34 -0
  28. data/lib/parslet/cause.rb +101 -0
  29. data/lib/parslet/context.rb +21 -0
  30. data/lib/parslet/convenience.rb +33 -0
  31. data/lib/parslet/error_reporter/contextual.rb +120 -0
  32. data/lib/parslet/error_reporter/deepest.rb +100 -0
  33. data/lib/parslet/error_reporter/tree.rb +63 -0
  34. data/lib/parslet/error_reporter.rb +8 -0
  35. data/lib/parslet/export.rb +163 -0
  36. data/lib/parslet/expression/treetop.rb +92 -0
  37. data/lib/parslet/expression.rb +51 -0
  38. data/lib/parslet/graphviz.rb +97 -0
  39. data/lib/parslet/parser.rb +68 -0
  40. data/lib/parslet/pattern/binding.rb +49 -0
  41. data/lib/parslet/pattern.rb +113 -0
  42. data/lib/parslet/position.rb +21 -0
  43. data/lib/parslet/rig/rspec.rb +52 -0
  44. data/lib/parslet/scope.rb +42 -0
  45. data/lib/parslet/slice.rb +105 -0
  46. data/lib/parslet/source/line_cache.rb +99 -0
  47. data/lib/parslet/source.rb +96 -0
  48. data/lib/parslet/transform.rb +265 -0
  49. data/lib/parslet/version.rb +5 -0
  50. data/lib/parslet.rb +314 -0
  51. data/plurimath-parslet.gemspec +42 -0
  52. data/spec/acceptance/infix_parser_spec.rb +145 -0
  53. data/spec/acceptance/mixing_parsers_spec.rb +74 -0
  54. data/spec/acceptance/regression_spec.rb +329 -0
  55. data/spec/acceptance/repetition_and_maybe_spec.rb +44 -0
  56. data/spec/acceptance/unconsumed_input_spec.rb +21 -0
  57. data/spec/examples/boolean_algebra_spec.rb +257 -0
  58. data/spec/examples/calc_spec.rb +278 -0
  59. data/spec/examples/capture_spec.rb +137 -0
  60. data/spec/examples/comments_spec.rb +186 -0
  61. data/spec/examples/deepest_errors_spec.rb +420 -0
  62. data/spec/examples/documentation_spec.rb +205 -0
  63. data/spec/examples/email_parser_spec.rb +275 -0
  64. data/spec/examples/empty_spec.rb +37 -0
  65. data/spec/examples/erb_spec.rb +482 -0
  66. data/spec/examples/ip_address_spec.rb +153 -0
  67. data/spec/examples/json_spec.rb +413 -0
  68. data/spec/examples/local_spec.rb +302 -0
  69. data/spec/examples/mathn_spec.rb +151 -0
  70. data/spec/examples/minilisp_spec.rb +492 -0
  71. data/spec/examples/modularity_spec.rb +340 -0
  72. data/spec/examples/nested_errors_spec.rb +322 -0
  73. data/spec/examples/optimized_erb_spec.rb +299 -0
  74. data/spec/examples/parens_spec.rb +239 -0
  75. data/spec/examples/prec_calc_spec.rb +525 -0
  76. data/spec/examples/readme_spec.rb +228 -0
  77. data/spec/examples/scopes_spec.rb +187 -0
  78. data/spec/examples/seasons_spec.rb +196 -0
  79. data/spec/examples/sentence_spec.rb +119 -0
  80. data/spec/examples/simple_xml_spec.rb +250 -0
  81. data/spec/examples/string_parser_spec.rb +407 -0
  82. data/spec/fixtures/examples/boolean_algebra.rb +62 -0
  83. data/spec/fixtures/examples/calc.rb +86 -0
  84. data/spec/fixtures/examples/capture.rb +36 -0
  85. data/spec/fixtures/examples/comments.rb +22 -0
  86. data/spec/fixtures/examples/deepest_errors.rb +99 -0
  87. data/spec/fixtures/examples/documentation.rb +32 -0
  88. data/spec/fixtures/examples/email_parser.rb +42 -0
  89. data/spec/fixtures/examples/empty.rb +10 -0
  90. data/spec/fixtures/examples/erb.rb +39 -0
  91. data/spec/fixtures/examples/ip_address.rb +103 -0
  92. data/spec/fixtures/examples/json.rb +107 -0
  93. data/spec/fixtures/examples/local.rb +60 -0
  94. data/spec/fixtures/examples/mathn.rb +47 -0
  95. data/spec/fixtures/examples/minilisp.rb +75 -0
  96. data/spec/fixtures/examples/modularity.rb +60 -0
  97. data/spec/fixtures/examples/nested_errors.rb +95 -0
  98. data/spec/fixtures/examples/optimized_erb.rb +105 -0
  99. data/spec/fixtures/examples/parens.rb +25 -0
  100. data/spec/fixtures/examples/prec_calc.rb +71 -0
  101. data/spec/fixtures/examples/readme.rb +59 -0
  102. data/spec/fixtures/examples/scopes.rb +43 -0
  103. data/spec/fixtures/examples/seasons.rb +40 -0
  104. data/spec/fixtures/examples/sentence.rb +18 -0
  105. data/spec/fixtures/examples/simple_xml.rb +51 -0
  106. data/spec/fixtures/examples/string_parser.rb +77 -0
  107. data/spec/parslet/atom_results_spec.rb +39 -0
  108. data/spec/parslet/atoms/alternative_spec.rb +26 -0
  109. data/spec/parslet/atoms/base_spec.rb +127 -0
  110. data/spec/parslet/atoms/capture_spec.rb +21 -0
  111. data/spec/parslet/atoms/combinations_spec.rb +5 -0
  112. data/spec/parslet/atoms/dsl_spec.rb +7 -0
  113. data/spec/parslet/atoms/entity_spec.rb +77 -0
  114. data/spec/parslet/atoms/ignored_spec.rb +15 -0
  115. data/spec/parslet/atoms/infix_spec.rb +5 -0
  116. data/spec/parslet/atoms/lookahead_spec.rb +22 -0
  117. data/spec/parslet/atoms/named_spec.rb +4 -0
  118. data/spec/parslet/atoms/re_spec.rb +14 -0
  119. data/spec/parslet/atoms/repetition_spec.rb +24 -0
  120. data/spec/parslet/atoms/scope_spec.rb +26 -0
  121. data/spec/parslet/atoms/sequence_spec.rb +28 -0
  122. data/spec/parslet/atoms/str_spec.rb +15 -0
  123. data/spec/parslet/atoms/visitor_spec.rb +101 -0
  124. data/spec/parslet/atoms_spec.rb +488 -0
  125. data/spec/parslet/convenience_spec.rb +54 -0
  126. data/spec/parslet/error_reporter/contextual_spec.rb +118 -0
  127. data/spec/parslet/error_reporter/deepest_spec.rb +82 -0
  128. data/spec/parslet/error_reporter/tree_spec.rb +7 -0
  129. data/spec/parslet/export_spec.rb +40 -0
  130. data/spec/parslet/expression/treetop_spec.rb +74 -0
  131. data/spec/parslet/minilisp.citrus +29 -0
  132. data/spec/parslet/minilisp.tt +29 -0
  133. data/spec/parslet/parser_spec.rb +36 -0
  134. data/spec/parslet/parslet_spec.rb +38 -0
  135. data/spec/parslet/pattern_spec.rb +272 -0
  136. data/spec/parslet/position_spec.rb +14 -0
  137. data/spec/parslet/rig/rspec_spec.rb +54 -0
  138. data/spec/parslet/scope_spec.rb +45 -0
  139. data/spec/parslet/slice_spec.rb +186 -0
  140. data/spec/parslet/source/line_cache_spec.rb +74 -0
  141. data/spec/parslet/source_spec.rb +210 -0
  142. data/spec/parslet/transform/context_spec.rb +56 -0
  143. data/spec/parslet/transform_spec.rb +183 -0
  144. data/spec/spec_helper.rb +74 -0
  145. data/spec/support/opal.rb +8 -0
  146. data/spec/support/opal.rb.erb +14 -0
  147. data/spec/support/parslet_matchers.rb +96 -0
  148. metadata +240 -0
@@ -0,0 +1,299 @@
1
+ require 'spec_helper'
2
+ require 'fixtures/examples/optimized_erb'
3
+
4
+ RSpec.describe 'Optimized ERB Example' do
5
+ include OptimizedErbExample
6
+
7
+ describe 'OptimizedErbExample::ErbParser' do
8
+ let(:parser) { OptimizedErbExample::ErbParser.new }
9
+
10
+ describe 'basic parsing components' do
11
+ describe '#ruby' do
12
+ it 'parses ruby code until %>' do
13
+ result = parser.ruby.parse('puts "hello"')
14
+ expect(result).to eq({ ruby: 'puts "hello"' })
15
+ end
16
+
17
+ it 'stops at %>' do
18
+ result = parser.ruby.parse('puts "hello"')
19
+ expect(result[:ruby].to_s).to eq('puts "hello"')
20
+ end
21
+
22
+ it 'handles empty ruby code' do
23
+ result = parser.ruby.parse('')
24
+ expect(result).to eq({ ruby: [] })
25
+ end
26
+ end
27
+
28
+ describe '#expression' do
29
+ it 'parses ERB expression syntax' do
30
+ result = parser.expression.parse('= @user.name')
31
+ expect(result).to eq({ expression: { ruby: ' @user.name' } })
32
+ end
33
+
34
+ it 'parses complex expressions' do
35
+ result = parser.expression.parse('= items.map(&:name).join(", ")')
36
+ expect(result[:expression][:ruby].to_s).to eq(' items.map(&:name).join(", ")')
37
+ end
38
+ end
39
+
40
+ describe '#comment' do
41
+ it 'parses ERB comment syntax' do
42
+ result = parser.comment.parse('# This is a comment')
43
+ expect(result).to eq({ comment: { ruby: ' This is a comment' } })
44
+ end
45
+
46
+ it 'parses empty comments' do
47
+ result = parser.comment.parse('#')
48
+ expect(result).to eq({ comment: { ruby: [] } })
49
+ end
50
+ end
51
+
52
+ describe '#code' do
53
+ it 'parses plain ruby code' do
54
+ result = parser.code.parse('if condition')
55
+ expect(result).to eq({ code: { ruby: 'if condition' } })
56
+ end
57
+
58
+ it 'parses multi-statement code' do
59
+ result = parser.code.parse('x = 1; y = 2')
60
+ expect(result[:code][:ruby].to_s).to eq('x = 1; y = 2')
61
+ end
62
+ end
63
+
64
+ describe '#erb' do
65
+ it 'parses expressions' do
66
+ result = parser.erb.parse('= @name')
67
+ expect(result).to eq({ expression: { ruby: ' @name' } })
68
+ end
69
+
70
+ it 'parses comments' do
71
+ result = parser.erb.parse('# comment')
72
+ expect(result).to eq({ comment: { ruby: ' comment' } })
73
+ end
74
+
75
+ it 'parses code' do
76
+ result = parser.erb.parse('puts "hello"')
77
+ expect(result).to eq({ code: { ruby: 'puts "hello"' } })
78
+ end
79
+ end
80
+
81
+ describe '#erb_with_tags' do
82
+ it 'parses ERB expression with tags' do
83
+ result = parser.erb_with_tags.parse('<%= @user.name %>')
84
+ expect(result).to eq({ expression: { ruby: ' @user.name ' } })
85
+ end
86
+
87
+ it 'parses ERB comment with tags' do
88
+ result = parser.erb_with_tags.parse('<%# This is a comment %>')
89
+ expect(result).to eq({ comment: { ruby: ' This is a comment ' } })
90
+ end
91
+
92
+ it 'parses ERB code with tags' do
93
+ result = parser.erb_with_tags.parse('<% if condition %>')
94
+ expect(result).to eq({ code: { ruby: ' if condition ' } })
95
+ end
96
+ end
97
+
98
+ describe '#text' do
99
+ it 'parses plain text' do
100
+ result = parser.text.parse('Hello World')
101
+ expect(result.to_s).to eq('Hello World')
102
+ end
103
+
104
+ it 'parses text with special characters' do
105
+ result = parser.text.parse('Hello! @#$%^&*()')
106
+ expect(result.to_s).to eq('Hello! @#$%^&*()')
107
+ end
108
+
109
+ it 'stops at ERB tags' do
110
+ result = parser.text.parse('Hello')
111
+ expect(result.to_s).to eq('Hello')
112
+ end
113
+
114
+ it 'fails on empty string' do
115
+ expect { parser.text.parse('') }.to raise_error(Parslet::ParseFailed)
116
+ end
117
+ end
118
+ end
119
+
120
+ describe 'integration parsing' do
121
+ describe '#text_with_ruby (root)' do
122
+ it 'parses plain text only' do
123
+ result = parser.parse('Hello World')
124
+ expect(result).to eq({ text: [{ text: 'Hello World' }] })
125
+ end
126
+
127
+ it 'parses ERB expression only' do
128
+ result = parser.parse('<%= @name %>')
129
+ expect(result).to eq({ text: [{ expression: { ruby: ' @name ' } }] })
130
+ end
131
+
132
+ it 'parses mixed text and ERB' do
133
+ result = parser.parse('Hello <%= @name %>!')
134
+ expect(result).to eq({
135
+ text: [
136
+ { text: 'Hello ' },
137
+ { expression: { ruby: ' @name ' } },
138
+ { text: '!' }
139
+ ]
140
+ })
141
+ end
142
+
143
+ it 'parses multiple ERB tags' do
144
+ result = parser.parse('<%= @first %> and <%= @second %>')
145
+ expect(result).to eq({
146
+ text: [
147
+ { expression: { ruby: ' @first ' } },
148
+ { text: ' and ' },
149
+ { expression: { ruby: ' @second ' } }
150
+ ]
151
+ })
152
+ end
153
+
154
+ it 'parses ERB comments' do
155
+ result = parser.parse('Before <%# comment %> After')
156
+ expect(result).to eq({
157
+ text: [
158
+ { text: 'Before ' },
159
+ { comment: { ruby: ' comment ' } },
160
+ { text: ' After' }
161
+ ]
162
+ })
163
+ end
164
+
165
+ it 'parses ERB code blocks' do
166
+ result = parser.parse('Before <% code %> After')
167
+ expect(result).to eq({
168
+ text: [
169
+ { text: 'Before ' },
170
+ { code: { ruby: ' code ' } },
171
+ { text: ' After' }
172
+ ]
173
+ })
174
+ end
175
+ end
176
+ end
177
+
178
+ describe 'complex examples' do
179
+ it 'parses a simple ERB template' do
180
+ template = <<~ERB
181
+ <h1>Welcome <%= @user.name %>!</h1>
182
+ <p>You have <%= @messages.count %> messages.</p>
183
+ ERB
184
+
185
+ result = parser.parse(template)
186
+ expect(result[:text]).to be_an(Array)
187
+ expect(result[:text].length).to be > 3
188
+
189
+ # Check that we have the expected ERB expressions
190
+ erb_expressions = result[:text].select { |item| item.key?(:expression) }
191
+ expect(erb_expressions.length).to eq(2)
192
+ expect(erb_expressions[0][:expression][:ruby].to_s).to include('@user.name')
193
+ expect(erb_expressions[1][:expression][:ruby].to_s).to include('@messages.count')
194
+ end
195
+
196
+ it 'parses ERB with different tag types' do
197
+ template = <<~ERB
198
+ <%# This is a comment %>
199
+ <% if @user %>
200
+ Hello <%= @user.name %>!
201
+ <% end %>
202
+ ERB
203
+
204
+ result = parser.parse(template)
205
+ expect(result[:text]).to be_an(Array)
206
+
207
+ # Should contain comment, code, expression, and text elements
208
+ has_comment = result[:text].any? { |item| item.key?(:comment) }
209
+ has_code = result[:text].any? { |item| item.key?(:code) }
210
+ has_expression = result[:text].any? { |item| item.key?(:expression) }
211
+ has_text = result[:text].any? { |item| item.key?(:text) }
212
+
213
+ expect(has_comment).to be true
214
+ expect(has_code).to be true
215
+ expect(has_expression).to be true
216
+ expect(has_text).to be true
217
+ end
218
+ end
219
+
220
+ describe 'big.erb file parsing' do
221
+ it 'successfully parses the big.erb file' do
222
+ result = OptimizedErbExample.parse_big_erb_file
223
+ expect(result).to be_a(Hash)
224
+ expect(result[:text]).to be_an(Array)
225
+ expect(result[:text].length).to be > 1
226
+
227
+ # Should contain the ERB expression from the file
228
+ erb_expressions = result[:text].select { |item| item.key?(:expression) }
229
+ expect(erb_expressions.length).to eq(1)
230
+ expect(erb_expressions[0][:expression][:ruby].to_s).to include('erb tag')
231
+ end
232
+
233
+ it 'handles large text content efficiently' do
234
+ # This test demonstrates the optimization aspect
235
+ expect { OptimizedErbExample.parse_big_erb_file }.not_to raise_error
236
+ end
237
+ end
238
+
239
+ describe 'error handling' do
240
+ it 'handles malformed ERB tags' do
241
+ expect { parser.parse('<%') }.to raise_error(Parslet::ParseFailed)
242
+ end
243
+
244
+ it 'handles unclosed ERB tags' do
245
+ expect { parser.parse('<% code') }.to raise_error(Parslet::ParseFailed)
246
+ end
247
+
248
+ it 'provides meaningful error messages' do
249
+ begin
250
+ parser.parse('<%')
251
+ fail 'Expected ParseFailed to be raised'
252
+ rescue Parslet::ParseFailed => e
253
+ expect(e.message).to include('Extra input after last repetition')
254
+ end
255
+ end
256
+ end
257
+
258
+ describe 'edge cases' do
259
+ it 'handles empty input' do
260
+ result = parser.parse('')
261
+ expect(result).to eq({ text: [] })
262
+ end
263
+
264
+ it 'handles whitespace only' do
265
+ result = parser.parse(' ')
266
+ expect(result).to eq({ text: [{ text: ' ' }] })
267
+ end
268
+
269
+ it 'handles nested angle brackets in text' do
270
+ result = parser.parse('This < that > other')
271
+ expect(result).to eq({ text: [{ text: 'This < that > other' }] })
272
+ end
273
+
274
+ it 'handles percent signs in text' do
275
+ result = parser.parse('100% complete')
276
+ expect(result).to eq({ text: [{ text: '100% complete' }] })
277
+ end
278
+ end
279
+ end
280
+
281
+ describe 'module methods' do
282
+ describe '.parse_erb_content' do
283
+ it 'parses ERB content using the parser' do
284
+ content = 'Hello <%= @world %>!'
285
+ result = OptimizedErbExample.parse_erb_content(content)
286
+ expect(result[:text]).to be_an(Array)
287
+ expect(result[:text].length).to eq(3)
288
+ end
289
+ end
290
+
291
+ describe '.parse_big_erb_file' do
292
+ it 'reads and parses the big.erb file' do
293
+ result = OptimizedErbExample.parse_big_erb_file
294
+ expect(result).to be_a(Hash)
295
+ expect(result[:text]).to be_an(Array)
296
+ end
297
+ end
298
+ end
299
+ end
@@ -0,0 +1,239 @@
1
+ require 'spec_helper'
2
+ require_relative '../fixtures/examples/parens'
3
+
4
+ RSpec.describe 'Parens Example' do
5
+ let(:parser) { LISP::Parser.new }
6
+ let(:transform) { LISP::Transform.new }
7
+
8
+ describe LISP::Parser do
9
+ describe '#balanced (root)' do
10
+ it 'parses empty parentheses' do
11
+ result = parser.parse('()')
12
+ expected = {
13
+ l: '(',
14
+ m: nil,
15
+ r: ')'
16
+ }
17
+ expect(result).to parse_as(expected)
18
+ end
19
+
20
+ it 'parses nested parentheses' do
21
+ result = parser.parse('(())')
22
+ expected = {
23
+ l: '(',
24
+ m: {
25
+ l: '(',
26
+ m: nil,
27
+ r: ')'
28
+ },
29
+ r: ')'
30
+ }
31
+ expect(result).to parse_as(expected)
32
+ end
33
+
34
+ it 'parses deeply nested parentheses' do
35
+ result = parser.parse('((((()))))')
36
+ expected = {
37
+ l: '(',
38
+ m: {
39
+ l: '(',
40
+ m: {
41
+ l: '(',
42
+ m: {
43
+ l: '(',
44
+ m: {
45
+ l: '(',
46
+ m: nil,
47
+ r: ')'
48
+ },
49
+ r: ')'
50
+ },
51
+ r: ')'
52
+ },
53
+ r: ')'
54
+ },
55
+ r: ')'
56
+ }
57
+ expect(result).to parse_as(expected)
58
+ end
59
+
60
+ it 'fails on unbalanced parentheses' do
61
+ expect { parser.parse('((())') }.to raise_error(Parslet::ParseFailed)
62
+ end
63
+
64
+ it 'fails on mismatched parentheses' do
65
+ expect { parser.parse('()(') }.to raise_error(Parslet::ParseFailed)
66
+ end
67
+
68
+ it 'fails on extra closing parentheses' do
69
+ expect { parser.parse('())') }.to raise_error(Parslet::ParseFailed)
70
+ end
71
+
72
+ it 'fails on just opening parenthesis' do
73
+ expect { parser.parse('(') }.to raise_error(Parslet::ParseFailed)
74
+ end
75
+
76
+ it 'fails on just closing parenthesis' do
77
+ expect { parser.parse(')') }.to raise_error(Parslet::ParseFailed)
78
+ end
79
+
80
+ it 'fails on empty string' do
81
+ expect { parser.parse('') }.to raise_error(Parslet::ParseFailed)
82
+ end
83
+
84
+ it 'parses triple nested parentheses' do
85
+ result = parser.parse('((()))')
86
+ expected = {
87
+ l: '(',
88
+ m: {
89
+ l: '(',
90
+ m: {
91
+ l: '(',
92
+ m: nil,
93
+ r: ')'
94
+ },
95
+ r: ')'
96
+ },
97
+ r: ')'
98
+ }
99
+ expect(result).to parse_as(expected)
100
+ end
101
+ end
102
+ end
103
+
104
+ describe LISP::Transform do
105
+ describe 'counting parentheses levels' do
106
+ it 'counts single level as 1' do
107
+ tree = { l: '(', m: nil, r: ')' }
108
+ result = transform.apply(tree)
109
+ expect(result).to eq(1)
110
+ end
111
+
112
+ it 'counts two levels as 2' do
113
+ tree = {
114
+ l: '(',
115
+ m: { l: '(', m: nil, r: ')' },
116
+ r: ')'
117
+ }
118
+ result = transform.apply(tree)
119
+ expect(result).to eq(2)
120
+ end
121
+
122
+ it 'counts three levels as 3' do
123
+ tree = {
124
+ l: '(',
125
+ m: {
126
+ l: '(',
127
+ m: { l: '(', m: nil, r: ')' },
128
+ r: ')'
129
+ },
130
+ r: ')'
131
+ }
132
+ result = transform.apply(tree)
133
+ expect(result).to eq(3)
134
+ end
135
+
136
+ it 'counts five levels as 5' do
137
+ tree = {
138
+ l: '(',
139
+ m: {
140
+ l: '(',
141
+ m: {
142
+ l: '(',
143
+ m: {
144
+ l: '(',
145
+ m: { l: '(', m: nil, r: ')' },
146
+ r: ')'
147
+ },
148
+ r: ')'
149
+ },
150
+ r: ')'
151
+ },
152
+ r: ')'
153
+ }
154
+ result = transform.apply(tree)
155
+ expect(result).to eq(5)
156
+ end
157
+ end
158
+ end
159
+
160
+ describe 'integration tests' do
161
+ it 'processes () correctly' do
162
+ tree = parser.parse('()')
163
+ count = transform.apply(tree)
164
+ expect(count).to eq(1)
165
+ end
166
+
167
+ it 'processes (()) correctly' do
168
+ tree = parser.parse('(())')
169
+ count = transform.apply(tree)
170
+ expect(count).to eq(2)
171
+ end
172
+
173
+ it 'processes (((((()))))) correctly' do
174
+ tree = parser.parse('((((()))))')
175
+ count = transform.apply(tree)
176
+ expect(count).to eq(5)
177
+ end
178
+
179
+ it 'fails on unbalanced ((()) correctly' do
180
+ expect { parser.parse('((())') }.to raise_error(Parslet::ParseFailed, /Failed to match/)
181
+ end
182
+
183
+ it 'produces the expected outputs from the example file' do
184
+ # Test case 1: ()
185
+ tree1 = parser.parse('()')
186
+ expected1 = { l: '(', m: nil, r: ')' }
187
+ expect(tree1).to parse_as(expected1)
188
+ expect(transform.apply(tree1)).to eq(1)
189
+
190
+ # Test case 2: (())
191
+ tree2 = parser.parse('(())')
192
+ expected2 = {
193
+ l: '(',
194
+ m: { l: '(', m: nil, r: ')' },
195
+ r: ')'
196
+ }
197
+ expect(tree2).to parse_as(expected2)
198
+ expect(transform.apply(tree2)).to eq(2)
199
+
200
+ # Test case 3: (((((())))))
201
+ tree3 = parser.parse('((((()))))')
202
+ expected3 = {
203
+ l: '(',
204
+ m: {
205
+ l: '(',
206
+ m: {
207
+ l: '(',
208
+ m: {
209
+ l: '(',
210
+ m: { l: '(', m: nil, r: ')' },
211
+ r: ')'
212
+ },
213
+ r: ')'
214
+ },
215
+ r: ')'
216
+ },
217
+ r: ')'
218
+ }
219
+ expect(tree3).to parse_as(expected3)
220
+ expect(transform.apply(tree3)).to eq(5)
221
+
222
+ # Test case 4: ((()) - should fail
223
+ expect { parser.parse('((())') }.to raise_error(Parslet::ParseFailed)
224
+ end
225
+
226
+ it 'demonstrates the power of tree pattern matching' do
227
+ # Simple case
228
+ simple_tree = parser.parse('()')
229
+ expect(transform.apply(simple_tree)).to eq(1)
230
+
231
+ # Complex nested case
232
+ complex_tree = parser.parse('(((())))')
233
+ expect(transform.apply(complex_tree)).to eq(4)
234
+
235
+ # The transform correctly counts nesting levels
236
+ # by recursively applying the rule that adds 1 for each level
237
+ end
238
+ end
239
+ end