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.
- checksums.yaml +7 -0
- data/HISTORY.txt +284 -0
- data/LICENSE +23 -0
- data/README.adoc +454 -0
- data/Rakefile +71 -0
- data/lib/parslet/accelerator/application.rb +62 -0
- data/lib/parslet/accelerator/engine.rb +112 -0
- data/lib/parslet/accelerator.rb +162 -0
- data/lib/parslet/atoms/alternative.rb +53 -0
- data/lib/parslet/atoms/base.rb +157 -0
- data/lib/parslet/atoms/can_flatten.rb +137 -0
- data/lib/parslet/atoms/capture.rb +38 -0
- data/lib/parslet/atoms/context.rb +103 -0
- data/lib/parslet/atoms/dsl.rb +112 -0
- data/lib/parslet/atoms/dynamic.rb +32 -0
- data/lib/parslet/atoms/entity.rb +45 -0
- data/lib/parslet/atoms/ignored.rb +26 -0
- data/lib/parslet/atoms/infix.rb +115 -0
- data/lib/parslet/atoms/lookahead.rb +52 -0
- data/lib/parslet/atoms/named.rb +32 -0
- data/lib/parslet/atoms/re.rb +41 -0
- data/lib/parslet/atoms/repetition.rb +87 -0
- data/lib/parslet/atoms/scope.rb +26 -0
- data/lib/parslet/atoms/sequence.rb +48 -0
- data/lib/parslet/atoms/str.rb +42 -0
- data/lib/parslet/atoms/visitor.rb +89 -0
- data/lib/parslet/atoms.rb +34 -0
- data/lib/parslet/cause.rb +101 -0
- data/lib/parslet/context.rb +21 -0
- data/lib/parslet/convenience.rb +33 -0
- data/lib/parslet/error_reporter/contextual.rb +120 -0
- data/lib/parslet/error_reporter/deepest.rb +100 -0
- data/lib/parslet/error_reporter/tree.rb +63 -0
- data/lib/parslet/error_reporter.rb +8 -0
- data/lib/parslet/export.rb +163 -0
- data/lib/parslet/expression/treetop.rb +92 -0
- data/lib/parslet/expression.rb +51 -0
- data/lib/parslet/graphviz.rb +97 -0
- data/lib/parslet/parser.rb +68 -0
- data/lib/parslet/pattern/binding.rb +49 -0
- data/lib/parslet/pattern.rb +113 -0
- data/lib/parslet/position.rb +21 -0
- data/lib/parslet/rig/rspec.rb +52 -0
- data/lib/parslet/scope.rb +42 -0
- data/lib/parslet/slice.rb +105 -0
- data/lib/parslet/source/line_cache.rb +99 -0
- data/lib/parslet/source.rb +96 -0
- data/lib/parslet/transform.rb +265 -0
- data/lib/parslet/version.rb +5 -0
- data/lib/parslet.rb +314 -0
- data/plurimath-parslet.gemspec +42 -0
- data/spec/acceptance/infix_parser_spec.rb +145 -0
- data/spec/acceptance/mixing_parsers_spec.rb +74 -0
- data/spec/acceptance/regression_spec.rb +329 -0
- data/spec/acceptance/repetition_and_maybe_spec.rb +44 -0
- data/spec/acceptance/unconsumed_input_spec.rb +21 -0
- data/spec/examples/boolean_algebra_spec.rb +257 -0
- data/spec/examples/calc_spec.rb +278 -0
- data/spec/examples/capture_spec.rb +137 -0
- data/spec/examples/comments_spec.rb +186 -0
- data/spec/examples/deepest_errors_spec.rb +420 -0
- data/spec/examples/documentation_spec.rb +205 -0
- data/spec/examples/email_parser_spec.rb +275 -0
- data/spec/examples/empty_spec.rb +37 -0
- data/spec/examples/erb_spec.rb +482 -0
- data/spec/examples/ip_address_spec.rb +153 -0
- data/spec/examples/json_spec.rb +413 -0
- data/spec/examples/local_spec.rb +302 -0
- data/spec/examples/mathn_spec.rb +151 -0
- data/spec/examples/minilisp_spec.rb +492 -0
- data/spec/examples/modularity_spec.rb +340 -0
- data/spec/examples/nested_errors_spec.rb +322 -0
- data/spec/examples/optimized_erb_spec.rb +299 -0
- data/spec/examples/parens_spec.rb +239 -0
- data/spec/examples/prec_calc_spec.rb +525 -0
- data/spec/examples/readme_spec.rb +228 -0
- data/spec/examples/scopes_spec.rb +187 -0
- data/spec/examples/seasons_spec.rb +196 -0
- data/spec/examples/sentence_spec.rb +119 -0
- data/spec/examples/simple_xml_spec.rb +250 -0
- data/spec/examples/string_parser_spec.rb +407 -0
- data/spec/fixtures/examples/boolean_algebra.rb +62 -0
- data/spec/fixtures/examples/calc.rb +86 -0
- data/spec/fixtures/examples/capture.rb +36 -0
- data/spec/fixtures/examples/comments.rb +22 -0
- data/spec/fixtures/examples/deepest_errors.rb +99 -0
- data/spec/fixtures/examples/documentation.rb +32 -0
- data/spec/fixtures/examples/email_parser.rb +42 -0
- data/spec/fixtures/examples/empty.rb +10 -0
- data/spec/fixtures/examples/erb.rb +39 -0
- data/spec/fixtures/examples/ip_address.rb +103 -0
- data/spec/fixtures/examples/json.rb +107 -0
- data/spec/fixtures/examples/local.rb +60 -0
- data/spec/fixtures/examples/mathn.rb +47 -0
- data/spec/fixtures/examples/minilisp.rb +75 -0
- data/spec/fixtures/examples/modularity.rb +60 -0
- data/spec/fixtures/examples/nested_errors.rb +95 -0
- data/spec/fixtures/examples/optimized_erb.rb +105 -0
- data/spec/fixtures/examples/parens.rb +25 -0
- data/spec/fixtures/examples/prec_calc.rb +71 -0
- data/spec/fixtures/examples/readme.rb +59 -0
- data/spec/fixtures/examples/scopes.rb +43 -0
- data/spec/fixtures/examples/seasons.rb +40 -0
- data/spec/fixtures/examples/sentence.rb +18 -0
- data/spec/fixtures/examples/simple_xml.rb +51 -0
- data/spec/fixtures/examples/string_parser.rb +77 -0
- data/spec/parslet/atom_results_spec.rb +39 -0
- data/spec/parslet/atoms/alternative_spec.rb +26 -0
- data/spec/parslet/atoms/base_spec.rb +127 -0
- data/spec/parslet/atoms/capture_spec.rb +21 -0
- data/spec/parslet/atoms/combinations_spec.rb +5 -0
- data/spec/parslet/atoms/dsl_spec.rb +7 -0
- data/spec/parslet/atoms/entity_spec.rb +77 -0
- data/spec/parslet/atoms/ignored_spec.rb +15 -0
- data/spec/parslet/atoms/infix_spec.rb +5 -0
- data/spec/parslet/atoms/lookahead_spec.rb +22 -0
- data/spec/parslet/atoms/named_spec.rb +4 -0
- data/spec/parslet/atoms/re_spec.rb +14 -0
- data/spec/parslet/atoms/repetition_spec.rb +24 -0
- data/spec/parslet/atoms/scope_spec.rb +26 -0
- data/spec/parslet/atoms/sequence_spec.rb +28 -0
- data/spec/parslet/atoms/str_spec.rb +15 -0
- data/spec/parslet/atoms/visitor_spec.rb +101 -0
- data/spec/parslet/atoms_spec.rb +488 -0
- data/spec/parslet/convenience_spec.rb +54 -0
- data/spec/parslet/error_reporter/contextual_spec.rb +118 -0
- data/spec/parslet/error_reporter/deepest_spec.rb +82 -0
- data/spec/parslet/error_reporter/tree_spec.rb +7 -0
- data/spec/parslet/export_spec.rb +40 -0
- data/spec/parslet/expression/treetop_spec.rb +74 -0
- data/spec/parslet/minilisp.citrus +29 -0
- data/spec/parslet/minilisp.tt +29 -0
- data/spec/parslet/parser_spec.rb +36 -0
- data/spec/parslet/parslet_spec.rb +38 -0
- data/spec/parslet/pattern_spec.rb +272 -0
- data/spec/parslet/position_spec.rb +14 -0
- data/spec/parslet/rig/rspec_spec.rb +54 -0
- data/spec/parslet/scope_spec.rb +45 -0
- data/spec/parslet/slice_spec.rb +186 -0
- data/spec/parslet/source/line_cache_spec.rb +74 -0
- data/spec/parslet/source_spec.rb +210 -0
- data/spec/parslet/transform/context_spec.rb +56 -0
- data/spec/parslet/transform_spec.rb +183 -0
- data/spec/spec_helper.rb +74 -0
- data/spec/support/opal.rb +8 -0
- data/spec/support/opal.rb.erb +14 -0
- data/spec/support/parslet_matchers.rb +96 -0
- metadata +240 -0
@@ -0,0 +1,492 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require_relative '../fixtures/examples/minilisp'
|
3
|
+
|
4
|
+
RSpec.describe 'MiniLisp Parser Example' do
|
5
|
+
let(:parser) { MiniLisp::Parser.new }
|
6
|
+
let(:transform) { MiniLisp::Transform.new }
|
7
|
+
|
8
|
+
describe MiniLisp::Parser do
|
9
|
+
describe '#space' do
|
10
|
+
it 'parses single space' do
|
11
|
+
result = parser.space.parse(' ')
|
12
|
+
expect(result).to eq(' ')
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'parses multiple spaces' do
|
16
|
+
result = parser.space.parse(' ')
|
17
|
+
expect(result).to eq(' ')
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'parses tabs and newlines' do
|
21
|
+
result = parser.space.parse("\t\n ")
|
22
|
+
expect(result).to eq("\t\n ")
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'fails on empty string' do
|
26
|
+
expect { parser.space.parse('') }.to raise_error(Parslet::ParseFailed)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe '#space?' do
|
31
|
+
it 'parses optional space' do
|
32
|
+
result = parser.space?.parse(' ')
|
33
|
+
expect(result).to eq(' ')
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'parses empty string' do
|
37
|
+
result = parser.space?.parse('')
|
38
|
+
expect(result).to eq('')
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'parses multiple spaces' do
|
42
|
+
result = parser.space?.parse(' ')
|
43
|
+
expect(result).to eq(' ')
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe '#identifier' do
|
48
|
+
it 'parses simple identifier' do
|
49
|
+
result = parser.identifier.parse('test')
|
50
|
+
expected = { identifier: 'test' }
|
51
|
+
expect(result).to parse_as(expected)
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'parses identifier with underscores' do
|
55
|
+
result = parser.identifier.parse('test_var')
|
56
|
+
expected = { identifier: 'test_var' }
|
57
|
+
expect(result).to parse_as(expected)
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'parses identifier with equals' do
|
61
|
+
result = parser.identifier.parse('=')
|
62
|
+
expected = { identifier: '=' }
|
63
|
+
expect(result).to parse_as(expected)
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'parses identifier with asterisk' do
|
67
|
+
result = parser.identifier.parse('*global*')
|
68
|
+
expected = { identifier: '*global*' }
|
69
|
+
expect(result).to parse_as(expected)
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'parses identifier with trailing space' do
|
73
|
+
result = parser.identifier.parse('test ')
|
74
|
+
expected = { identifier: 'test' }
|
75
|
+
expect(result).to parse_as(expected)
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'parses mixed case identifier' do
|
79
|
+
result = parser.identifier.parse('TestVar')
|
80
|
+
expected = { identifier: 'TestVar' }
|
81
|
+
expect(result).to parse_as(expected)
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'fails on identifier starting with number' do
|
85
|
+
expect { parser.identifier.parse('1test') }.to raise_error(Parslet::ParseFailed)
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'fails on empty string' do
|
89
|
+
expect { parser.identifier.parse('') }.to raise_error(Parslet::ParseFailed)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
describe '#integer' do
|
94
|
+
it 'parses positive integer' do
|
95
|
+
result = parser.integer.parse('123')
|
96
|
+
expected = { integer: '123' }
|
97
|
+
expect(result).to parse_as(expected)
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'parses negative integer' do
|
101
|
+
result = parser.integer.parse('-123')
|
102
|
+
expected = { integer: '-123' }
|
103
|
+
expect(result).to parse_as(expected)
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'parses integer with plus sign' do
|
107
|
+
result = parser.integer.parse('+123')
|
108
|
+
expected = { integer: '+123' }
|
109
|
+
expect(result).to parse_as(expected)
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'parses single digit' do
|
113
|
+
result = parser.integer.parse('5')
|
114
|
+
expected = { integer: '5' }
|
115
|
+
expect(result).to parse_as(expected)
|
116
|
+
end
|
117
|
+
|
118
|
+
it 'parses zero' do
|
119
|
+
result = parser.integer.parse('0')
|
120
|
+
expected = { integer: '0' }
|
121
|
+
expect(result).to parse_as(expected)
|
122
|
+
end
|
123
|
+
|
124
|
+
it 'parses integer with trailing space' do
|
125
|
+
result = parser.integer.parse('123 ')
|
126
|
+
expected = { integer: '123' }
|
127
|
+
expect(result).to parse_as(expected)
|
128
|
+
end
|
129
|
+
|
130
|
+
it 'fails on empty string' do
|
131
|
+
expect { parser.integer.parse('') }.to raise_error(Parslet::ParseFailed)
|
132
|
+
end
|
133
|
+
|
134
|
+
it 'fails on just sign' do
|
135
|
+
expect { parser.integer.parse('+') }.to raise_error(Parslet::ParseFailed)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
describe '#float' do
|
140
|
+
it 'parses decimal float' do
|
141
|
+
result = parser.float.parse('123.45')
|
142
|
+
expected = { float: { integer: '123', e: '.45' } }
|
143
|
+
expect(result).to parse_as(expected)
|
144
|
+
end
|
145
|
+
|
146
|
+
it 'parses scientific notation' do
|
147
|
+
result = parser.float.parse('123e45')
|
148
|
+
expected = { float: { integer: '123', e: 'e45' } }
|
149
|
+
expect(result).to parse_as(expected)
|
150
|
+
end
|
151
|
+
|
152
|
+
it 'parses negative float' do
|
153
|
+
result = parser.float.parse('-123.45')
|
154
|
+
expected = { float: { integer: '-123', e: '.45' } }
|
155
|
+
expect(result).to parse_as(expected)
|
156
|
+
end
|
157
|
+
|
158
|
+
it 'parses float with plus sign' do
|
159
|
+
result = parser.float.parse('+123.45')
|
160
|
+
expected = { float: { integer: '+123', e: '.45' } }
|
161
|
+
expect(result).to parse_as(expected)
|
162
|
+
end
|
163
|
+
|
164
|
+
it 'parses float with trailing space' do
|
165
|
+
result = parser.float.parse('123.45 ')
|
166
|
+
expected = { float: { integer: '123', e: '.45' } }
|
167
|
+
expect(result).to parse_as(expected)
|
168
|
+
end
|
169
|
+
|
170
|
+
it 'parses zero float' do
|
171
|
+
result = parser.float.parse('0.0')
|
172
|
+
expected = { float: { integer: '0', e: '.0' } }
|
173
|
+
expect(result).to parse_as(expected)
|
174
|
+
end
|
175
|
+
|
176
|
+
it 'fails on integer without decimal part' do
|
177
|
+
expect { parser.float.parse('123') }.to raise_error(Parslet::ParseFailed)
|
178
|
+
end
|
179
|
+
|
180
|
+
it 'fails on decimal point without digits' do
|
181
|
+
expect { parser.float.parse('123.') }.to raise_error(Parslet::ParseFailed)
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
describe '#string' do
|
186
|
+
it 'parses simple string' do
|
187
|
+
result = parser.string.parse('"hello"')
|
188
|
+
expected = { string: 'hello' }
|
189
|
+
expect(result).to parse_as(expected)
|
190
|
+
end
|
191
|
+
|
192
|
+
it 'parses empty string' do
|
193
|
+
result = parser.string.parse('""')
|
194
|
+
expected = { string: [] }
|
195
|
+
expect(result).to parse_as(expected)
|
196
|
+
end
|
197
|
+
|
198
|
+
it 'parses string with spaces' do
|
199
|
+
result = parser.string.parse('"hello world"')
|
200
|
+
expected = { string: 'hello world' }
|
201
|
+
expect(result).to parse_as(expected)
|
202
|
+
end
|
203
|
+
|
204
|
+
it 'parses string with trailing space' do
|
205
|
+
result = parser.string.parse('"hello" ')
|
206
|
+
expected = { string: 'hello' }
|
207
|
+
expect(result).to parse_as(expected)
|
208
|
+
end
|
209
|
+
|
210
|
+
it 'parses string with numbers' do
|
211
|
+
result = parser.string.parse('"test123"')
|
212
|
+
expected = { string: 'test123' }
|
213
|
+
expect(result).to parse_as(expected)
|
214
|
+
end
|
215
|
+
|
216
|
+
it 'fails on unclosed string' do
|
217
|
+
expect { parser.string.parse('"hello') }.to raise_error(Parslet::ParseFailed)
|
218
|
+
end
|
219
|
+
|
220
|
+
it 'fails on string without opening quote' do
|
221
|
+
expect { parser.string.parse('hello"') }.to raise_error(Parslet::ParseFailed)
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
describe '#body' do
|
226
|
+
it 'parses single identifier' do
|
227
|
+
result = parser.body.parse('test')
|
228
|
+
expected = { exp: [{ identifier: 'test' }] }
|
229
|
+
expect(result).to parse_as(expected)
|
230
|
+
end
|
231
|
+
|
232
|
+
it 'parses multiple identifiers' do
|
233
|
+
result = parser.body.parse('test var')
|
234
|
+
expected = { exp: [{ identifier: 'test' }, { identifier: 'var' }] }
|
235
|
+
expect(result).to parse_as(expected)
|
236
|
+
end
|
237
|
+
|
238
|
+
it 'parses mixed types' do
|
239
|
+
result = parser.body.parse('test 123 "hello"')
|
240
|
+
expected = {
|
241
|
+
exp: [
|
242
|
+
{ identifier: 'test' },
|
243
|
+
{ integer: '123' },
|
244
|
+
{ string: 'hello' }
|
245
|
+
]
|
246
|
+
}
|
247
|
+
expect(result).to parse_as(expected)
|
248
|
+
end
|
249
|
+
|
250
|
+
it 'parses nested expression' do
|
251
|
+
result = parser.body.parse('(test)')
|
252
|
+
expected = {
|
253
|
+
exp: [
|
254
|
+
{ exp: [{ identifier: 'test' }] }
|
255
|
+
]
|
256
|
+
}
|
257
|
+
expect(result).to parse_as(expected)
|
258
|
+
end
|
259
|
+
|
260
|
+
it 'parses empty body' do
|
261
|
+
result = parser.body.parse('')
|
262
|
+
expected = { exp: [] }
|
263
|
+
expect(result).to parse_as(expected)
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
describe '#expression (root)' do
|
268
|
+
it 'parses simple expression' do
|
269
|
+
result = parser.parse('(test)')
|
270
|
+
expected = { exp: [{ identifier: 'test' }] }
|
271
|
+
expect(result).to parse_as(expected)
|
272
|
+
end
|
273
|
+
|
274
|
+
it 'parses expression with string' do
|
275
|
+
result = parser.parse('(display "hello")')
|
276
|
+
expected = {
|
277
|
+
exp: [
|
278
|
+
{ identifier: 'display' },
|
279
|
+
{ string: 'hello' }
|
280
|
+
]
|
281
|
+
}
|
282
|
+
expect(result).to parse_as(expected)
|
283
|
+
end
|
284
|
+
|
285
|
+
it 'parses empty expression' do
|
286
|
+
result = parser.parse('()')
|
287
|
+
expected = { exp: [] }
|
288
|
+
expect(result).to parse_as(expected)
|
289
|
+
end
|
290
|
+
|
291
|
+
it 'handles whitespace around expression' do
|
292
|
+
result = parser.parse(' ( test ) ')
|
293
|
+
expected = { exp: [{ identifier: 'test' }] }
|
294
|
+
expect(result).to parse_as(expected)
|
295
|
+
end
|
296
|
+
|
297
|
+
it 'fails on unclosed expression' do
|
298
|
+
expect { parser.parse('(test') }.to raise_error(Parslet::ParseFailed)
|
299
|
+
end
|
300
|
+
|
301
|
+
it 'fails on expression without opening paren' do
|
302
|
+
expect { parser.parse('test)') }.to raise_error(Parslet::ParseFailed)
|
303
|
+
end
|
304
|
+
|
305
|
+
it 'fails on mismatched parens' do
|
306
|
+
expect { parser.parse('(test))') }.to raise_error(Parslet::ParseFailed)
|
307
|
+
end
|
308
|
+
end
|
309
|
+
|
310
|
+
describe 'error handling' do
|
311
|
+
it 'provides meaningful error for invalid syntax' do
|
312
|
+
expect { parser.parse('(test invalid@symbol)') }.to raise_error(Parslet::ParseFailed)
|
313
|
+
end
|
314
|
+
|
315
|
+
it 'handles unclosed strings in expressions' do
|
316
|
+
expect { parser.parse('(test "unclosed)') }.to raise_error(Parslet::ParseFailed)
|
317
|
+
end
|
318
|
+
end
|
319
|
+
end
|
320
|
+
|
321
|
+
describe MiniLisp::Transform do
|
322
|
+
describe 'identifier transformation' do
|
323
|
+
it 'transforms identifier to symbol' do
|
324
|
+
parsed = { identifier: 'test' }
|
325
|
+
result = transform.do(parsed)
|
326
|
+
expect(result).to eq(:test)
|
327
|
+
end
|
328
|
+
|
329
|
+
it 'transforms special identifiers' do
|
330
|
+
parsed = { identifier: '+' }
|
331
|
+
result = transform.do(parsed)
|
332
|
+
expect(result).to eq(:+)
|
333
|
+
end
|
334
|
+
|
335
|
+
it 'transforms identifier with underscores' do
|
336
|
+
parsed = { identifier: 'test_var' }
|
337
|
+
result = transform.do(parsed)
|
338
|
+
expect(result).to eq(:test_var)
|
339
|
+
end
|
340
|
+
end
|
341
|
+
|
342
|
+
describe 'string transformation' do
|
343
|
+
it 'transforms string to string' do
|
344
|
+
parsed = { string: 'hello' }
|
345
|
+
result = transform.do(parsed)
|
346
|
+
expect(result).to eq('hello')
|
347
|
+
end
|
348
|
+
|
349
|
+
it 'transforms empty string' do
|
350
|
+
parsed = { string: [] }
|
351
|
+
result = transform.do(parsed)
|
352
|
+
expect(result).to eq({ string: [] })
|
353
|
+
end
|
354
|
+
|
355
|
+
it 'transforms string with spaces' do
|
356
|
+
parsed = { string: 'hello world' }
|
357
|
+
result = transform.do(parsed)
|
358
|
+
expect(result).to eq('hello world')
|
359
|
+
end
|
360
|
+
end
|
361
|
+
|
362
|
+
describe 'integer transformation' do
|
363
|
+
it 'transforms positive integer' do
|
364
|
+
parsed = { integer: '123' }
|
365
|
+
result = transform.do(parsed)
|
366
|
+
expect(result).to eq(123)
|
367
|
+
end
|
368
|
+
|
369
|
+
it 'transforms negative integer' do
|
370
|
+
parsed = { integer: '-123' }
|
371
|
+
result = transform.do(parsed)
|
372
|
+
expect(result).to eq(-123)
|
373
|
+
end
|
374
|
+
|
375
|
+
it 'transforms zero' do
|
376
|
+
parsed = { integer: '0' }
|
377
|
+
result = transform.do(parsed)
|
378
|
+
expect(result).to eq(0)
|
379
|
+
end
|
380
|
+
|
381
|
+
it 'transforms integer with plus sign' do
|
382
|
+
parsed = { integer: '+123' }
|
383
|
+
result = transform.do(parsed)
|
384
|
+
expect(result).to eq(123)
|
385
|
+
end
|
386
|
+
end
|
387
|
+
|
388
|
+
describe 'float transformation' do
|
389
|
+
it 'transforms decimal float' do
|
390
|
+
parsed = { float: { integer: '123', e: '.45' } }
|
391
|
+
result = transform.do(parsed)
|
392
|
+
expect(result).to eq(123.45)
|
393
|
+
end
|
394
|
+
|
395
|
+
it 'transforms scientific notation' do
|
396
|
+
parsed = { float: { integer: '123', e: 'e45' } }
|
397
|
+
result = transform.do(parsed)
|
398
|
+
expect(result).to eq(123e45)
|
399
|
+
end
|
400
|
+
|
401
|
+
it 'transforms negative float' do
|
402
|
+
parsed = { float: { integer: '-123', e: '.45' } }
|
403
|
+
result = transform.do(parsed)
|
404
|
+
expect(result).to eq(-123.45)
|
405
|
+
end
|
406
|
+
|
407
|
+
it 'transforms zero float' do
|
408
|
+
parsed = { float: { integer: '0', e: '.0' } }
|
409
|
+
result = transform.do(parsed)
|
410
|
+
expect(result).to eq(0.0)
|
411
|
+
end
|
412
|
+
end
|
413
|
+
|
414
|
+
describe 'expression transformation' do
|
415
|
+
it 'transforms expression list' do
|
416
|
+
parsed = { exp: [{ identifier: 'test' }, { integer: '123' }] }
|
417
|
+
result = transform.do(parsed)
|
418
|
+
expect(result).to eq([:test, 123])
|
419
|
+
end
|
420
|
+
|
421
|
+
it 'transforms empty expression' do
|
422
|
+
parsed = { exp: [] }
|
423
|
+
result = transform.do(parsed)
|
424
|
+
expect(result).to eq([])
|
425
|
+
end
|
426
|
+
|
427
|
+
it 'transforms nested expressions' do
|
428
|
+
parsed = {
|
429
|
+
exp: [
|
430
|
+
{ identifier: 'display' },
|
431
|
+
{ exp: [{ identifier: 'test' }] }
|
432
|
+
]
|
433
|
+
}
|
434
|
+
result = transform.do(parsed)
|
435
|
+
expect(result).to eq([:display, [:test]])
|
436
|
+
end
|
437
|
+
end
|
438
|
+
|
439
|
+
describe 'integration transformation' do
|
440
|
+
it 'transforms function call with string' do
|
441
|
+
input = '(display "hello world")'
|
442
|
+
parsed = parser.parse(input)
|
443
|
+
result = transform.do(parsed)
|
444
|
+
expect(result).to eq([:display, "hello world"])
|
445
|
+
end
|
446
|
+
|
447
|
+
it 'transforms simple function call' do
|
448
|
+
input = '(test)'
|
449
|
+
parsed = parser.parse(input)
|
450
|
+
result = transform.do(parsed)
|
451
|
+
expect(result).to eq([:test])
|
452
|
+
end
|
453
|
+
|
454
|
+
it 'transforms nested function calls' do
|
455
|
+
input = '(outer (inner))'
|
456
|
+
parsed = parser.parse(input)
|
457
|
+
result = transform.do(parsed)
|
458
|
+
expect(result).to eq([:outer, [:inner]])
|
459
|
+
end
|
460
|
+
end
|
461
|
+
end
|
462
|
+
|
463
|
+
describe 'parser and transformer integration' do
|
464
|
+
it 'processes simple lisp expression end-to-end' do
|
465
|
+
input = '(test)'
|
466
|
+
parsed = parser.parse(input)
|
467
|
+
result = transform.do(parsed)
|
468
|
+
expect(result).to eq([:test])
|
469
|
+
end
|
470
|
+
|
471
|
+
it 'processes function call with string end-to-end' do
|
472
|
+
input = '(display "hello")'
|
473
|
+
parsed = parser.parse(input)
|
474
|
+
result = transform.do(parsed)
|
475
|
+
expect(result).to eq([:display, "hello"])
|
476
|
+
end
|
477
|
+
|
478
|
+
it 'processes nested expressions end-to-end' do
|
479
|
+
input = '(outer (inner "value"))'
|
480
|
+
parsed = parser.parse(input)
|
481
|
+
result = transform.do(parsed)
|
482
|
+
expect(result).to eq([:outer, [:inner, "value"]])
|
483
|
+
end
|
484
|
+
|
485
|
+
it 'processes empty expression end-to-end' do
|
486
|
+
input = '()'
|
487
|
+
parsed = parser.parse(input)
|
488
|
+
result = transform.do(parsed)
|
489
|
+
expect(result).to eq([])
|
490
|
+
end
|
491
|
+
end
|
492
|
+
end
|