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.
- checksums.yaml +4 -0
- data/COPYING +0 -0
- data/History.txt +14 -0
- data/Makefile +59 -0
- data/README +87 -40
- data/article.txt +838 -0
- data/{assert.rb → lib/assert.rb} +3 -3
- data/{reg.rb → lib/reg.rb} +11 -4
- data/lib/reg/version.rb +21 -0
- data/lib/regarray.rb +455 -0
- data/{regarrayold.rb → lib/regarrayold.rb} +33 -7
- data/lib/regbackref.rb +73 -0
- data/lib/regbind.rb +230 -0
- data/{regcase.rb → lib/regcase.rb} +15 -5
- data/lib/regcompiler.rb +2341 -0
- data/{regcore.rb → lib/regcore.rb} +196 -85
- data/{regdeferred.rb → lib/regdeferred.rb} +35 -4
- data/{regposition.rb → lib/regevent.rb} +36 -38
- data/lib/reggraphpoint.rb +28 -0
- data/lib/reghash.rb +631 -0
- data/lib/reginstrumentation.rb +36 -0
- data/{regitem_that.rb → lib/regitem_that.rb} +32 -11
- data/{regknows.rb → lib/regknows.rb} +4 -2
- data/{reglogic.rb → lib/reglogic.rb} +76 -59
- data/{reglookab.rb → lib/reglookab.rb} +31 -21
- data/lib/regmatchset.rb +323 -0
- data/{regold.rb → lib/regold.rb} +27 -27
- data/{regpath.rb → lib/regpath.rb} +91 -1
- data/lib/regposition.rb +79 -0
- data/lib/regprogress.rb +1522 -0
- data/lib/regrepeat.rb +307 -0
- data/lib/regreplace.rb +254 -0
- data/lib/regslicing.rb +581 -0
- data/lib/regsubseq.rb +72 -0
- data/lib/regsugar.rb +361 -0
- data/lib/regvar.rb +180 -0
- data/lib/regxform.rb +212 -0
- data/{trace.rb → lib/trace_during.rb} +6 -4
- data/lib/warning.rb +37 -0
- data/parser.txt +26 -8
- data/philosophy.txt +18 -0
- data/reg.gemspec +58 -25
- data/regguide.txt +18 -0
- data/test/andtest.rb +46 -0
- data/test/regcompiler_test.rb +346 -0
- data/test/regdemo.rb +20 -0
- data/{item_thattest.rb → test/regitem_thattest.rb} +2 -2
- data/test/regtest.rb +2125 -0
- data/test/test_all.rb +32 -0
- data/test/test_reg.rb +19 -0
- metadata +108 -73
- data/calc.reg +0 -73
- data/forward_to.rb +0 -49
- data/numberset.rb +0 -200
- data/regarray.rb +0 -675
- data/regbackref.rb +0 -126
- data/regbind.rb +0 -74
- data/reggrid.csv +1 -2
- data/reghash.rb +0 -318
- data/regprogress.rb +0 -1054
- data/regreplace.rb +0 -114
- data/regsugar.rb +0 -230
- data/regtest.rb +0 -1078
- 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
|
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.
|
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)
|
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
|
-
|
21
|
-
|
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
|
34
|
-
|
35
|
-
@positions=nums
|
27
|
+
def fail_on(name)
|
28
|
+
EventReceiver.new(self,name)
|
36
29
|
end
|
37
30
|
|
38
|
-
def
|
39
|
-
|
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
|
-
|
51
|
-
|
52
|
-
|
37
|
+
class EventEmitter
|
38
|
+
include Reg
|
39
|
+
def initialize name
|
40
|
+
@name=name
|
41
|
+
@name=@name.to_sym
|
53
42
|
end
|
54
|
-
|
55
|
-
def
|
56
|
-
|
43
|
+
|
44
|
+
def === other
|
45
|
+
throw @name
|
57
46
|
end
|
58
47
|
end
|
59
48
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
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
|
data/lib/reghash.rb
ADDED
@@ -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
|
+
|