yaparc 0.3.0 → 0.4.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.
data/lib/yaparc.rb CHANGED
@@ -1,617 +1,47 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Yaparc
4
- VERSION = "0.3.0"
5
-
6
- module Result
7
- class Base
8
- attr_accessor :message, :input, :value
9
- def initialize(options = {})
10
- @message = options[:message] if options[:message]
11
- @input = options[:input] if options[:input]
12
- @value = options[:value]
13
- end
14
- end
15
-
16
- class OK < Base
17
- end
18
-
19
- class Fail < Base
20
- end
21
-
22
- class Error < Base
23
- end
24
- end # of module Result
25
-
26
- module Parsable
27
- attr_accessor :tree
28
-
29
- IS_LOWER = lambda {|c| c >= 'a' and c <= 'z'}
30
- IS_ALPHANUM = lambda {|c| (c >= 'a' and c <= 'z') or (c >= '0' and c <= '9')}
31
- IS_DIGIT = lambda {|i| i >= '0' and i <= '9'}
32
- IS_SPACE = lambda {|i| i == ' '}
33
- IS_WHITESPACE = lambda {|i| i == ' ' or i == "\n" or i == "\t"}
34
- IS_CR = lambda {|i| i == "\n"}
35
-
36
- def parse(input) #, &block)
37
- result = @parser.call(input)
38
-
39
- if result.respond_to?(:parse)
40
- result.parse(input)
41
- else
42
- result
43
- end
44
- end
45
-
46
- end # of Module Parsable
47
-
48
- class Succeed
49
- include Parsable
50
- attr_reader :remaining
51
-
52
- def initialize(value, remaining = nil)
53
- @parser = lambda do |input|
54
- Result::OK.new(:value => value, :input => input)
55
- end
56
- @remaining = remaining
57
- end
58
- end
59
-
60
- class Fail
61
- include Parsable
62
- def initialize
63
- @parser = lambda do |input|
64
- Result::Fail.new(:input => input)
65
- end
66
- end
67
- end
68
-
69
-
70
- class Item
71
- include Parsable
72
-
73
- def initialize
74
- @parser = lambda do |input|
75
- if input.nil? or input.empty?
76
- Result::Fail.new(:input => input)
77
- else
78
- Result::OK.new(:value => input[0..0],:input => input[1..input.length])
79
- end
80
- end
81
- end
82
- end
83
-
84
- class ZeroOne
85
- include Parsable
86
-
87
- def initialize(parser, identity = [])
88
- @parser = lambda do |input|
89
- case result = parser.parse(input)
90
- when Result::Fail
91
- Result::OK.new(:value => identity, :input => input)
92
- # Succeed.new(identity)
93
- when Result::Error
94
- Result::Error.new(:value => result.value, :input => result.input)
95
- when Result::OK
96
- result
97
- else
98
- raise
99
- end
100
- end
101
- end
102
- end
103
-
104
- class Satisfy
105
- include Parsable
106
-
107
- def initialize(predicate)
108
- raise unless predicate.instance_of?(Proc)
109
- @parser = lambda do |input|
110
- result = Item.new.parse(input)
111
- if result.instance_of?(Result::OK) and predicate.call(result.value)
112
- Succeed.new(result.value, result.input)
113
- else
114
- Fail.new
115
- end
116
- end
117
- end
118
-
119
- def parse(input)
120
- case parser = @parser.call(input)
121
- when Succeed
122
- parser.parse(parser.remaining)
123
- when Fail
124
- parser.parse(input)
125
- else
126
- raise
127
- end
128
- end
129
- end
130
-
131
-
132
- class NoFail
133
- # hutton92:_higher_order_funct_parsin,p.19
134
- include Parsable
135
-
136
- def initialize(parser, &block)
137
- @parser = lambda do |input|
138
- result = parser.parse(input)
139
- if result.instance_of?(Result::Fail)
140
- Result::Error.new(:value => result.value, :input => result.input)
141
- else
142
- Succeed.new(result.value)
143
- end
144
- end
145
- end
146
- end # of NoFail
147
-
148
-
149
- class Seq
150
- include Parsable
151
-
152
- def initialize(*parsers, &block)
153
- @parser = lambda do |input|
154
- args = []
155
- initial_result = Result::OK.new(:input => input)
156
- final_result = parsers.inject(initial_result) do |subsequent, parser|
157
- result = parser.parse(subsequent.input)
158
- if result.instance_of?(Result::Fail)
159
- break Result::Fail.new(:input => subsequent.input)
160
- else
161
- args << result.value
162
- result
163
- end
164
- end
165
-
166
- case final_result
167
- when Result::Fail
168
- Result::Fail.new(:input => final_result.input)
169
- when Result::OK
170
- final_value = if block_given?
171
- yield(*args)
172
- else
173
- args.last
174
- end
175
- Result::OK.new(:value => final_value, :input => final_result.input)
176
- else
177
- raise
178
- end
179
- end
180
- end # of initialize
181
- end # of Seq
182
-
183
- class Alt
184
- include Parsable
185
- def initialize(*parsers)
186
- @parser = lambda do |input|
187
- final_result = Result::Fail.new(:input => input)
188
- parsers.each do |parser|
189
- case result = parser.parse(input)
190
- when Result::Fail
191
- next
192
- # when Result::Error
193
- # raise
194
- # return Result::Error.new(:value => result.value, :input => result.input)
195
- when Result::OK
196
- break final_result = result
197
- else
198
- raise
199
- end
200
- end
201
- final_result
202
- end
203
- end # of initialize
204
- end
205
-
206
- # class Alt
207
- # include Parsable
208
- # def initialize(*parsers)
209
- # @parser = lambda do |input|
210
- # if head = parsers[0]
211
- # case result = head.parse(input)
212
- # when Result::Fail
213
- # if parsers.empty?
214
- # result
215
- # else
216
- # Alt.new(*parsers[1..-1]).parse(input)
217
- # end
218
- # when Result::OK
219
- # result
220
- # else
221
- # raise
222
- # end
223
- # else
224
- # Result::Fail.new(:input => input)
225
- # end
226
- # end
227
- # end # of initialize
228
- # end
229
-
230
-
231
- class Apply
232
- include Parsable
233
-
234
- def initialize(parser, &block)
235
- @parser = lambda do |input|
236
- result = parser.parse(input)
237
- if result.instance_of?(Result::OK)
238
- Succeed.new(yield(result.value)).parse(result.input)
239
- else
240
- Fail.new.parse(input)
241
- end
242
- end
243
- end # of initialize
244
- end # of Apply
245
-
246
-
247
- class String
248
- include Parsable
249
-
250
- def initialize(string, case_sensitive = true)
251
- @parser = lambda do |input|
252
- result = Item.new.parse(string)
253
- if result.instance_of?(Result::OK)
254
- Seq.new(
255
- Char.new(result.value, case_sensitive),
256
- Yaparc::String.new(result.input, case_sensitive),
257
- Succeed.new(result.value + result.input)
258
- # ) do |char_result, string_result, succeed_result|
259
- ) do |_, _, succeed_result|
260
- succeed_result
261
- end
262
- else
263
- Succeed.new(result)
264
- end
265
- end
266
- end
267
- end
268
-
269
- class Regex
270
- include Parsable
271
-
272
- def initialize(regex, &block)
273
- @regex = regex
274
- @parser = lambda do |input|
275
- if match = Regexp.new(regex).match(input)
276
- if block_given?
277
- Succeed.new(yield(*match.to_a[1..match.to_a.length])).parse(match.post_match)
278
- else
279
- Result::OK.new(:value => match[0], :input => match.post_match)
280
- end
281
- else
282
- Result::Fail.new(:input => input)
283
- end
284
- end
285
- end
286
-
287
- # def parse_with_parameter(input)
288
- # raise "Deprecated!! Use Regex with block"
289
- # if match = Regexp.new(@regex).match(input)
290
- # if block_given?
291
- # yield match.to_a[1..match.to_a.length]
292
- # else
293
- # Result::OK.new(:value => match, :input => match.post_match)
294
- # end
295
- # else
296
- # Result::Fail.new(:input => input)
297
- # end
298
- # end
299
- end
300
-
301
- # permits zero or more applications of parser.
302
- class Many
303
- include Parsable
304
-
305
- def initialize(parser, identity = [])
306
- @parser = lambda do |input|
307
- Alt.new(ManyOne.new(parser, identity), Succeed.new(identity))
308
- end
309
- end
310
- end
311
-
312
- # requires at least one successfull application of parser.
313
- class ManyOne
314
- include Parsable
315
-
316
- def initialize(parser, identity = [])
317
- @parser = lambda do |input|
318
- Seq.new(parser, Many.new(parser, identity)) do |head, tail|
319
- case head
320
- when ::String
321
- if tail.instance_of?(::String)
322
- head + tail
323
- else
324
- raise "Incompatible type: head => #{head.inspect}, tail => #{tail.inspect}"
325
- end
326
- when ::Array
327
- if tail.instance_of?(Array)
328
- head + tail
329
- else
330
- raise "Incompatible type: head => #{head.inspect}, tail => #{tail.inspect}"
331
- end
332
- when ::Hash
333
- if tail.instance_of?(Hash)
334
- head.merge(tail)
335
- else
336
- raise "Incompatible type: head => #{head.inspect}, tail => #{tail.inspect}"
337
- end
338
- when ::Integer
339
- if tail.kind_of?(Integer)
340
- head + tail
341
- else
342
- raise "Incompatible type: head => #{head.inspect}, tail => #{tail.inspect}"
343
- end
344
- else
345
- if tail.nil?
346
- head
347
- else
348
- [head] + tail
349
- end
350
- end
351
- end
352
- end
353
- end
354
- end
355
-
356
- class Space
357
- include Parsable
358
- def initialize
359
- @parser = lambda do |input|
360
- #Many.new(Satisfy.new(IS_SPACE),"")
361
- Regex.new(/\A[ ]*/)
362
- end
363
- end
364
- end
365
-
366
- class CR
367
- include Parsable
368
- def initialize
369
- @parser = lambda do |input|
370
- Regex.new(/\A[ \t]+[\n][ \t\n]+/)
371
- end
372
- end
373
- end
374
-
375
- class WhiteSpace
376
- include Parsable
377
-
378
- def initialize
379
- @parser = lambda do |input|
380
- #Many.new(Satisfy.new(IS_WHITESPACE),'')
381
- Regex.new(/\A[\t\n ]*/)
382
- end
383
- end
384
- end
385
-
386
- class Tokenize
387
- include Parsable
388
- attr_accessor :prefix, :postfix
389
-
390
- def initialize(parser, args = {}, &block)
391
- @parser = lambda do |input|
392
- @prefix = args[:prefix] ? args[:prefix] : WhiteSpace.new
393
- @postfix = args[:postfix] ? args[:postfix] : WhiteSpace.new
394
- if block_given?
395
- yield self
396
- Seq.new(@prefix, parser, @postfix) do |_, vs, _|
397
- vs
398
- end
399
- else
400
- Seq.new(@prefix, parser, @postfix) do |_, vs, _|
401
- vs
402
- end
403
- end
404
- end
405
- end
406
- end
407
-
408
- class Literal
409
- include Parsable
410
-
411
- def initialize(literal, case_sensitive = true)
412
- @parser = lambda do |input|
413
- Tokenize.new(Yaparc::String.new(literal, case_sensitive))
414
- end
415
- end
416
- end
417
-
418
- # class Tokenizer
419
- # include Parsable
420
- # attr_accessor :prefix, :postfix
421
-
422
- # def initialize(args = {})
423
- # @parser = lambda do |input|
424
- # @prefix = args[:prefix] ? args[:prefix] : WhiteSpace.new
425
- # @postfix = args[:postfix] ? args[:postfix] : WhiteSpace.new
426
- # end
427
- # end
428
-
429
- # def tokenize(&block)
430
- # parser = yield
431
-
432
- # Seq.new(@prefix, parser, @postfix) do |_, vs, _|
433
- # vs
434
- # end
435
- # end
436
- # end
437
-
438
- # class Literalizer
439
- # include Parsable
440
-
441
- # def initialize(literal, options = {})
442
- # unless case_sensitive = options[:case_sensitive]
443
- # true
444
- # end
445
-
446
- # unless tokenizer = options[:tokenizer]
447
- # tokenizer = Tokenizer.new
448
- # end
449
-
450
- # @parser = lambda do |input|
451
- # tokenizer.tokenize do
452
- # Yaparc::String.new(literal, case_sensitive)
453
- # end
454
- # end
455
- # end
456
- # end
3
+ require_relative 'yaparc/alt'
4
+ require_relative 'yaparc/apply'
5
+ require_relative 'yaparc/char'
6
+ require_relative 'yaparc/cr'
7
+ require_relative 'yaparc/digit'
8
+ require_relative 'yaparc/fail_parser'
9
+ require_relative 'yaparc/ident'
10
+ require_relative 'yaparc/identifier'
11
+ require_relative 'yaparc/item'
12
+ require_relative 'yaparc/literal'
13
+ require_relative 'yaparc/many'
14
+ require_relative 'yaparc/many_one'
15
+ require_relative 'yaparc/nat'
16
+ require_relative 'yaparc/natural'
17
+ require_relative 'yaparc/no_fail'
18
+ require_relative 'yaparc/parsable'
19
+ require_relative 'yaparc/regex'
20
+ require_relative 'yaparc/satisfy'
21
+ require_relative 'yaparc/seq'
22
+ require_relative 'yaparc/space'
23
+ require_relative 'yaparc/string'
24
+ require_relative 'yaparc/succeed'
25
+ require_relative 'yaparc/symbol'
26
+ require_relative 'yaparc/tokenize'
27
+ require_relative 'yaparc/white_space'
28
+ require_relative 'yaparc/zero_one'
457
29
 
