reg 0.4.8 → 0.5.0a0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. checksums.yaml +4 -0
  2. data/COPYING +0 -0
  3. data/History.txt +14 -0
  4. data/Makefile +59 -0
  5. data/README +87 -40
  6. data/article.txt +838 -0
  7. data/{assert.rb → lib/assert.rb} +3 -3
  8. data/{reg.rb → lib/reg.rb} +11 -4
  9. data/lib/reg/version.rb +21 -0
  10. data/lib/regarray.rb +455 -0
  11. data/{regarrayold.rb → lib/regarrayold.rb} +33 -7
  12. data/lib/regbackref.rb +73 -0
  13. data/lib/regbind.rb +230 -0
  14. data/{regcase.rb → lib/regcase.rb} +15 -5
  15. data/lib/regcompiler.rb +2341 -0
  16. data/{regcore.rb → lib/regcore.rb} +196 -85
  17. data/{regdeferred.rb → lib/regdeferred.rb} +35 -4
  18. data/{regposition.rb → lib/regevent.rb} +36 -38
  19. data/lib/reggraphpoint.rb +28 -0
  20. data/lib/reghash.rb +631 -0
  21. data/lib/reginstrumentation.rb +36 -0
  22. data/{regitem_that.rb → lib/regitem_that.rb} +32 -11
  23. data/{regknows.rb → lib/regknows.rb} +4 -2
  24. data/{reglogic.rb → lib/reglogic.rb} +76 -59
  25. data/{reglookab.rb → lib/reglookab.rb} +31 -21
  26. data/lib/regmatchset.rb +323 -0
  27. data/{regold.rb → lib/regold.rb} +27 -27
  28. data/{regpath.rb → lib/regpath.rb} +91 -1
  29. data/lib/regposition.rb +79 -0
  30. data/lib/regprogress.rb +1522 -0
  31. data/lib/regrepeat.rb +307 -0
  32. data/lib/regreplace.rb +254 -0
  33. data/lib/regslicing.rb +581 -0
  34. data/lib/regsubseq.rb +72 -0
  35. data/lib/regsugar.rb +361 -0
  36. data/lib/regvar.rb +180 -0
  37. data/lib/regxform.rb +212 -0
  38. data/{trace.rb → lib/trace_during.rb} +6 -4
  39. data/lib/warning.rb +37 -0
  40. data/parser.txt +26 -8
  41. data/philosophy.txt +18 -0
  42. data/reg.gemspec +58 -25
  43. data/regguide.txt +18 -0
  44. data/test/andtest.rb +46 -0
  45. data/test/regcompiler_test.rb +346 -0
  46. data/test/regdemo.rb +20 -0
  47. data/{item_thattest.rb → test/regitem_thattest.rb} +2 -2
  48. data/test/regtest.rb +2125 -0
  49. data/test/test_all.rb +32 -0
  50. data/test/test_reg.rb +19 -0
  51. metadata +108 -73
  52. data/calc.reg +0 -73
  53. data/forward_to.rb +0 -49
  54. data/numberset.rb +0 -200
  55. data/regarray.rb +0 -675
  56. data/regbackref.rb +0 -126
  57. data/regbind.rb +0 -74
  58. data/reggrid.csv +1 -2
  59. data/reghash.rb +0 -318
  60. data/regprogress.rb +0 -1054
  61. data/regreplace.rb +0 -114
  62. data/regsugar.rb +0 -230
  63. data/regtest.rb +0 -1078
  64. data/regvar.rb +0 -76
@@ -1,5 +1,5 @@
1
1
  =begin copyright
2
- Copyright (C) 2004,2005 Caleb Clausen
2
+ Copyright (C) 2004,2005, 2016 Caleb Clausen
3
3
 
4
4
  This library is free software; you can redistribute it and/or
5
5
  modify it under the terms of the GNU Lesser General Public
@@ -18,14 +18,14 @@
18
18
 
19
19
  module Kernel
20
20
  def assert(expr,msg="assertion failed")
21
- $Debug and (expr or raise msg)
21
+ defined? $Debug and $Debug and (expr or raise msg)
22
22
  end
23
23
 
24
24
  @@printed={}
