raabro 0.9.0 → 1.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.
@@ -0,0 +1,13 @@
1
+
2
+ = raabro CHANGELOG.txt
3
+
4
+
5
+ == raabro 1.0.0 not yet released
6
+
7
+ - first complete (hopefully) release
8
+
9
+
10
+ == raabro 0.9.0
11
+
12
+ - initial push to RubyGems
13
+
data/README.md CHANGED
@@ -1,6 +1,9 @@
1
1
 
2
2
  # raabro
3
3
 
4
+ [![Build Status](https://secure.travis-ci.org/jmettraux/raabro.png)](http://travis-ci.org/jmettraux/raabro)
5
+ [![Gem Version](https://badge.fury.io/rb/raabro.png)](http://badge.fury.io/rb/raabro)
6
+
4
7
  A very dumb PEG parser library.
5
8
 
6
9
  Son to [aabro](https://github.com/flon-io/aabro), grandson to [neg](https://github.com/jmettraux/neg).
@@ -26,25 +26,25 @@
26
26
 
27
27
  module Raabro
28
28
 
29
- VERSION = '0.9.0'
29
+ VERSION = '1.0.0'
30
30
 
31
31
  class Input
32
32
 
33
33
  attr_accessor :string, :offset
34
34
  attr_reader :options
35
35
 
36
- def initialize(string, options={})
36
+ def initialize(string, offset=0, options={})
37
37
 
38
38
  @string = string
39
- @offset = 0
40
- @options = options
39
+ @offset = offset.is_a?(Hash) ? 0 : offset
40
+ @options = offset.is_a?(Hash) ? offset : options
41
41
  end
42
42
 
43
43
  def match(str_or_regex)
44
44
 
45
45
  if str_or_regex.is_a?(Regexp)
46
46
  m = @string[@offset..-1].match(str_or_regex)
47
- m ? m[0].length : false
47
+ m && (m.offset(0).first == 0) ? m[0].length : false
48
48
  else # String or whatever responds to #to_s
49
49
  s = str_or_regex.to_s
50
50
  l = s.length
@@ -71,124 +71,342 @@ module Raabro
71
71
  @children = []
72
72
  end
73
73
 
74
+ def successful_children
75
+
76
+ @children.select { |c| c.result == 1 }
77
+ end
78
+
79
+ def prune!
80
+
81
+ @children = successful_children
82
+ end
83
+
84
+ def shrink!
85
+
86
+ @children =
87
+ @children.inject([]) do |a, c|
88
+ a << c.shrink! if c.result == 1 && c.name
89
+ a
90
+ end
91
+
92
+ self
93
+ end
94
+
95
+ def string
96
+
97
+ @input.string[@offset, @length]
98
+ end
99
+
100
+ def lookup(name)
101
+
102
+ name = name.to_s
103
+
104
+ return self if @name.to_s == name
105
+ @children.each { |c| if n = c.lookup(name); return n; end }
106
+ nil
107
+ end
108
+
109
+ def gather(name, acc=[])
110
+
111
+ name = name.to_s
112
+
113
+ if @name.to_s == name
114
+ acc << self
115
+ else
116
+ @children.each { |c| c.gather(name, acc) }
117
+ end
118
+
119
+ acc
120
+ end
121
+
74
122
  def to_a(opts={})
75
123
 
124
+ opts = Array(opts).inject({}) { |h, e| h[e] = true; h } \
125
+ unless opts.is_a?(Hash)
126
+
76
127
  cn =
77
128
  opts[:leaves] && (@result == 1) && @children.empty? ?
78
- @input.string[@offset, @length] :
129
+ string :
79
130
  @children.collect { |e| e.to_a(opts) }
80
131
 
81
132
  [ @name, @result, @offset, @length, @note, @parter, cn ]
82
133
  end
83
- end
84
134
 
85
- def self.match(name, input, parter, regex_or_string)
135
+ def to_s(depth=0, io=StringIO.new)
86
136
 
87
- r = Tree.new(name, parter, input)
137
+ io.print "\n" if depth > 0
138
+ io.print ' ' * depth
139
+ io.print "#{@result} #{@name.inspect} #{@offset},#{@length}"
140
+ io.print result == 1 && children.size == 0 ? ' ' + string.inspect : ''
88
141
 
89
- if l = input.match(regex_or_string)
90
- r.result = 1
91
- r.length = l
92
- input.offset += l
93
- end
142
+ @children.each { |c| c.to_s(depth + 1, io) }
94
143
 
95
- r
144
+ depth == 0 ? io.string : nil
145
+ end
96
146
  end
97
147
 
98
- def self.str(name, input, string)
148
+ module ModuleMethods
99
149
 
100
- match(name, input, :str, string)
101
- end
150
+ def _match(name, input, parter, regex_or_string)
102
151
 
103
- def self.rex(name, input, regex_or_string)
152
+ r = Raabro::Tree.new(name, parter, input)
104
153
 
105
- match(name, input, :rex, Regexp.new(regex_or_string))
106
- end
154
+ if l = input.match(regex_or_string)
155
+ r.result = 1
156
+ r.length = l
157
+ input.offset += l
158
+ end
107
159
 
108
- def self.narrow(parser)
160
+ r
161
+ end
109
162
 
110
- return parser if parser.is_a?(Method)
111
- return method(parser) if parser.is_a?(Symbol)
163
+ def str(name, input, string)
112
164
 
113
- k, m = parser.to_s.split('.')
114
- k, m = [ Object, k ] unless m
165
+ _match(name, input, :str, string)
166
+ end
115
167
 
116
- Kernel.const_get(k).method(m)
117
- end
168
+ def rex(name, input, regex_or_string)
118
169
 
119
- def self.parse(parser, input)
170
+ _match(name, input, :rex, Regexp.new(regex_or_string))
171
+ end
120
172
 
121
- narrow(parser).call(input)
122
- end
173
+ def _quantify(parser)
123
174
 
124
- def self.seq(name, input, *parsers)
175
+ return nil if parser.is_a?(Symbol) && respond_to?(parser)
176
+ # so that :plus and co can be overriden
125
177
 
126
- r = Tree.new(name, :seq, input)
178
+ case parser
179
+ when '?', :q, :qmark then [ 0, 1 ]
180
+ when '*', :s, :star then [ 0, 0 ]
181
+ when '+', :p, :plus then [ 1, 0 ]
182
+ else nil
183
+ end
184
+ end
127
185
 
128
- start = input.offset
129
- c = nil
186
+ def _narrow(parser)
130
187
 
131
- parsers.each do |pa|
132
- c = parse(pa, input)
133
- r.children << c
134
- break if c.result != 1
188
+ raise ArgumentError.new("lone quantifier #{parser}") if _quantify(parser)
189
+
190
+ return parser if parser.is_a?(Method)
191
+ return method(parser) if parser.is_a?(Symbol)
192
+
193
+ k, m = parser.to_s.split('.')
194
+ k, m = [ Object, k ] unless m
195
+
196
+ Kernel.const_get(k).method(m)
135
197
  end
136
198
 
137
- if c && c.result == 1
138
- r.result = 1
139
- r.length = input.offset - start
140
- else
141
- input.offset = start
199
+ def _parse(parser, input)
200
+
201
+ _narrow(parser).call(input)
142
202
  end
143
203
 
144
- r
145
- end
204
+ def seq(name, input, *parsers)
146
205
 
147
- def self.alt(name, input, *parsers)
206
+ r = ::Raabro::Tree.new(name, :seq, input)
148
207
 
149
- r = Tree.new(name, :alt, input)
208
+ start = input.offset
209
+ c = nil
150
210
 
151
- c = nil
211
+ loop do
152
212
 
153
- parsers.each do |pa|
154
- c = parse(pa, input)
155
- r.children << c
156
- break if c.result == 1
213
+ pa = parsers.shift
214
+ break unless pa
215
+
216
+ if q = _quantify(parsers.first)
217
+ parsers.shift
218
+ c = rep(nil, input, pa, *q)
219
+ r.children.concat(c.children)
220
+ else
221
+ c = _parse(pa, input)
222
+ r.children << c
223
+ end
224
+
225
+ break if c.result != 1
226
+ end
227
+
228
+ if c && c.result == 1
229
+ r.result = 1
230
+ r.length = input.offset - start
231
+ else
232
+ input.offset = start
233
+ end
234
+
235
+ r
157
236
  end
158
237
 
159
- if c && c.result == 1
160
- r.result = 1
161
- r.length = c.length
238
+ def alt(name, input, *parsers)
239
+
240
+ greedy =
241
+ if parsers.last == true || parsers.last == false
242
+ parsers.pop
243
+ else
244
+ false
245
+ end
246
+
247
+ r = ::Raabro::Tree.new(name, greedy ? :altg : :alt, input)
248
+
249
+ start = input.offset
250
+ c = nil
251
+
252
+ parsers.each do |pa|
253
+
254
+ cc = _parse(pa, input)
255
+ r.children << cc
256
+
257
+ input.offset = start
258
+
259
+ if greedy
260
+ if cc.result == 1 && cc.length > (c ? c.length : -1)
261
+ c.result = 0 if c
262
+ c = cc
263
+ end
264
+ else
265
+ c = cc
266
+ break if c.result == 1
267
+ end
268
+ end
269
+
270
+ if c && c.result == 1
271
+ r.result = 1
272
+ r.length = c.length
273
+ input.offset = start + r.length
274
+ end
275
+
276
+ r.prune! if input.options[:prune]
277
+
278
+ r
162
279
  end
163
280
 
164
- r
165
- end
281
+ def altg(name, input, *parsers)
282
+
283
+ alt(name, input, *parsers, true)
284
+ end
166
285
 
167
- def self.rep(name, input, parser, min, max=0)
286
+ def rep(name, input, parser, min, max=0)
287
+
288
+ min = 0 if min == nil || min < 0
289
+ max = nil if max.nil? || max < 1
290
+
291
+ r = ::Raabro::Tree.new(name, :rep, input)
292
+ start = input.offset
293
+ count = 0
294
+
295
+ loop do
296
+ c = _parse(parser, input)
297
+ r.children << c
298
+ break if c.result != 1
299
+ count += 1
300
+ break if max && count == max
301
+ end
302
+
303
+ if count >= min && (max == nil || count <= max)
304
+ r.result = 1
305
+ r.length = input.offset - start
306
+ else
307
+ input.offset = start
308
+ end
309
+
310
+ r.prune! if input.options[:prune]
311
+
312
+ r
313
+ end
314
+
315
+ def ren(name, input, parser)
316
+
317
+ r = _parse(parser, input)
318
+ r.name = name
319
+
320
+ r
321
+ end
322
+ alias rename ren
168
323
 
169
- min = 0 if min == nil || min < 0
170
- max = nil if max.nil? || max < 1
324
+ def all(name, input, parser)
171
325
 
172
- r = Tree.new(name, :rep, input)
173
- start = input.offset
174
- count = 0
326
+ start = input.offset
327
+ length = input.string.length - input.offset
175
328
 
176
- loop do
177
- c = parse(parser, input)
329
+ r = ::Raabro::Tree.new(name, :all, input)
330
+ c = _parse(parser, input)
178
331
  r.children << c
179
- break if c.result != 1
180
- count += 1
181
- break if max && count == max
332
+
333
+ if c.length < length
334
+ input.offset = start
335
+ else
336
+ r.result = 1
337
+ r.length = c.length
338
+ end
339
+
340
+ r
182
341
  end
183
342
 
184
- if count >= min && (max == nil || count <= max)
343
+ def eseq(name, input, startpa, eltpa, seppa=nil, endpa=nil)
344
+
345
+ jseq = false
346
+
347
+ if seppa.nil? && endpa.nil?
348
+ jseq = true
349
+ seppa = eltpa; eltpa = startpa; startpa = nil
350
+ end
351
+
352
+ start = input.offset
353
+ r = ::Raabro::Tree.new(name, jseq ? :jseq : :eseq, input)
185
354
  r.result = 1
186
- r.length = input.offset - start
187
- else
188
- input.offset = start
355
+ c = nil
356
+
357
+ if startpa
358
+ c = _parse(startpa, input)
359
+ r.children << c
360
+ r.result = 0 if c.result != 1
361
+ end
362
+
363
+ if r.result == 1
364
+
365
+ i = 1
366
+ count = 0
367
+
368
+ loop do
369
+
370
+ i = (i + 1) % 2
371
+ pa = i == 0 ? eltpa : seppa
372
+
373
+ c = _parse(pa, input)
374
+ r.children << c
375
+
376
+ break if c.result != 1
377
+
378
+ count += 1
379
+ end
380
+
381
+ r.result = 0 if jseq && count < 1
382
+ end
383
+
384
+ if r.result == 1 && endpa
385
+ c = _parse(endpa, input)
386
+ r.children << c
387
+ r.result = 0 if c.result != 1
388
+ end
389
+
390
+ if r.result == 1
391
+ r.length = input.offset - start
392
+ else
393
+ input.offset = start
394
+ end
395
+
396
+ r.prune! if input.options[:prune]
397
+
398
+ r
189
399
  end
400
+ alias jseq eseq
401
+ end
402
+ extend ModuleMethods
403
+
404
+ def self.included(target)
190
405
 
191
- r
406
+ target.instance_eval do
407
+ extend ::Raabro::ModuleMethods
408
+ extend self
409
+ end
192
410
  end
193
411
  end
194
412