458
- # Refer to http://www.cs.nott.ac.uk/~gmh/monparsing.pdf, p.23
459
- class Identifier
460
- include Yaparc::Parsable
461
-
462
- IDENTIFIER_REGEX = /\A[a-zA-Z_]+[a-zA-Z0-9_]*/
463
-
464
- def initialize(options = {})
465
- identifier_regex = if regex = options[:regex]
466
- ::Yaparc::Regex.new(regex)
467
- else
468
- ::Yaparc::Regex.new(IDENTIFIER_REGEX)
469
- end
470
-
471
- tokenizer = Tokenize.new(identifier_regex)
472
-
473
- if exclude = options[:exclude]
474
- @parser = lambda do |input|
475
- keyword_parsers = exclude.map {|keyword| Yaparc::String.new(keyword)}
476
-
477
- case result = Yaparc::Alt.new(*keyword_parsers).parse(input)
478
- when Yaparc::Result::OK
479
- Yaparc::Fail.new
480
- else # Result::Fail or Result::Error
481
- tokenizer
482
- end
483
- end
484
- else
485
- @parser = lambda do |input|
486
- tokenizer
487
- end
488
- end
489
- end
490
- end
491
-
492
- # class Identifier
493
- # include Yaparc::Parsable
494
- # @@identifier_regex = ::Yaparc::Regex.new(/\A[a-zA-Z_]+[a-zA-Z0-9_]*/)
495
-
496
- # def initialize(*keywords)
497
- # # def initialize(*keywords, &block)
498
- # if keywords == []
499
- # @parser = lambda do |input|
500
- # Tokenize.new(@@identifier_regex)
501
- # # if block_given?
502
- # # tokenize = Tokenize.new(@@identifier_regex)
503
- # # yield tokenize
504
- # # tokenize
505
- # # else
506
- # # Tokenize.new(@@identifier_regex)
507
- # # end
508
- # end
509
- # else
510
- # @parser = lambda do |input|
511
- # keyword_parsers = keywords.map {|keyword| Yaparc::String.new(keyword)}
512
-
513
- # case result = Yaparc::Alt.new(*keyword_parsers).parse(input)
514
- # when Yaparc::Result::OK
515
- # Yaparc::Fail.new
516
- # else # Result::Fail or Result::Error
517
- # Tokenize.new(@@identifier_regex)
518
- # end
519
- # end
520
- # end
521
- # end
522
- # end
523
-
524
- class Char
525
- include Parsable
526
-
527
- def initialize(char, case_sensitive = true)
528
- raise unless char.length == 1
529
- if case_sensitive
530
- equal_char = lambda {|i| i == char}
531
- else # in case of case-insentive
532
- equal_char = lambda {|i| i.casecmp(char) == 0}
533
- end
534
- @parser = lambda do |input|
535
- Satisfy.new(equal_char)
536
- end
537
- end
538
- end
539
-
540
- class Ident
541
- include Parsable
542
- def initialize
543
- @parser = lambda do |input|
544
- Seq.new(
545
- Satisfy.new(IS_LOWER),
546
- Many.new(Satisfy.new(IS_ALPHANUM),"")
547
- ) do |head, tail|
548
- head + tail
549
- end
550
- end
551
- end
552
- end
553
-
554
- class Digit
555
- include Parsable
556
- def initialize
557
- @parser = lambda do |input|
558
- Satisfy.new(IS_DIGIT)
559
- end
560
- end
561
- end
562
-
563
- class Nat
564
- include Parsable
565
- def initialize
566
- @parser = lambda do |input|
567
- Seq.new(ManyOne.new(Digit.new,'')) do |vs|
568
- if vs == ""
569
- 0 # vs
570
- else
571
- vs.to_i
572
- end
573
- end
574
- end
575
- end
576
- end
30
+ module Yaparc
31
+ VERSION = '0.4.0'
577
32
 
33
+ begin
34
+ base = Class.new do
35
+ attr :input, :value
578
36
 
579
- class Natural
580
- include Parsable
581
- def initialize(args = {})
582
- @parser = lambda do |input|
583
- Tokenize.new(Nat.new, args)
37
+ def initialize(input:, value: nil)
38
+ @input = input
39
+ @value = value
584
40
  end
585
41
  end
586
- end
587
42
 
588
- class Symbol
589
- include Parsable
590
- def initialize(literal, args = {})
591
- @parser = lambda do |input|
592
- Literal.new(literal)
593
- end
594
- end
595
- end
596
-
597
- class AbstractParser
598
- include Parsable
599
-
600
- # def parse(input, &block)
601
- # tree = @parser.call.parse(input)
602
- # if block_given?
603
- # yield tree
604
- # else
605
- # tree
606
- # end
607
- # end
608
- def parse(input, &block)
609
- tree = @parser.call.parse(input)
610
- if block_given?
611
- @tree = yield tree
612
- else
613
- @tree = tree
614
- end
615
- end
43
+ OK = Class.new(base)
44
+ Fail = Class.new(base)
45
+ Error = Class.new(base)
616
46
  end
617
- end # of Yaparc
47
+ end