reg 0.4.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,318 @@
1
+
2
+ =begin copyright
3
+ reg - the ruby extended grammar
4
+ Copyright (C) 2005 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
+ require 'forward_to'
23
+
24
+
25
+
26
+ module Reg
27
+
28
+ class Hash
29
+ include Reg
30
+ attr :others
31
+
32
+ def initialize(hashdat=nil)
33
+ @matchers={}
34
+ @literals={}
35
+ @others=nil
36
+ hashdat or return
37
+ hashdat.key?(OB) and @others=hashdat.delete(OB)
38
+ hashdat.each {|key,val|
39
+ if Reg.interesting_matcher? key
40
+ Fixed===key and key=key.unwrap
41
+ @matchers[key]=val
42
+ else
43
+ Equals===key and key=key.unwrap
44
+ @literals[key]=val
45
+ end
46
+ }
47
+ end
48
+
49
+ def Hash.[](*args); new(*args); end
50
+
51
+ def matches_class; ::Hash end
52
+
53
+ def ordered
54
+ pairs=[]
55
+ @literals.each{|k,v| pairs<< Pair[k,v] }
56
+ @matchers.each{|k,v| pairs<< Pair[k,v] }
57
+ pairs<<Pair[OB,@others] if @others
58
+ return +pairs
59
+ end
60
+
61
+ def subregs;
62
+ @literals.keys + @literals.values +
63
+ @matchers.keys + @matchers.values +
64
+ (@others==nil ? [OB,@others] : [])
65
+ end
66
+
67
+ def inspect
68
+ result=[]
69
+ result<<@literals.inspect.sub(/.(.*)./, "\\1") unless @literals.empty?
70
+ result<<@matchers.inspect.sub(/.(.*)./, "\\1") unless @matchers.empty?
71
+ result<<"OB=>#{@others.inspect}" if defined? @others and @others!=nil
72
+ return "+{#{result.join(", ")}}"
73
+ end
74
+
75
+ def -@ #make object matcher
76
+ Rob(@literals.merge(@matchers).merge(OB=>@others))
77
+ end
78
+
79
+ def ===(other)
80
+ matchedliterals={}
81
+ matchedmatchers={}
82
+ other.each_pair{|key,val|
83
+ #literals get a chance first
84
+ @literals.key? key and
85
+ if (@literals[key]===val)
86
+ matchedliterals[key]=true
87
+ next
88
+ else
89
+ return
90
+ end
91
+
92
+ #now try more general matchers
93
+ saw_matcher=nil
94
+ @matchers.each_pair{|mkey,mval|
95
+ if mkey===key
96
+ return unless (mval===val)
97
+ saw_matcher=matchedmatchers[mkey]=true
98
+ break
99
+ end
100
+ }
101
+
102
+
103
+ #last of all, try the catchall
104
+ saw_matcher or @others===val or return
105
+ }
106
+ @literals.each_pair{|k,v| matchedliterals[k] or v==(other.default k) or return }
107
+ @matchers.each_pair{|k,v| matchedmatchers[k] or v===other.default or return }
108
+ other.empty? and @literals.empty? and @matchers.empty? and return @others===other.default
109
+ return true
110
+ end
111
+
112
+ #tla of +{}
113
+ assign_TLAs :Rah=>:Hash
114
+
115
+ end
116
+
117
+ #--------------------------
118
+ class OrderedHash
119
+ include Reg
120
+ def initialize(*args)
121
+ @keys=[]
122
+ @vals=[]
123
+ @others=nil
124
+ args.each{|a|
125
+ if Pair===a
126
+ l,r=a.left,a.right
127
+ Fixed===l and l=l.unwrap
128
+ if l==OB
129
+ @others=r
130
+ else
131
+ @keys<<l
132
+ @vals<<r
133
+ end
134
+ else
135
+ @keys<<a
136
+ @vals<<OB
137
+ end
138
+ }
139
+ end
140
+
141
+ def ===(other)
142
+ matched=0
143
+ saw1=nil
144
+ other.each_pair do |ko,vo|
145
+ saw1=nil
146
+ @vals.each_index do|i|
147
+ kr,vr=@keys[i],@vals[i]
148
+ if kr===ko
149
+ vr===vo or return
150
+ saw1=matched |= 1<<i
151
+ break
152
+ end
153
+ end
154
+ saw1 or (@others===vo or return)
155
+ end
156
+ @vals.each_index {|i|
157
+ unless (matched&(1<<i)).nonzero?
158
+ @vals[i]===other.default((@keys[i] unless Reg::interesting_matcher? @keys[i])) or return
159
+ end
160
+ }
161
+ other.empty? and @vals.empty? and return @others===other.default
162
+ # @subhashes.each do|subhash|
163
+ # subhash===other or return false
164
+ # end
165
+ return other||true #huh need more complex result?
166
+ end
167
+
168
+ def self.[](*args); new(*args); end
169
+
170
+ def matches_class; ::Hash end
171
+
172
+ def &; huh end
173
+ def inspect;
174
+ "+[#{
175
+ map{|k,v| k.inspect+ ((Reg===k)? "" : ".reg") +
176
+ "**"+v.inspect unless OB==k && nil==v
177
+ }.compact.join ", "
178
+ }]"
179
+ end
180
+ def subregs; huh end
181
+
182
+ def each
183
+ @keys.each_index{|i|
184
+ yield @keys[i],@vals[i]
185
+ }
186
+ yield OB,@others
187
+ end
188
+ include Enumerable
189
+
190
+
191
+ def to_ruby
192
+ result= "def self.===(a_hash)\n"
193
+ result<<" a_hash.each_pair{|k,v|\n"
194
+ result<<" case k\n"
195
+ @keys.each_index{|i|
196
+ result<<" when #{@keys[i]}: #{vals[i]}\n"
197
+ }
198
+ result<<" else #{@other}\n" +
199
+ " end===v or break\n" +
200
+ " }\n" +
201
+ "end\n"
202
+
203
+ return result
204
+ end
205
+ end
206
+
207
+ #--------------------------
208
+ class Object < Hash
209
+ #decending from Hash isn't particularly useful here
210
+ #it looks like everything (but &) is overridden, anyway
211
+
212
+ def initialize(*args)
213
+ hash= (::Hash===args.last ? args.pop : {})
214
+ @vars={}; @meths={}; @meth_matchers={}
215
+ hash.each_pair{|item,val|
216
+ if ::String===item or ::Symbol===item
217
+ item=item.to_s
218
+ (/^@@?/===item ? @vars : @meths)[item.to_sym]=val
219
+ else
220
+ @meth_matchers[item]=val
221
+ end
222
+ }
223
+ @meths[:class]=args.shift if (Module===args.first)
224
+ end
225
+ def self.[](*args) new(*args); end
226
+
227
+
228
+ def inspect
229
+ "-{"+@vars.inspect.sub( /^.(.*).$/, '\\1') +
230
+ @meths.inspect.sub(/^.(.*).$/, '\\1') +
231
+ @meth_matchers.inspect.sub(/^.(.*).$/, '\\1') + "}"
232
+
233
+ end
234
+
235
+ def matches_class
236
+ @meths[:class] or Object
237
+ end
238
+
239
+ def -@ #make object matcher
240
+ self
241
+ end
242
+
243
+ def ===(other)
244
+ seenmeths=[];seenvars=[];seenmats=[]
245
+ @meths.each_pair{|name,val|
246
+ val===other.send(name) or return
247
+ seenmeths<<name
248
+ }
249
+ @vars.each_pair{|name,val|
250
+ val===other.instance_eval(name.to_s) or return
251
+ seenvars<<name
252
+ }
253
+ @meth_matchers.empty? or other.public_methods.each {|meth|
254
+ @meth_matchers.each_pair{|name, val|
255
+ if name===meth
256
+ val===other.send(meth) || return
257
+ seenmats<< name
258
+ end
259
+ }
260
+ }
261
+ @meths.keys.-(seenmeths).empty? or return
262
+ @vars.keys.-(seenvars).empty? or return
263
+ @meth_matchers.keys.-(seenmats).empty? or return
264
+
265
+
266
+ return other || true
267
+
268
+ rescue
269
+ return false
270
+ end
271
+
272
+ #tla of -{}
273
+ assign_TLAs :Rob=>:Object
274
+
275
+
276
+ end
277
+
278
+
279
+ #OrderedObject not even attempted yet
280
+
281
+ module Reg
282
+ def **(other)
283
+ Pair[self,other]
284
+ end
285
+ alias has **
286
+ end
287
+
288
+ class Pair
289
+ include Reg
290
+ class<<self; alias [] new; end
291
+
292
+ attr_reader :left,:right
293
+
294
+ def initialize(l,r)
295
+ @left,@right=l,r
296
+ end
297
+
298
+ if false #not sure if i know what i want here...
299
+ def hash_cmp(hash,k,v)
300
+ @left
301
+ end
302
+
303
+ def obj_cmp
304
+ end
305
+ end
306
+ #tla of **
307
+ assign_TLAs :Rap=>:Pair
308
+
309
+
310
+
311
+ end
312
+
313
+
314
+
315
+ end
316
+
317
+
318
+
@@ -0,0 +1,146 @@
1
+ =begin copyright
2
+ reg - the ruby extended grammar
3
+ Copyright (C) 2005 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 'regdeferred.rb'
20
+
21
+ module Reg
22
+ class <<self
23
+ #sugar forwards this from Kernel
24
+ def item_that(klass=nil,&block)
25
+ return ItemThat.new(klass) unless block
26
+
27
+ class <<block
28
+ #include arguments to include appear to be processed in a strange order... this is
29
+ #significant if order is important to you
30
+ #the #included methods are perhaps not called when i think they should be....
31
+ #(DON'T simplify the next line; it'll break.)
32
+ [BlankSlate ,Formula, BlockLike].each{|mod| include mod}
33
+ restore :inspect,:extend,:call
34
+
35
+ alias === eeee #workaround-- shouldn't be needed
36
+ alias formula_value call
37
+ # undef eeee
38
+ end
39
+ block.klass=klass
40
+ block
41
+ end
42
+ alias item_is item_that
43
+ end
44
+
45
+ #----------------------------------
46
+ module BlockLike
47
+ # include Formula
48
+
49
+ attr_writer :klass #for internal use only
50
+
51
+ def eeee(val)
52
+ @klass and @klass===val || return
53
+ begin call(val)
54
+ rescue: false
55
+ end
56
+ end
57
+ alias === eeee #does nothing in includers.... why?
58
+ def formula_value *a,&b; call( *a,&b) end
59
+
60
+
61
+ def mixmod; ItemThatLike end
62
+ def reg; dup.extend Reg end
63
+ end
64
+
65
+ #----------------------------------
66
+ module DeferredQuery
67
+ #just an ancestor for ItemThat and RegThat
68
+ def eee(item)
69
+ begin formula_value item
70
+ rescue: false
71
+ end
72
+ end
73
+ alias === eee #this doesn't work!!! WHY????
74
+ #there's no way to define the method === in this
75
+ #module and have it be defined in class ItemThat.
76
+ #mixmod and reg don't have this problem. this must
77
+ #be a bug. for now, I work around it with clever
78
+ #alias/undefing in places that include/extend ItemThatLike
79
+ #(seemingly, this is only a problem when including, not extending... dunno why)
80
+ #this bug may be gone now; need to try to get rid of weird eee stuff.
81
+
82
+ end
83
+
84
+ #----------------------------------
85
+ module ItemThatLike
86
+ include DeferredQuery
87
+
88
+ def mixmod; ItemThatLike end
89
+ def reg; dup.extend RegThatLike end
90
+ end
91
+
92
+ #----------------------------------
93
+ class ItemThat
94
+ include BlankSlate
95
+ restore :inspect,:extend
96
+ include Formula
97
+ include ItemThatLike
98
+ alias === eee
99
+ undef eee
100
+ def initialize(klass=nil)
101
+ @klass=klass
102
+ end
103
+
104
+ def formula_value(val,*rest)
105
+ #the exception raised here should be (eventually) caught by
106
+ #the handler in ItemThatLike#eee. calling ItemThat#formula_value isn't
107
+ #really legitimate otherwise.
108
+ @klass and @klass===val || fail("item_that constraint mismatch")
109
+
110
+ val
111
+ end
112
+
113
+ end
114
+
115
+ #----------------------------------
116
+ module RegThatLike
117
+ include DeferredQuery
118
+ include Reg
119
+
120
+ def mixmod; RegThatLike end
121
+ end
122
+
123
+ #----------------------------------
124
+ class RegThat
125
+ include BlankSlate
126
+ restore :inspect,:extend
127
+ include Formula
128
+ include RegThatLike
129
+ alias === eee
130
+ undef eee
131
+ def initialize(klass=nil)
132
+ @klass=klass
133
+ end
134
+
135
+ def formula_value(val,*rest)
136
+ #the exception raised here should be (eventually) caught by
137
+ #the handler in RegThatLike#eee. calling RegThat#formula_value isn't
138
+ #really legitimate otherwise.
139
+ @klass and @klass===val || fail("item_that constraint mismatch")
140
+
141
+ val
142
+ end
143
+
144
+ end
145
+
146
+ end