25
25
  def fixme(s)
26
26
  unless @@printed[s]
27
27
  @@printed[s]=1
28
- $Debug and $stderr.print "FIXME: #{s}\n"
28
+ defined? $Debug and $Debug and $stderr.print "FIXME: #{s}\n"
29
29
  end
30
30
  end
31
31
  end
@@ -1,6 +1,6 @@
1
1
  =begin copyright
2
2
  reg - the ruby extended grammar
3
- Copyright (C) 2005,2009 Caleb Clausen
3
+ Copyright (C) 2005, 2016 Caleb Clausen
4
4
 
5
5
  This library is free software; you can redistribute it and/or
6
6
  modify it under the terms of the GNU Lesser General Public
@@ -16,19 +16,26 @@
16
16
  License along with this library; if not, write to the Free Software
17
17
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
18
  =end
19
-
20
19
  require 'regcore'
21
20
  require 'reglogic'
22
21
  require 'reghash'
23
22
  require 'regarray'
23
+ require 'regrepeat'
24
+ require 'regsubseq'
24
25
  #require 'regarrayold' #old bt engine
25
26
  require 'regprogress' #new bt engine
26
27
  #enable one engine or the other, but not both
27
28
 
29
+ require 'regevent'
30
+ require 'regbind'
31
+ require 'regreplace'
28
32
  require 'regbackref'
29
33
  require 'regitem_that'
30
34
  require 'regknows'
31
35
  require 'regsugar'
36
+ require 'regvar'
37
+ require 'regposition'
32
38
  require 'regold' #will go away
