raabro 0.9.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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