reg 0.4.8 → 0.5.0a0

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.
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,6 +1,6 @@
1
1
  =begin copyright
2
2
  reg - the ruby extended grammar
3
- Copyright (C) 2005 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
@@ -17,6 +17,7 @@
17
17
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
18
  =end
19
19
 
20
+
20
21
  #----------------------------------
21
22
  module Kernel
22
23
  def formula_value(*ctx) #hopefully, no-one else will ever use this same name....
@@ -34,7 +35,7 @@ module Reg
34
35
 
35
36
 
36
37
  #----------------------------------
37
- module BlankSlate;
38
+ module BlankSlate
38
39
  module ClassMethods
39
40
  def restore(*names)
40
41
  names.each{|name| alias_method name, "##{name}"}
@@ -48,13 +49,26 @@ module Reg
48
49
 
49
50
  def BlankSlate.included(othermod)
50
51
  othermod.instance_eval {
51
- instance_methods.each { |m|
52
+ ms=instance_methods#+private_instance_methods
53
+ ms.each { |m|
54
+ next if m=="initialize"
52
55
  alias_method "##{m}", m #archive m
53
56
  undef_method m unless m =~ /^__/ || m=='instance_eval' || m==:instance_eval
54
57
  }
55
58
  extend BlankSlate::ClassMethods
56
59
  }
57
60
  end
61
+ def BlankSlate.extended(other)
62
+ class <<other
63
+ ms=instance_methods#+private_instance_methods
64
+ ms.each { |m|
65
+ next if m=="initialize"
66
+ alias_method "##{m}", m #archive m
67
+ undef_method m unless m =~ /^__/ || m=='instance_eval'
68
+ }
69
+ extend BlankSlate::ClassMethods
70
+ end
71
+ end
58
72
  end
59
73
 
60
74
  #----------------------------------
@@ -79,6 +93,8 @@ module Reg
79
93
  class Deferred
80
94
  include BlankSlate
81
95
  restore :inspect,:extend
96
+ restore :respond_to?
97
+ # restore :respond_to?
82
98
  include Formula
83
99
  attr_reader :operation, :args, :target, :block
84
100
 
@@ -87,7 +103,7 @@ module Reg
87
103
  @operation = operation
88
104
  @args = args
89
105
  @block = block
90
- mod ||= args.find{|a| Formula===a }
106
+ mod ||= args.grep(Formula).first.class.ancestors.grep(DeferredQuery.reg|BackrefLike).first
91
107
  mod and extend mod
92
108
  end
93
109
 
@@ -110,8 +126,23 @@ module Reg
110
126
  new__no_const( *args)
111
127
  end
112
128
  end
129
+
130
+ def defang!(x)
131
+ class<<x
132
+ ms=instance_methods#.+(private_instance_methods)
133
+ ms.map!{|m| m.to_s}
134
+ candidates=ms.grep(/\A\#/)
135
+ candidates-=ms.grep(/\A[^\#]/).map{|n| "#"+n}
136
+ candidates.each{|n| alias_method n[1..-1],n }
137
+ undef method_missing
138
+ include Defanged
139
+ end if Deferred===x and not Defanged===x
140
+ return x
141
+ end
113
142
  end
114
143
 
144
+ module Defanged; end
145
+
115
146
  class Const
116
147
  include BlankSlate
117
148
  restore :inspect,:extend
@@ -1,6 +1,6 @@
1
1
  =begin copyright
2
2
  reg - the ruby extended grammar
3
- Copyright (C) 2005 Caleb Clausen
3
+ Copyright (C) 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,53 +16,51 @@
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
21
  module Reg
20
- class Position
21
- require 'reg'
22
-
23
- class<<self
24
- alias new__no_negatives
25
- def new(nums)
26
- nums.respond_to? :to_i and 0>nums and
27
- return PositionFromEnd.new(-nums)
28
- new__no_negatives nums
29
- end
30
- alias [] new
22
+ module Reg
23
+ def self.event(name)
24
+ EventEmitter.new name
31
25
  end
32
26
 
33
- def initialize(nums)
34
- Float===nums and nums=nums.to_i #enables Position[-0.1]
35
- @positions=nums
27
+ def fail_on(name)
28
+ EventReceiver.new(self,name)
36
29
  end
37
30
 
38
- def mmatch(pr)
39
- pos=@positions
40
- pos=adjust_position(pr,pos)
41
-
42
- to_res pos===pr.cursor.pos
43
-
44
- end
45
-
46
- def itemrange
47
- 0..0
31
+ def succeed_on(name)
32
+ EventReceiver.new(self,name,true)
48
33
  end
34
+
35
+ end
49
36
 
50
- private
51
- def adjust_position(pr,pos)
52
- pos
37
+ class EventEmitter
38
+ include Reg
39
+ def initialize name
40
+ @name=name
41
+ @name=@name.to_sym
53
42
  end
54
-
55
- def to_res bool
56
- bool ? 0 : nil
43
+
44
+ def === other
45
+ throw @name
57
46
  end
58
47
  end
59
48
 
60
-
61
- class PositionFromEnd < Position
62
- private
63
- def adjust_position(pr,pos)
64
- pr.cursor.size+pos
49
+ class EventReceiver
50
+ include Reg
51
+ def initialize reg,name,result=false
52
+ @reg,@name,@result=reg,name,result
53
+ @name=@name.to_sym
54
+ end
55
+
56
+ def === other
57
+ flag=nil
58
+ result=catch @name do
59
+ x= @reg===other ; flag=true ; x
60
+ end
61
+ flag ? result : @result
65
62
  end
66
63
  end
67
-
68
- end
64
+
65
+ def self.event(name); Reg.event(name) end
66
+ end
@@ -0,0 +1,28 @@
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
+ require 'roggraphedge'
20
+ module Reg
21
+
22
+ GraphTrace=::Rog::GraphTrace
23
+
24
+ GraphWalk=::Rog::GraphWalk
25
+
26
+ GraphEdge=::Rog::GraphEdge
27
+ GraphPoint=GraphEdge #hack, to be removed (GraphPoint is wrong terminology)
28
+ end
@@ -0,0 +1,631 @@
1
+
2
+ =begin copyright
3
+ reg - the ruby extended grammar
4
+ Copyright (C) 2005, 2016 Caleb Clausen
5
+
6
+ This library is free software; you can redistribute it and/or
7
+ modify it under the terms of the GNU Lesser General Public
8
+ License as published by the Free Software Foundation; either
9
+ version 2.1 of the License, or (at your option) any later version.
10
+
11
+ This library is distributed in the hope that it will be useful,
12
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
+ Lesser General Public License for more details.
15
+
16
+ You should have received a copy of the GNU Lesser General Public
17
+ License along with this library; if not, write to the Free Software
18
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
+ =end
20
+
21
+
22
+
23
+
24
+
25
+ module Reg
26
+
27
+
28
+ class Hash
29
+ include Reg,Composite
30
+ include CausesBacktracking #of course, it's not implmented correctly, right now
31
+ attr :others
32
+
33
+ def initialize(hashdat=nil)
34
+ @matchers={}
35
+ @literals={}
36
+ @others=nil
37
+ hashdat or return
38
+ hashdat.key?(OB) and @others=hashdat.delete(OB)
39
+ hashdat.each {|key,val|
40
+ key=Deferred.defang! key
41
+ val=Deferred.defang! val
42
+ if Reg.interesting_matcher? key
43
+ Fixed===key and key=key.unwrap
44
+ @matchers[key]=val
45
+ else
46
+ Equals===key and key=key.unwrap
47
+ @literals[key]=val
48
+ end
49
+ }
50
+ super
51
+ end
52
+
53
+ def initialize_copy(other)
54
+ @matchers,@literals=*other.instance_eval{[@matchers,@literals]}.map{|x| x.clone }
55
+ @others=other.instance_eval{@others}
56
+ @others=@others.clone if @others
57
+ end
58
+
59
+ def self.[](*args); new(*args); end
60
+
61
+ def matches_class; ::Hash end
62
+
63
+ def loose
64
+ result=clone
65
+ result.instance_variable_set(:@others,OB)
66
+ result
67
+ end
68
+ alias -@ loose
69
+
70
+ def ordered
71
+ pairs=[]
72
+ @literals.each{|k,v| pairs<< Pair[k,v] }
73
+ @matchers.each{|k,v| pairs<< Pair[k,v] }
74
+ pairs<<Pair[OB,@others] if @others
75
+ return +pairs
76
+ end
77
+
78
+ def subregs;
79
+ @literals.keys + @literals.values +
80
+ @matchers.keys + @matchers.values +
81
+ (@others==nil ? [OB,@others] : [])
82
+ end
83
+
84
+ def inspect
85
+ name="$RegInspectRecursing#{object_id}"
86
+ Thread.current[name] and return '+{...}'
87
+ Thread.current[name]=true
88
+
89
+ result=[]
90
+ result<<@literals.inspect[1..-2] unless @literals.empty?
91
+ result<<@matchers.inspect[1..-2] unless @matchers.empty?
92
+ result<<"_=>#{@others.inspect}" if defined? @others and @others!=nil
93
+ Thread.current[name]=nil
94
+ return "+{#{result.join(", ")}}"
95
+ end
96
+
97
+ def ===(other)
98
+ matchedliterals={}
99
+ matchedmatchers={}
100
+ other.each_pair{|key,val|
101
+ #literals get a chance first
102
+ @literals.key? key and
103
+ if (@literals[key]===val rescue false)
104
+ matchedliterals[key.__id__]=true
105
+ next
106
+ else
107
+ return
108
+ end
109
+
110
+ #now try more general matchers
111
+ saw_matcher=nil
112
+ @matchers.each_pair{|mkey,mval|
113
+ if (((mkey===key) rescue false))
114
+ return unless (mval===val rescue false)
115
+ saw_matcher=matchedmatchers[mkey.__id__]=true
116
+ break
117
+ end
118
+ }
119
+
120
+
121
+ #last of all, try the catchall
122
+ saw_matcher or (@others===val rescue false) or return
123
+ }
124
+
125
+ #make sure each pattern matched some key/value pair (even if it's the hash's #default value)
126
+ #...make sure each literal matched some key/value (or #default)
127
+ @literals.each_pair{|k,v| matchedliterals[k.__id__] or v==(other.default k) or return }
128
+
129
+ #...make sure each matcher matched some key/value (or #default)
130
+ @matchers.each_pair{|k,v| matchedmatchers[k.__id__] or (v===other.default rescue false) or return }
131
+
132
+ #...empty hash values match if catchall matches hash's #default value
133
+ #...and matcher was empty (except for catchall)
134
+ other.empty? and @literals.empty? and @matchers.empty? and return (@others===other.default rescue false)
135
+
136
+
137
+ return true
138
+ end
139
+
140
+ #too similar to #===
141
+ def mmatch_full(progress)
142
+ other= progress.cursor.readahead1
143
+ progress.newcontext self,other
144
+ matchedliterals={}
145
+ matchedmatchers={}
146
+ other.each_pair{|key,val|
147
+ progress.context_index=key
148
+ #literals get a chance first
149
+ progress.with_context GraphPoint::HashKey, val
150
+ @literals.key? key and
151
+ if @literals[key].mmatchhuh val
152
+ matchedliterals[key.__id__]=true
153
+ next
154
+ else
155
+ return
156
+ end
157
+
158
+ #now try more general matchers
159
+ progress.with_context GraphPoint::HashKey, key
160
+ saw_matcher=nil
161
+ @matchers.each_pair{|mkey,mval|
162
+ if mkey.mmatch progress
163
+ progress.with_context GraphPoint::HashValue, val
164
+ return unless (mval.mmatchhuh val)
165
+ saw_matcher=matchedmatchers[mkey.__id__]=true
166
+ break
167
+ end
168
+ }
169
+
170
+
171
+ #last of all, try the catchall
172
+ progress.with_context GraphPoint::HashValue, val
173
+ saw_matcher or @others.mmatch progress or return
174
+ }
175
+ progress.context_index=nil
176
+ progress.with_context GraphPoint::HashDefaultValue,(other.default)
177
+
178
+ #make sure each pattern matched some key/value pair (even if it's the hash's #default value)...
179
+ #...make sure each literal matched some key/value (or #default)
180
+ @literals.each_pair{|k,v| matchedliterals[k.__id__] or v==(other.default k) or return }
181
+
182
+ #...make sure each matcher matched some key/value (or #default)
183
+ @matchers.each_pair{|k,v| matchedmatchers[k.__id__] or v.mmatch progress or return }
184
+
185
+ #...empty hash values match if catchall matches hash's #default value
186
+ #...(and matcher was empty (except for catchall))
187
+ other.empty? and (@literals.empty? and @matchers.empty?) and return @others.mmatch( progress )
188
+ return [true, 1]
189
+ ensure
190
+ progress.endcontext
191
+ end
192
+
193
+ #tla of +{}
194
+ # assign_TLAs :Rah=>:Hash
195
+
196
+ end
197
+
198
+ #--------------------------
199
+ class RestrictHash
200
+ include Reg,Composite
201
+ def initialize a_hash
202
+ @filters=a_hash
203
+ super
204
+ end
205
+
206
+ def inspect
207
+ name="$RegInspectRecursing#{object_id}"
208
+ Thread.current[name] and return huh
209
+ Thread.current[name]=true
210
+ huh
211
+ Thread.current[name]=nil
212
+ end
213
+
214
+ def subregs
215
+ huh
216
+ end
217
+
218
+ def to_h
219
+ @filters
220
+ end
221
+
222
+ def === other
223
+ result={}
224
+ other.each_pair{|okey,oval|
225
+ @filters.each_pair{|fkey,fval|
226
+ if (fkey===okey rescue false) and (fval===oval rescue false)
227
+ result[okey]=oval
228
+ break
229
+ end
230
+ }
231
+ }
232
+ result unless result.empty?
233
+ end
234
+
235
+ #too similar to #===
236
+ def mmatch_full(progress)
237
+ huh "need to use ::Sequence::SingleItem"
238
+ other= progress.cursor.readahead1
239
+ progress.newcontext self,other
240
+ result={}
241
+ other.each_pair{|okey,oval|
242
+ @filters.each_pair{|fkey,fval|
243
+ progress.context_index=okey
244
+
245
+ progress.with_context GraphPoint::HashKey, okey
246
+ fkey.mmatch progress or next
247
+
248
+ progress.with_context GraphPoint::HashValue, oval
249
+ fval.mmatch progress or next
250
+
251
+ result[okey]=oval
252
+ break
253
+ }
254
+ }
255
+ progress.endcontext
256
+ return [true,1] unless result.empty?
257
+ end
258
+ end
259
+
260
+ #--------------------------
261
+ class OrderedHash
262
+ include Reg,Composite
263
+ include CausesBacktracking #of course, it's not implmented correctly, right now
264
+ def initialize(*args)
265
+ @keys=[]
266
+ @vals=[]
267
+ @others=nil
268
+ args.each{|a|
269
+ if Pair===a
270
+ l,r=a.left,a.right
271
+ Fixed===l and l=l.unwrap
272
+ if l==OB
273
+ @others=r
274
+ else
275
+ @keys<<Deferred.defang!(l)
276
+ @vals<<Deferred.defang!(r)
277
+ end
278
+ else
279
+ @keys<<Deferred.defang!(a)
280
+ @vals<<OB
281
+ end
282
+ }
283
+ super
284
+ end
285
+
286
+ def ===(other)
287
+ matched=0
288
+ saw1=nil
289
+ other.each_pair do |ko,vo|
290
+ saw1=nil
291
+ @vals.each_index do|i|
292
+ kr,vr=@keys[i],@vals[i]
293
+ if (kr===ko rescue false)
294
+ (vr===vo rescue false) or return
295
+ saw1=matched |= 1<<i
296
+ break
297
+ end
298
+ end
299
+ saw1 or ((@others===vo rescue false) or return)
300
+ end
301
+ @vals.each_index {|i|
302
+ if (matched&(1<<i)).zero?
303
+ dflt=other.default((@keys[i] unless Reg::interesting_matcher? @keys[i]))
304
+ (@vals[i]===dflt rescue false) or return
305
+ end
306
+ }
307
+ other.empty? and @vals.empty? and return (@others===other.default rescue false)
308
+ return other
309
+ end
310
+
311
+ #too similar to #===
312
+ def mmatch_full(progress)
313
+ huh
314
+ other= progress.cursor.readahead1
315
+ progress.newcontext self,other
316
+
317
+ matched=0
318
+ saw1=nil
319
+ other.each_pair do |ko,vo|
320
+ progress.context_index=ko
321
+ saw1=nil
322
+ @vals.each_index do|i|
323
+ kr,vr=@keys[i],@vals[i]
324
+ progress.with_context GraphPoint::HashKey, vo
325
+ if kr.mmatch progress
326
+ progress.with_context GraphPoint::HashValue, ko
327
+ vr.mmatch progress or return
328
+ saw1=matched |= 1<<i
329
+ break
330
+ end
331
+ end
332
+ progress.with_context GraphPoint::HashValue, vo
333
+ saw1 or (@others.mmatch progress or return)
334
+ end
335
+ @vals.each_index {|i|
336
+ if (matched&(1<<i)).zero?
337
+ default=other.default((@keys[i] unless Reg::interesting_matcher? @keys[i]))
338
+ progress.with_context GraphPoint::HashDefaultValue, default
339
+ @vals[i].mmatch progress or return
340
+ end
341
+ }
342
+ progress.with_context GraphPoint::HashDefaultValue, other.default
343
+ other.empty? and @vals.empty? and return( @others.mmatch progress )
344
+ return [true,1]
345
+ ensure
346
+ progress.endcontext
347
+ end
348
+
349
+ def self.[](*args); new(*args); end
350
+
351
+ def matches_class; ::Hash end
352
+
353
+ def inspect
354
+ name="$RegInspectRecursing#{object_id}"
355
+ Thread.current[name] and return '+[...**...]'
356
+ Thread.current[name]=true
357
+ result="+[#{
358
+ str=''
359
+ each_pair{|k,v|
360
+ str<< k.inspect+ ((Reg===k)? "" : ".reg") +
361
+ "**"+v.inspect+", " unless OB==k && nil==v
362
+ }
363
+ str
364
+ }]"
365
+ Thread.current[name]=nil
366
+ result
367
+ end
368
+ def subregs
369
+ result=@keys+@vals
370
+ result.push @others if @others
371
+ result
372
+ end
373
+
374
+ def each_pair
375
+ @keys.each_index{|i|
376
+ yield @keys[i],@vals[i]
377
+ }
378
+ yield OB,@others
379
+ end
380
+ # include Enumerable
381
+
382
+
383
+ def to_ruby
384
+ result= "def self.===(a_hash)\n"
385
+ result<<" a_hash.each_pair{|k,v|\n"
386
+ result<<" (case k\n"
387
+ @keys.each_index{|i|
388
+ result<<" when #{@keys[i]}: #{vals[i]}\n"
389
+ }
390
+ result<<" else #{@other}\n" +
391
+ " end===v rescue false) or break\n" +
392
+ " }\n" +
393
+ "end\n"
394
+
395
+ return result
396
+ end
397
+ end
398
+
399
+ #--------------------------
400
+ class Object #< Hash
401
+ #decending from Hash isn't particularly useful here
402
+ #it looks like everything is overridden, anyway
403
+ include Reg,Composite
404
+ include CausesBacktracking #of course, it's not implemented correctly, right now
405
+
406
+ def initialize(*args)
407
+ hash= (::Hash===args.last ? args.pop : {})
408
+
409
+ @vars={}; @meths={}; @meth_matchers={}; @var_matchers={}
410
+ hash.each_pair{|item,val|
411
+ if ::String===item or ::Symbol===item
412
+ item=item.to_s
413
+ (/^@@?/===item ? @vars : @meths)[item.to_sym]=Deferred.defang! val
414
+ elsif Regexp===item && item.source[/^\^?[@A-Z]/]
415
+ @var_matchers[item]=Deferred.defang! val
416
+ elsif Wrapper===item
417
+ @meth_matchers[item.unwrap]=Deferred.defang! val
418
+ else
419
+ @meth_matchers[Deferred.defang!( item )]=Deferred.defang!( val )
420
+ end
421
+ }
422
+ @meths[:class]=args.shift if (Class===args.first)
423
+
424
+ super
425
+ end
426
+ def self.[](*args) new(*args); end
427
+
428
+
429
+ def inspect
430
+ name="$RegInspectRecursing#{object_id}"
431
+ Thread.current[name] and return '+[...**...]'
432
+ Thread.current[name]=true
433
+ result= "-{#{
434
+ [@vars,@meths,@var_matchers,@meth_matchers].map{|h|
435
+ h.inspect[1..-2]+", "
436
+ }.join('')}}"
437
+ Thread.current[name]=nil
438
+ result
439
+ end
440
+
441
+ def subregs
442
+ @vars.keys+@vars.values+
443
+ @meths.keys+@meths.values+
444
+ @meth_matchers.keys+@meth_matchers.values+
445
+ @var_matchers.keys+@var_matchers.values
446
+ end
447
+
448
+ def to_h
449
+ [@vars,@meths,@meth_matchers,@var_matchers].inject{|sum,h|
450
+ sum.merge h
451
+ }
452
+ end
453
+
454
+ def ===(other)
455
+ seenmeths=[];seenvars=[]; #maybe not needed?
456
+ seenvarmats=[];seenmats=[]
457
+ @meths.each_pair{|name,val|
458
+ (val===other.send(name) rescue false) or return
459
+ seenmeths<<name
460
+ }
461
+ @vars.each_pair{|name,val|
462
+ (val===other.instance_eval(name.to_s) rescue false) or return
463
+ seenvars<<name
464
+ }
465
+ @meth_matchers.empty? or other.public_methods.each {|meth|
466
+ #I should consider preventing methods that are in Object.instance_methods from being called here
467
+ #or perhaps only known dangerous methods from Object and Kernel such as #freeze and #send
468
+ next if seenmeths.include? meth
469
+ @meth_matchers.each_pair{|name, val|
470
+ if (name===meth rescue false)
471
+ (val===other.send(meth) rescue false) or return
472
+ seenmats<< name.__id__
473
+ end
474
+ }
475
+ }
476
+
477
+ @var_matchers.empty? or other.instance_variables.each {|var|
478
+ next if seenvars.include? var
479
+ @var_matchers.each_pair{|name,val|
480
+ if (name===var and val===other.instance_eval(name.to_s) rescue false)
481
+ seenvarmats<<name.__id__
482
+ end
483
+ }
484
+ }
485
+ #todo:should support class, global, and constant variables here too?!
486
+
487
+ @meths.keys.-(seenmeths).empty? or return
488
+ @vars.keys.-(seenvars).empty? or return
489
+ @meth_matchers.keys.map{|k| k.__id__}.-(seenmats).empty? or return
490
+ @var_matchers.keys.map{|k| k.__id__}.-(seenvarmats).empty? or return
491
+
492
+ return other || true
493
+
494
+ rescue
495
+ return false
496
+ end
497
+
498
+
499
+ #too similar to #===
500
+ def mmatch_full(progress)
501
+ huh
502
+ other= progress.cursor.readahead1
503
+ progress.newcontext self,other
504
+
505
+ seenmeths=[];seenvars=[]; #maybe not needed?
506
+ seenmats=[];seenvarmats=[]
507
+ @meths.each_pair{|name,val|
508
+ progress.context_index=name
509
+ progress.with_context GraphPoint::ObjectMethValue, other.send(name)
510
+ val.mmatch progress or return
511
+ seenmeths<<name
512
+ }
513
+ @vars.each_pair{|name,val|
514
+ progress.context_index=name
515
+ progress.with_context GraphPoint::ObjectIvarValue, other.instance_eval(name.to_s)
516
+ val.mmatch progress or return
517
+ seenvars<<name
518
+ }
519
+ @meth_matchers.empty? or other.public_methods.each {|meth|
520
+ next if seenmeths.include? meth
521
+ @meth_matchers.each_pair{|name, val|
522
+ progress.context_index=meth
523
+ progress.with_context GraphPoint::ObjectName, meth
524
+ if name.mmatch progress
525
+ progress.with_context GraphPoint::ObjectMethValue, other.send(meth)
526
+ val.mmatch progress and seenmats<< name.__id__
527
+ end
528
+ }
529
+ }
530
+ @var_matchers.empty? or other.instance_variables.each {|var|
531
+ next if seenvars.include? var
532
+ @var_matchers.each_pair{|name,val|
533
+ progress.context_index=var
534
+ progress.with_context GraphPoint::ObjectName, var
535
+ if name.mmatch progress
536
+ progress.with_context GraphPoint::ObjectIvarValue, other.instance_eval(name.to_s)
537
+ val.mmatch other.instance_eval(name.to_s) and
538
+ seenvarmats<<name.__id__
539
+ end
540
+ }
541
+ }
542
+ #todo:should support class, global, and constant variables here too!
543
+ @meths.keys.-(seenmeths).empty? or return
544
+ @vars.keys.-(seenvars).empty? or return
545
+ @meth_matchers.keys.map{|k| k.__id__}.-(seenmats).empty? or return
546
+ @var_matchers.keys.map{|k| k.__id__}.-(seenvarmats).empty? or return
547
+
548
+
549
+ return [true,1]
550
+
551
+ rescue Exception
552
+ return false
553
+ ensure
554
+ progress.endcontext
555
+ end
556
+
557
+ #tla of -{}
558
+ # assign_TLAs :Rob=>:Object
559
+
560
+
561
+ end
562
+
563
+
564
+ #OrderedObject not even attempted yet
565
+
566
+ module Reg
567
+
568
+ #pairing operator
569
+ def **(other)
570
+ Pair[self,other]
571
+ end
572
+ alias to **
573
+
574
+
575
+ end
576
+
577
+ class ::Array
578
+ #pairing operator
579
+ def **(other)
580
+ Pair[self,other]
581
+ end
582
+ end
583
+ class ::String
584
+ #pairing operator
585
+ def **(other)
586
+ Pair[self,other]
587
+ end
588
+ end
589
+ class ::Symbol
590
+ #pairing operator
591
+ def **(other)
592
+ Pair[self,other]
593
+ end
594
+ end
595
+
596
+
597
+ class Pair
598
+ include Reg
599
+ class<<self; alias [] new; end
600
+
601
+ attr_reader :left,:right
602
+
603
+ def initialize(l,r)
604
+ @left,@right=Deferred.defang!(l),Deferred.defang!(r)
605
+ #super
606
+ end
607
+
608
+ def to_a; [@left,@right] end
609
+ alias to_ary to_a #mebbe to_ary too?
610
+
611
+ if false #not sure if i know what i want here...
612
+ def hash_cmp(hash,k,v)
613
+ @left
614
+ end
615
+
616
+ def obj_cmp
617
+ end
618
+ end
619
+ #tla of **
620
+ #assign_TLAs :Rap=>:Pair
621
+
622
+
623
+
624
+ end
625
+
626
+
627
+
628
+ end
629
+
630
+
631
+