33
- Kernel.instance_eval( &Reg::TLA_pirate)
34
- Reg::Sugar.include!
39
+
40
+ require 'regcompiler' #engine, bah
41
+ #Kernel.instance_eval( &Reg::TLA_pirate)
@@ -0,0 +1,21 @@
1
+ =begin copyright
2
+ reg - the ruby extended grammar
3
+ Copyright (C) 2016 Caleb Clausen
4
+
5
+ This library is free software; you can redistribute it and/or
6
+ modify it under the terms of the GNU Lesser General Public
7
+ License as published by the Free Software Foundation; either
8
+ version 2.1 of the License, or (at your option) any later version.
9
+
10
+ This library is distributed in the hope that it will be useful,
11
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
+ Lesser General Public License for more details.
14
+
15
+ You should have received a copy of the GNU Lesser General Public
16
+ License along with this library; if not, write to the Free Software
17
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
+ =end
19
+ module Reg
20
+ VERSION="0.5.0a0"
21
+ end
@@ -0,0 +1,455 @@
1
+ =begin copyright
2
+ reg - the ruby extended grammar
3
+ Copyright (C) 2005, 2016 Caleb Clausen
4
+
5
+ This library is free software; you can redistribute it and/or
6
+ modify it under the terms of the GNU Lesser General Public
7
+ License as published by the Free Software Foundation; either
8
+ version 2.1 of the License, or (at your option) any later version.
9
+
10
+ This library is distributed in the hope that it will be useful,
11
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
+ Lesser General Public License for more details.
14
+
15
+ You should have received a copy of the GNU Lesser General Public
16
+ License along with this library; if not, write to the Free Software
17
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
+ =end
19
+
20
+ require "assert"
21
+ require "pp"
22
+ require "forwardable"
23
+ require "regdeferred"
24
+
25
+ module Reg
26
+ module Reg
27
+ def itemrange; 1..1 end #default match 1 item
28
+
29
+
30
+ #create a (vector) Reg that will match this pattern repeatedly.
31
+ #(creates a Reg::Repeat.)
32
+ #the argument determines the number of times to match.
33
+ #times may be a positive integer, zero, Infinity, or a
34
+ #range over any of the above. if a range, the lower
35
+ #end may not be Infinity! Reg#- and Reg#+ are shortcuts
36
+ #for the most common cases of multiplting by a range.
37
+ #(at least 0 and at most Infinity.) watch out when
38
+ #multiplying with zero and Infinity (including in a
39
+ #range), as you can easily create a situation where
40
+ #the number of matches to enumerate explodes exponentionaly,
41
+ #or even is infinite. i won't say too much here except
42
+ #that these are generally the same sorts of problems you
43
+ #can run into with Regexps as well.
44
+ def *(times=0..Infinity)
45
+ Repeat.new(self,times)
46
+ end
47
+
48
+ #repeat this pattern up to atmost times. could match
49
+ #0 times as the minimum number of matches here is zero.
50
+ def -(atmost=1)
51
+ self*(0..atmost)
52
+ end
53
+
54
+ #repeat this pattern atleast times or more
55
+ def +(atleast=1)
56
+ self*(atleast..Infinity)
57
+ end
58
+
59
+ end
60
+
61
+ #--------------------------
62
+ module Undoable
63
+
64
+ end
65
+
66
+ #--------------------------
67
+ module Composite
68
+ include Reg
69
+ def initialize(*args,&block)
70
+ at_construct_time(*args,&block)
71
+ # super
72
+ end
73
+
74
+ def at_construct_time(*a,&b); end #default does nothing
75
+
76
+ def visit_subregs()
77
+ todo=[self]
78
+ visited=Set[]
79
+ while node=todo.shift
80
+ next if visited[node.__id__]
81
+ yield node #visit this node
82
+ visited<<node.__id__
83
+ todo.push(*node.subregs) #schedule children to be visited
84
+ end
85
+ end
86
+ alias breadth_visit_subregs visit_subregs
87
+
88
+ def depth_visit_subregs(set=Set[],&visit)
89
+ set[self.__id__] and return
90
+ set<<self.__id__
91
+ subregs.each{|r| r.depth_visit_subregs(set,&visit) }
92
+ visit[self]
93
+ end
94
+
95
+ def undoable_infection
96
+ unless subregs.grep(Undoable).empty?
97
+ extend Undoable
98
+ class <<self
99
+ undef mmatch
100
+ alias mmatch mmatch_full
101
+ end
102
+ end
103
+ end
104
+
105
+
106
+ def subregs
107
+ [@reg]
108
+ end
109
+ #includers should define #subregs if they don't have just a single @reg
110
+
111
+ protected
112
+ def multiple_infection(*regs)
113
+ regs.empty? and regs=subregs
114
+ regs.each{|reg|
115
+ reg.respond_to? :maybe_multiple and
116
+ reg.maybe_multiple(self)
117
+ }
118
+ end
119
+ end
120
+
121
+ #--------------------------
122
+ module Multiple
123
+ include Reg
124
+ def ===(other)
125
+ method_missing(:===, other)
126
+ end
127
+ =begin
128
+ def maybe_multiple(needsmult) #better name needed
129
+ assert( needsmult.respond_to?( :mmatch))
130
+ class <<needsmult
131
+ undef_method :mmatch
132
+ include Multiple
133
+ #alias mmatch mmatch_full #this doesn't work... why?
134
+ def mmatch(*xx) mmatch_full(*xx); end #have to do this instead
135
+ end
136
+ assert( needsmult.respond_to?( :mmatch))
137
+ end
138
+
139
+ def multiple_infection(*args) end #not needed?
140
+ #we're already multiple; no need to try to become multiple again
141
+ =end
142
+ def mmatch(*xx) #multiple match
143
+ abstract
144
+ end
145
+
146
+ #negated Reg::Multiple's are automatically lookaheads
147
+ def ~
148
+ ~(Lookahead.new self)
149
+ end
150
+
151
+
152
+ def starts_with
153
+ abstract
154
+ end
155
+
156
+ def ends_with
157
+ abstract
158
+ end
159
+
160
+ def matches_class
161
+ raise 'multiple regs match no single class'
162
+ end
163
+ end
164
+
165
+ #--------------------------
166
+ module Backtrace
167
+ # protected
168
+
169
+ def regs(ri) @regs[ri] end
170
+
171
+ def update_di(di,len); di+len; end
172
+ #--------------------------
173
+ $RegTraceEnable=$RegTraceDisable=nil
174
+ def trace_enabled?
175
+ @trace||=nil
176
+ $RegTraceEnable or (!$RegTraceDisable && @trace)
177
+ end
178
+
179
+ #--------------------------
180
+ def trace!
181
+ @trace=true
182
+ self
183
+ end
184
+
185
+ #--------------------------
186
+ def notrace!
187
+ @trace=false
188
+ self
189
+ end
190
+ end
191
+
192
+ #--------------------------
193
+ if false
194
+ class RR < ::Array
195
+ def inspect
196
+ [self,super].to_s
197
+ end
198
+
199
+ def rrflatten
200
+ result=[]
201
+ each{|i|
202
+ case i
203
+ when RR then result +=i.rrflatten
204
+ when Literal then result << i.unlit
205
+ else result << i
206
+ end
207
+ }
208
+ end
209
+
210
+ def +(other)
211
+ RR[*super]
212
+ end
213
+ end
214
+ Result=RR
215
+ else
216
+ RR=::Array
217
+ end
218
+
219
+
220
+
221
+
222
+ #--------------------------
223
+ class Or
224
+ def mmatch(arr,start)
225
+ assert start <= arr.size
226
+ @regs.each_with_index {|reg,i|
227
+ reg===arr[start] and
228
+ return OrMatchSet.new(self,i,nil,1)
229
+ } unless start == arr.size
230
+ return nil
231
+ end
232
+
233
+ def itemrange
234
+ if true
235
+ min,max=Infinity,0
236
+ @regs.each {|r|
237
+ min=r.itemrange.first if Reg===r and min>r.itemrange.first
238
+ max=r.itemrange.last if Reg===r and max<r.itemrange.last
239
+ }
240
+ return min..max
241
+ else
242
+ limits=@regs.map{|r|
243
+
244
+ i=(r.respond_to? :itemrange)? r.itemrange : 1..1
245
+ [i.first,i.last]
246
+ }.transpose
247
+ limits.first.sort.first .. limits.last.sort.last
248
+ end
249
+ end
250
+
251
+ private
252
+ def mmatch_full(arr,start)
253
+ mat=nil
254
+ @regs.each_with_index{|r,i|
255
+ if r.respond_to? :mmatch
256
+ mat=r.mmatch(arr,start) or next
257
+ if mat.respond_to? :next_match
258
+ return OrMatchSet.new(self,i,mat,mat.next_match(arr,start).last)
259
+ else
260
+ return OrMatchSet.new(self,i,nil,mat.last)
261
+ end
262
+ else
263
+ r===arr[start] and
264
+ return OrMatchSet.new(self,i,nil,1)
265
+ end
266
+ }
267
+
268
+ assert mat.nil?
269
+ return nil
270
+ end
271
+ end
272
+
273
+ #--------------------------
274
+ class Xor
275
+ def clean_result
276
+ huh
277
+ end
278
+
279
+ def itemrange
280
+ #min,max=Infinity,0
281
+ #@regs.each {|r|
282
+ # min=[min,r.itemrange.first].sort.first
283
+ # max=[r.itemrange.last,max].sort.last
284
+ #}
285
+ #return min..max
286
+ limits=@regs.map{|r| i=r.itemrange; [i.first,i.last]}.transpose
287
+ limits.first.sort.first .. limits.last.sort.last
288
+ end
289
+
290
+ private
291
+ if false
292
+ def mmatch_full(arr,start)
293
+ mat=i=nil
294
+ count=0
295
+ @regs.each_with_index{|reg,idx|
296
+ if reg.respond_to? :mmatch
297
+ mat=reg.mmatch(arr,start) or next
298
+ else
299
+ reg===arr[start] or next
300
+ mat=[[arr[start]],1]
301
+ end
302
+ count==0 or return nil
303
+ count=1
304
+ assert mat
305
+ }
306
+
307
+ return nil unless mat
308
+ assert count==1
309
+ mat.respond_to? :next_match and return XorMatchSet.new(reg,idx,mat,huh)
310
+
311
+ a=RR[nil]*regs.size
312
+ a[idx]=mat[0]
313
+ mat[0]=a
314
+ assert huh
315
+ assert ::Array===mat.first.first
316
+ return mat
317
+ end
318
+ end
319
+
320
+ def mmatch_full arr, start
321
+ found=nil
322
+ @regs.each{|reg|
323
+ if m=reg.mmatch(arr, start)
324
+ return if found
325
+ found=m
326
+ end
327
+ }
328
+ return found
329
+ end
330
+
331
+ end
332
+
333
+ #--------------------------
334
+ class And
335
+ include Backtrace #shouldn't this be included only when needed?
336
+
337
+ def update_di(di,len) di; end
338
+
339
+
340
+ def clean_result
341
+ huh
342
+ end
343
+
344
+
345
+ def enough_matches? matchcnt,*bogus
346
+ matchcnt==@regs.size
347
+ end
348
+
349
+ def itemrange
350
+ limits=@regs.map{|r| i=r.itemrange; [i.first,i.last]}.transpose
351
+ limits.first.sort.last .. limits.last.sort.last
352
+ end
353
+
354
+ private
355
+ def mmatch_full(arr,start)
356
+ #in this version, at least one of @regs is a multiple reg
357
+ assert( (0..arr.size).include?( start))
358
+ result,*bogus=huh.bt_match(arr,start,0,0,[RR[]])
359
+ result and AndMatchSet.new(self,result)
360
+ end
361
+ end
362
+
363
+ #--------------------------
364
+ class Array
365
+ include Reg,Backtrace,Composite
366
+
367
+ def max_matches; @regs.size end
368
+
369
+ def initialize(*regs)
370
+
371
+ #inline subsequences and short fixed repetitions
372
+ iterate=proc{|list|
373
+ result=[]
374
+ list.each{|reg|
375
+ case reg
376
+ when Subseq
377
+ result.push(*iterate[reg.subregs])
378
+ when Repeat
379
+ rr=reg.times
380
+ if rr.first==rr.last and rr.first<=3
381
+ result.push(*iterate[[reg.regs(nil)]*rr.first])
382
+ else
383
+ result<<reg
384
+ end
385
+ else result<< Deferred.defang!(reg)
386
+ end
387
+ }
388
+ result
389
+ }
390
+ @regs=iterate[regs]
391
+ # p [:+, :[]]
392
+ super
393
+ end
394
+
395
+ class <<self
396
+ alias new__nobooleans new
397
+ def new(*args)
398
+ # args.detect{|o| /^(AND|X?OR)$/.sym===o } or return new__nobooleans(*args)
399
+ # +[/^(AND|X?OR)$/.sym.splitter].match(args)
400
+ Pair===args.first and return ::Reg::OrderedHash.new(*args)
401
+ new__nobooleans(*args)
402
+ end
403
+ alias [] new
404
+ end
405
+
406
+ def matches_class; ::Array end
407
+
408
+ def subitemrange
409
+ #add the ranges of the individual items
410
+ @subitemrange ||= #some caching...
411
+ begin
412
+ list=Thread.current[:$Reg__Subseq__subitemranges_in_progress]||={}
413
+ id=__id__
414
+ list[id] and throw(id.to_s.to_sym,0..Infinity)
415
+ list[id]=1
416
+ catch(id.to_s.to_sym){
417
+ @regs.inject(0){|sum,ob| sum+(Reg===ob ? ob.itemrange.begin : 1) } ..
418
+ @regs.inject(0){|sum,ob| sum+(Reg===ob ? ob.itemrange.end : 1) }
419
+ }
420
+ ensure
421
+ list.delete id
422
+ end
423
+
424
+ end
425
+
426
+ def multiple_infection(*args) end #never do anything for Reg::Array
427
+
428
+ def enough_matches? matchcnt,eof
429
+ matchcnt==@regs.size and eof
430
+ end
431
+
432
+ def +(reg)
433
+ if self.class==reg.class
434
+ self.class.new( *@regs+reg.regs )
435
+ else
436
+ super
437
+ end
438
+ end
439
+
440
+ def inspect
441
+ name="$RegInspectRecursing#{object_id}"
442
+ Thread.current[name] and return '+[...]'
443
+ Thread.current[name]=true
444
+ result="+["+ @regs.collect{|r| r.inspect}.join(', ') +"]"
445
+ Thread.current[name]=nil
446
+ result
447
+ end
448
+
449
+ def subregs; @regs.dup end
450
+ end
451
+
452
+
453
+
454
+
455
+ end