DeepConnect 0.4.06
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/deep-connect.rb +83 -0
- data/lib/deep-connect/accepter.rb +64 -0
- data/lib/deep-connect/class-spec-space.rb +652 -0
- data/lib/deep-connect/conf.rb +48 -0
- data/lib/deep-connect/cron.rb +91 -0
- data/lib/deep-connect/deep-fork.rb +70 -0
- data/lib/deep-connect/deep-mq.rb +62 -0
- data/lib/deep-connect/deep-space.rb +403 -0
- data/lib/deep-connect/evaluator.rb +149 -0
- data/lib/deep-connect/event.rb +551 -0
- data/lib/deep-connect/exceptions.rb +38 -0
- data/lib/deep-connect/future.rb +67 -0
- data/lib/deep-connect/organizer.rb +378 -0
- data/lib/deep-connect/port.rb +151 -0
- data/lib/deep-connect/reference.rb +422 -0
- data/lib/deep-connect/serialize.rb +127 -0
- data/lib/deep-connect/session.rb +348 -0
- data/lib/deep-connect/version.rb +8 -0
- metadata +86 -0
data/lib/deep-connect.rb
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
#
|
3
|
+
# deep-connect.rb -
|
4
|
+
# Copyright (C) 1996-2010 Keiju ISHITSUKA
|
5
|
+
# (Penta Advanced Labrabries, Co.,Ltd)
|
6
|
+
#
|
7
|
+
|
8
|
+
require "forwardable"
|
9
|
+
|
10
|
+
require "deep-connect/conf"
|
11
|
+
|
12
|
+
module DeepConnect
|
13
|
+
@RCS_ID='-$Id: $-'
|
14
|
+
|
15
|
+
# DC is a internal using short cut of DeepConnect .
|
16
|
+
DC = DeepConnect
|
17
|
+
Conf = Config.new
|
18
|
+
end
|
19
|
+
|
20
|
+
require "deep-connect/organizer"
|
21
|
+
|
22
|
+
module DeepConnect
|
23
|
+
class DeepConnect
|
24
|
+
extend Forwardable
|
25
|
+
|
26
|
+
def self.start(service=0)
|
27
|
+
dc = new
|
28
|
+
dc.start(service)
|
29
|
+
dc
|
30
|
+
end
|
31
|
+
|
32
|
+
def initialize
|
33
|
+
@organizer = Organizer.new
|
34
|
+
end
|
35
|
+
|
36
|
+
def_delegator :@organizer, :start
|
37
|
+
def_delegator :@organizer, :stop
|
38
|
+
|
39
|
+
def_delegator :@organizer, :open_deep_space
|
40
|
+
def_delegator :@organizer, :open_deepspace
|
41
|
+
def_delegator :@organizer, :close_deep_space
|
42
|
+
def_delegator :@organizer, :close_deepspace
|
43
|
+
def_delegator :@organizer, :when_connected
|
44
|
+
def_delegator :@organizer, :when_disconnected
|
45
|
+
|
46
|
+
def_delegator :@organizer, :export
|
47
|
+
def_delegator :@organizer, :register_service
|
48
|
+
|
49
|
+
def_delegator :@organizer, :export_mq
|
50
|
+
|
51
|
+
def_delegator :@organizer, :release_object
|
52
|
+
|
53
|
+
def_delegator :@organizer, :local_id
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
def DC.start(service = nil)
|
58
|
+
DeepConnect.start(service)
|
59
|
+
end
|
60
|
+
|
61
|
+
def DC.def_method_spec(*opts)
|
62
|
+
Organizer.def_method_spec(*opts)
|
63
|
+
end
|
64
|
+
|
65
|
+
def DC.def_single_method_spec(*opts)
|
66
|
+
Organizer.def_single_method_spec(*opts)
|
67
|
+
end
|
68
|
+
|
69
|
+
def DC.def_interface(*opts)
|
70
|
+
Organizer.def_interface(*opts)
|
71
|
+
end
|
72
|
+
|
73
|
+
def DC.def_single_interface(*opts)
|
74
|
+
Organizer.def_single_interface(*opts)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
require "deep-connect/serialize"
|
79
|
+
|
80
|
+
|
81
|
+
|
82
|
+
|
83
|
+
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
#
|
3
|
+
# accepter.rb -
|
4
|
+
# Copyright (C) 1996-2010 Keiju ISHITSUKA
|
5
|
+
# (Penta Advanced Labrabries, Co.,Ltd)
|
6
|
+
#
|
7
|
+
|
8
|
+
|
9
|
+
require "socket"
|
10
|
+
require "ipaddr"
|
11
|
+
|
12
|
+
require "deep-connect/event"
|
13
|
+
|
14
|
+
module DeepConnect
|
15
|
+
class Accepter
|
16
|
+
def initialize(org)
|
17
|
+
@organizer = org
|
18
|
+
@probe = nil
|
19
|
+
end
|
20
|
+
|
21
|
+
def port_number
|
22
|
+
@probe.addr[1]
|
23
|
+
end
|
24
|
+
|
25
|
+
def open(service = 0)
|
26
|
+
@probe = TCPServer.open("", service)
|
27
|
+
end
|
28
|
+
|
29
|
+
def start
|
30
|
+
@probe_thread = Thread.start {
|
31
|
+
loop do
|
32
|
+
sock = @probe.accept
|
33
|
+
Thread.start do
|
34
|
+
port = Port.new(sock)
|
35
|
+
begin
|
36
|
+
unless (ev = port.import).kind_of?(Event::InitSessionEvent)
|
37
|
+
puts "WARN: 接続初期化エラー: [#{port.peeraddr}]"
|
38
|
+
end
|
39
|
+
begin
|
40
|
+
@organizer.connect_deep_space_with_port port, ev.local_id
|
41
|
+
rescue ConnectCancel
|
42
|
+
puts "INFO: クライアント(#{ev.local_id}からの接続を拒否しました."
|
43
|
+
rescue ConnectionRefused
|
44
|
+
puts "WARN: クライアント(#{ev.local_id}への接続が拒否されました"
|
45
|
+
rescue ProtocolError, IOError
|
46
|
+
puts "WARN: 接続初期化エラー: [#{port.peeraddr}]"
|
47
|
+
|
48
|
+
end
|
49
|
+
rescue EOFError
|
50
|
+
puts "WARN: 接続初期化中に[#{port.peeraddr}]との接続が切れました"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
}
|
55
|
+
end
|
56
|
+
|
57
|
+
def stop
|
58
|
+
@probe_thread.exit
|
59
|
+
@probe.close
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
|
@@ -0,0 +1,652 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
#
|
3
|
+
# class-spec-space.rb -
|
4
|
+
# Copyright (C) 1996-2010 Keiju ISHITSUKA
|
5
|
+
# (Penta Advanced Labrabries, Co.,Ltd)
|
6
|
+
#
|
7
|
+
|
8
|
+
require "thread"
|
9
|
+
require "e2mmap"
|
10
|
+
|
11
|
+
module DeepConnect
|
12
|
+
|
13
|
+
class ClassSpecSpace
|
14
|
+
NULL = :NULL
|
15
|
+
|
16
|
+
def initialize(remote = :remote)
|
17
|
+
case remote
|
18
|
+
when :remote
|
19
|
+
@class_specs = nil
|
20
|
+
when :local
|
21
|
+
@class_specs = {}
|
22
|
+
end
|
23
|
+
|
24
|
+
@class_specs_mutex = Mutex.new
|
25
|
+
@class_specs_cv = ConditionVariable.new
|
26
|
+
|
27
|
+
@method_spec_cache = {}
|
28
|
+
end
|
29
|
+
|
30
|
+
def class_spec_id_of(obj)
|
31
|
+
ancestors = obj.class.ancestors
|
32
|
+
begin
|
33
|
+
single = (class<<obj;self;end)
|
34
|
+
ancestors.unshift single
|
35
|
+
rescue
|
36
|
+
end
|
37
|
+
#p ancestors
|
38
|
+
# p ancestors.collect{|e| e.object_id}
|
39
|
+
klass = ancestors.find{|kls|
|
40
|
+
@class_specs[kls.object_id]
|
41
|
+
}
|
42
|
+
if klass
|
43
|
+
klass.object_id
|
44
|
+
else
|
45
|
+
nil
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def method_spec(ref_or_obj, method)
|
50
|
+
puts "method_spec(#{ref_or_obj}, #{method})" if Conf.DISPLAY_METHOD_SPEC
|
51
|
+
if ref_or_obj.__deep_connect_reference?
|
52
|
+
csid = ref_or_obj.csid
|
53
|
+
else
|
54
|
+
csid = class_spec_id_of(ref_or_obj)
|
55
|
+
end
|
56
|
+
return nil unless csid
|
57
|
+
|
58
|
+
# mid = [csid, method]
|
59
|
+
# mid = sprintf("%X-%s", csid, method)
|
60
|
+
mid = "#{csid}-#{method}"
|
61
|
+
case mspec = @method_spec_cache[mid]
|
62
|
+
when nil
|
63
|
+
# pass
|
64
|
+
when NULL
|
65
|
+
return nil
|
66
|
+
else
|
67
|
+
return mspec
|
68
|
+
end
|
69
|
+
|
70
|
+
class_spec_ancestors(csid) do |cspec|
|
71
|
+
if mspec = cspec.method_spec(method)
|
72
|
+
return mspec
|
73
|
+
end
|
74
|
+
end
|
75
|
+
@method_spec_cache[mid] = NULL
|
76
|
+
return nil
|
77
|
+
end
|
78
|
+
|
79
|
+
def def_method_spec(klass, *method_spec)
|
80
|
+
csid = klass.object_id
|
81
|
+
unless cspec = @class_specs[csid]
|
82
|
+
cspec = ClassSpec.new(klass)
|
83
|
+
@class_specs[csid] = cspec
|
84
|
+
end
|
85
|
+
|
86
|
+
if method_spec.size == 1 and method_spec.first.kind_of?(MethodSpec)
|
87
|
+
mspec = method_spec.first
|
88
|
+
else
|
89
|
+
mspec = MethodSpec.spec(*method_spec)
|
90
|
+
end
|
91
|
+
cspec.add_method_spec(mspec)
|
92
|
+
end
|
93
|
+
|
94
|
+
def def_single_method_spec(obj, method_spec)
|
95
|
+
klass = class<<obj;self;end
|
96
|
+
def_method_spec(klass, method_spec)
|
97
|
+
end
|
98
|
+
|
99
|
+
def def_interface(klass, method)
|
100
|
+
mspec = MethodSpec.new
|
101
|
+
mspec.method = method
|
102
|
+
mspec.interface = true
|
103
|
+
def_method_spec(klass, mspec)
|
104
|
+
end
|
105
|
+
|
106
|
+
def def_single_interface(obj, method)
|
107
|
+
klass = class<<obj;self;end
|
108
|
+
def_interface(klass, method)
|
109
|
+
end
|
110
|
+
|
111
|
+
def class_specs=(cspecs)
|
112
|
+
@class_specs_mutex.synchronize do
|
113
|
+
@class_specs = cspecs
|
114
|
+
@class_specs_cv.broadcast
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def class_specs
|
119
|
+
@class_specs_mutex.synchronize do
|
120
|
+
while !@class_specs
|
121
|
+
@class_specs_cv.wait(@class_specs_mutex)
|
122
|
+
end
|
123
|
+
@class_specs
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def class_spec_ancestors(csid, &block)
|
128
|
+
@class_specs_mutex.synchronize do
|
129
|
+
while !@class_specs
|
130
|
+
@class_specs_cv.wait(@class_specs_mutex)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
class_spec = @class_specs[csid]
|
135
|
+
|
136
|
+
class_spec.ancestors.select{|anc| @class_specs[anc]}.each{|anc|
|
137
|
+
yield @class_specs[anc]
|
138
|
+
}
|
139
|
+
end
|
140
|
+
|
141
|
+
end
|
142
|
+
|
143
|
+
class ClassSpec
|
144
|
+
def initialize(klass)
|
145
|
+
@name = klass.name
|
146
|
+
@csid = klass.object_id
|
147
|
+
ancestors = klass.ancestors
|
148
|
+
ancestors.unshift klass
|
149
|
+
@ancestors = ancestors.collect{|k| k.object_id}
|
150
|
+
@method_specs = {}
|
151
|
+
end
|
152
|
+
|
153
|
+
attr_reader :name
|
154
|
+
attr_reader :csid
|
155
|
+
attr_reader :ancestors
|
156
|
+
|
157
|
+
def add_method_spec(mspec)
|
158
|
+
if sp = @method_specs[mspec.method]
|
159
|
+
@method_specs[mspec.method].override(mspec)
|
160
|
+
else
|
161
|
+
@method_specs[mspec.method] = mspec
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
def method_spec(method)
|
166
|
+
@method_specs[method]
|
167
|
+
end
|
168
|
+
|
169
|
+
end
|
170
|
+
|
171
|
+
class MethodSpec
|
172
|
+
extend Exception2MessageMapper
|
173
|
+
|
174
|
+
def_exception :UnrecognizedError, "パーズできません(%s)"
|
175
|
+
|
176
|
+
# method(arg_spec, ..., *arg_spec)
|
177
|
+
# ret_spec, ... method()
|
178
|
+
# ret_spec, ... method(arg_spec, ..., *arg_spec)
|
179
|
+
# ret_spec, ... method() block_ret, ... {}
|
180
|
+
# ret_spec, ... method() {arg_spec, ...}
|
181
|
+
# ret_spec, ... method() block_ret, ... {arg_spec, ...}
|
182
|
+
# ret_spec, ... method(arg_spec, ..., *arg_spec) block_ret, ... {arg_spec, ...}
|
183
|
+
|
184
|
+
# *****method が記号の時できてない
|
185
|
+
|
186
|
+
ARG_SPEC = ["DEFAULT", "REF", "VAL", "DVAL"]
|
187
|
+
# VALができるのは, Array, Hash のみ, Structは相手にも同一クラスがあれば可能
|
188
|
+
|
189
|
+
def self.spec(spec)
|
190
|
+
mspec = MethodSpec.new
|
191
|
+
case spec
|
192
|
+
when String
|
193
|
+
mspec.parse(spec)
|
194
|
+
when Hash
|
195
|
+
mspec.direct_setting(spec)
|
196
|
+
else
|
197
|
+
raise "スペック指定は文字列もしくはキーワード指定です"
|
198
|
+
end
|
199
|
+
mspec
|
200
|
+
end
|
201
|
+
|
202
|
+
def initialize
|
203
|
+
@rets = nil
|
204
|
+
@method = nil
|
205
|
+
@args = nil
|
206
|
+
@block_rets = nil
|
207
|
+
@block_args = nil
|
208
|
+
|
209
|
+
@interface = nil
|
210
|
+
end
|
211
|
+
|
212
|
+
attr_accessor :rets
|
213
|
+
attr_accessor :method
|
214
|
+
attr_accessor :args
|
215
|
+
attr_accessor :block_rets
|
216
|
+
attr_accessor :block_args
|
217
|
+
attr_accessor :interface
|
218
|
+
alias interface? interface
|
219
|
+
|
220
|
+
def has_block?
|
221
|
+
@block_rets || @block_args
|
222
|
+
end
|
223
|
+
|
224
|
+
def override(mspec)
|
225
|
+
if mspec.rets
|
226
|
+
@rets = mspec.rets
|
227
|
+
end
|
228
|
+
if mspec.args
|
229
|
+
@args = mspec.args
|
230
|
+
end
|
231
|
+
if mspec.block_rets
|
232
|
+
@block_rets = mspec.block.rets
|
233
|
+
end
|
234
|
+
if mspec.block_args
|
235
|
+
@block_args = mspec.block_args
|
236
|
+
end
|
237
|
+
if mspec.interface
|
238
|
+
@interface = mspec.interface
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
class ArgSpecs
|
243
|
+
include Enumerable
|
244
|
+
def initialize(arg_specs)
|
245
|
+
@arg_specs = arg_specs.dup
|
246
|
+
end
|
247
|
+
|
248
|
+
def each
|
249
|
+
while arg_spec = @arg_specs.shift
|
250
|
+
if arg_spec.mult?
|
251
|
+
@arg_specs.unshift arg_spec
|
252
|
+
end
|
253
|
+
yield arg_spec
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
def succ
|
258
|
+
if (ret = @arg_specs.shift) && ret.mult?
|
259
|
+
@arg_specs.unshift ret
|
260
|
+
end
|
261
|
+
ret
|
262
|
+
end
|
263
|
+
|
264
|
+
end
|
265
|
+
|
266
|
+
def rets_zip(rets, &block)
|
267
|
+
retspecs = ArgSpecs.new(@rets)
|
268
|
+
begin
|
269
|
+
param_zip(retspecs, rets, &block)
|
270
|
+
rescue ArgumentError
|
271
|
+
raise ArgumentError,
|
272
|
+
"argument spec mismatch rets: #{@rets}"
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
def arg_zip(args, &block)
|
277
|
+
argspecs = ArgSpecs.new(@args)
|
278
|
+
begin
|
279
|
+
param_zip(argspecs, args, &block)
|
280
|
+
rescue ArgumentError
|
281
|
+
raise ArgumentError,
|
282
|
+
"argument spec mismatch args: #{@args}"
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
def block_arg_zip(args, &block)
|
287
|
+
argspecs = ArgSpecs.new(@block_args)
|
288
|
+
begin
|
289
|
+
param_zip(argspecs, args, &block)
|
290
|
+
rescue ArgumentError
|
291
|
+
raise ArgumentError,
|
292
|
+
"argument spec mismatch block args: #{@block_args}"
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
def param_zip(arg_specs, args, &block)
|
297
|
+
ary = []
|
298
|
+
args.each do |arg|
|
299
|
+
spec = arg_specs.succ
|
300
|
+
unless spec
|
301
|
+
raise ArgumentError
|
302
|
+
end
|
303
|
+
ary.push yield(spec, arg)
|
304
|
+
end
|
305
|
+
ary
|
306
|
+
end
|
307
|
+
|
308
|
+
def to_s
|
309
|
+
spec = ""
|
310
|
+
case @rets
|
311
|
+
when nil
|
312
|
+
when Array
|
313
|
+
spec.concat(@rets.join(", "))
|
314
|
+
spec.concat(" ")
|
315
|
+
when
|
316
|
+
spec.concat(@rets.to_s)
|
317
|
+
spec.concat(" ")
|
318
|
+
end
|
319
|
+
|
320
|
+
if @method
|
321
|
+
spec.concat(@method.to_s)
|
322
|
+
else
|
323
|
+
spec.concat("(missing)")
|
324
|
+
end
|
325
|
+
if @args
|
326
|
+
spec.concat("("+@args.join(", ")+")")
|
327
|
+
end
|
328
|
+
if has_block?
|
329
|
+
if @block_rets
|
330
|
+
spec.concat(@block_rets.join(", "))
|
331
|
+
end
|
332
|
+
if @block_args
|
333
|
+
spec.concat("{"+@block_args.join(", ")+"}")
|
334
|
+
else
|
335
|
+
spec.concat("{}")
|
336
|
+
end
|
337
|
+
end
|
338
|
+
"#<#{self.class} #{spec} >"
|
339
|
+
end
|
340
|
+
|
341
|
+
class ParamSpec
|
342
|
+
def self.identifier(token, *opts)
|
343
|
+
case token
|
344
|
+
when String
|
345
|
+
name = token
|
346
|
+
if /^\*(.*)/ =~ token
|
347
|
+
name = $1
|
348
|
+
opts.push :mult
|
349
|
+
end
|
350
|
+
when Token
|
351
|
+
name = token.name
|
352
|
+
end
|
353
|
+
|
354
|
+
klass = Name2ParamSpec[name]
|
355
|
+
unless klass
|
356
|
+
MethodSpec.Raise UnrecognizedError, name
|
357
|
+
end
|
358
|
+
pspec = klass.new(name)
|
359
|
+
if opts.include?(:mult)
|
360
|
+
pspec.mult = true
|
361
|
+
end
|
362
|
+
pspec
|
363
|
+
end
|
364
|
+
|
365
|
+
def self.param_specs(string_ary)
|
366
|
+
case string_ary
|
367
|
+
when nil
|
368
|
+
nil
|
369
|
+
when Array
|
370
|
+
string_ary.collect{|e| ParamSpec.identifier(e)}
|
371
|
+
else
|
372
|
+
[ParamSpec.identifier(string_ary)]
|
373
|
+
end
|
374
|
+
end
|
375
|
+
|
376
|
+
def initialize(name)
|
377
|
+
@type = name
|
378
|
+
|
379
|
+
@mult = nil
|
380
|
+
end
|
381
|
+
|
382
|
+
attr_reader :type
|
383
|
+
attr_accessor :mult
|
384
|
+
alias mult? mult
|
385
|
+
|
386
|
+
def to_s
|
387
|
+
if mult
|
388
|
+
"*"+@type
|
389
|
+
else
|
390
|
+
@type
|
391
|
+
end
|
392
|
+
end
|
393
|
+
end
|
394
|
+
|
395
|
+
class DefaultParamSpec<ParamSpec;end
|
396
|
+
class RefParamSpec<ParamSpec;end
|
397
|
+
class ValParamSpec<ParamSpec;end
|
398
|
+
class DValParamSpec<ParamSpec;end
|
399
|
+
|
400
|
+
Name2ParamSpec = {
|
401
|
+
"DEFAULT"=>DefaultParamSpec,
|
402
|
+
"REF" => RefParamSpec,
|
403
|
+
"VAL" => ValParamSpec,
|
404
|
+
"DVAL" => DValParamSpec
|
405
|
+
}
|
406
|
+
|
407
|
+
def direct_setting(opts)
|
408
|
+
if opts[:rets]
|
409
|
+
@rets = ParamSpec.param_specs(opts[:rets])
|
410
|
+
if @rets.size == 1
|
411
|
+
@rets = @rets.first
|
412
|
+
end
|
413
|
+
end
|
414
|
+
|
415
|
+
@method = opts[:method]
|
416
|
+
@method = @method.intern unless @method.kind_of?(Symbol)
|
417
|
+
|
418
|
+
if opts[:args]
|
419
|
+
@args = ParamSpec.param_specs(opts[:args])
|
420
|
+
end
|
421
|
+
|
422
|
+
if opts[:block_rets]
|
423
|
+
@block_rets = ParamSpec.param_specs(opts[:block_rets])
|
424
|
+
if @block_rets.size == 1
|
425
|
+
@block_rets = @block_rets.first
|
426
|
+
end
|
427
|
+
end
|
428
|
+
if opts[:block_args]
|
429
|
+
@block_args = ParamSpec.param_specs(opts[:block_args])
|
430
|
+
end
|
431
|
+
end
|
432
|
+
|
433
|
+
# private method
|
434
|
+
def parse(spec)
|
435
|
+
tokener = Tokener.new(spec)
|
436
|
+
|
437
|
+
tk1, tk2 = tokener.next, tokener.peek
|
438
|
+
tokener.unget tk1
|
439
|
+
case tk1
|
440
|
+
when TkIdentifier
|
441
|
+
case tk2
|
442
|
+
when nil
|
443
|
+
when TkIdentifier, TkCOMMA, TkMULT
|
444
|
+
parse_rets(tokener, spec)
|
445
|
+
when TkLPAREN, TkLBRACE
|
446
|
+
else
|
447
|
+
MethodSpec.Raise UnrecognizedError, spec
|
448
|
+
end
|
449
|
+
when TkMULTI
|
450
|
+
parse_rets(tokener, spec)
|
451
|
+
else
|
452
|
+
MethodSpec.Raise UnrecognizedError, spec
|
453
|
+
end
|
454
|
+
|
455
|
+
parse_method(tokener, spec)
|
456
|
+
parse_args(tokener, spec)
|
457
|
+
parse_block(tokener, spec)
|
458
|
+
end
|
459
|
+
|
460
|
+
def parse_rets(tokener, spec)
|
461
|
+
@rets = parse_params(tokener, spec)
|
462
|
+
if @rets && @rets.size == 1
|
463
|
+
@rets = @rets.first
|
464
|
+
end
|
465
|
+
end
|
466
|
+
|
467
|
+
def parse_method(tokener, spec)
|
468
|
+
tk = tokener.next
|
469
|
+
case tk
|
470
|
+
when TkIdentifier
|
471
|
+
@method = tk.name.intern
|
472
|
+
else
|
473
|
+
MethodSpec.Raise UnrecognizedError, tk.to_s+ " in " +spec
|
474
|
+
end
|
475
|
+
end
|
476
|
+
|
477
|
+
def parse_args(tokener, spec)
|
478
|
+
tk = tokener.next
|
479
|
+
case tk
|
480
|
+
when TkLPAREN
|
481
|
+
@args = parse_params(tokener, spec)
|
482
|
+
tk2 = tokener.next
|
483
|
+
unless tk2 == TkRPAREN
|
484
|
+
MethodSpec.Raise UnrecognizedError, tk2 + " in " +spec
|
485
|
+
end
|
486
|
+
else
|
487
|
+
# パラメータなし
|
488
|
+
end
|
489
|
+
end
|
490
|
+
|
491
|
+
def parse_block(tokener, spec)
|
492
|
+
parse_block_rets(tokener, spec)
|
493
|
+
tk = tokener.peek
|
494
|
+
unless tk == TkLBRACE
|
495
|
+
if @block_rets
|
496
|
+
MethodSpec.Raise UnrecognizedError, "ブロック定義では`{'が必要です(#{tk.to_s}, #{spec})"
|
497
|
+
else
|
498
|
+
return
|
499
|
+
end
|
500
|
+
end
|
501
|
+
parse_block_args(tokener, spec)
|
502
|
+
end
|
503
|
+
|
504
|
+
def parse_block_rets(tokner, spec)
|
505
|
+
@block_rets = parse_params(tokner, spec)
|
506
|
+
if @block_rets
|
507
|
+
if @block_rets && @block_rets.size == 1
|
508
|
+
@block_rets = @block_rets.first
|
509
|
+
end
|
510
|
+
end
|
511
|
+
end
|
512
|
+
|
513
|
+
def parse_block_args(tokener, spec)
|
514
|
+
tk = tokener.next
|
515
|
+
case tk
|
516
|
+
when TkLBRACE
|
517
|
+
@block_args = parse_params(tokener, spec)
|
518
|
+
@args = parse_params(tokener, spec)
|
519
|
+
tk2 = tokener.next
|
520
|
+
unless tk2 == TkRBRACE
|
521
|
+
MethodSpec.Raise UnrecognizedError, tk2 +" in " +spec
|
522
|
+
end
|
523
|
+
else
|
524
|
+
# パラメータなし
|
525
|
+
end
|
526
|
+
end
|
527
|
+
|
528
|
+
def parse_params(tokener, spec)
|
529
|
+
args = []
|
530
|
+
while token = tokener.next
|
531
|
+
case token
|
532
|
+
when TkIdentifier
|
533
|
+
case tk2 = tokener.peek
|
534
|
+
when nil
|
535
|
+
args.push ArgSpec.identifier(token)
|
536
|
+
break
|
537
|
+
when TkMULT
|
538
|
+
MethodSpec.Raise UnrecognizedError, token
|
539
|
+
when TkCOMMA
|
540
|
+
tokener.next
|
541
|
+
args.push ParamSpec.identifier(token)
|
542
|
+
when TkIdentifier, TkRPAREN, TkRBRACE
|
543
|
+
args.push ParamSpec.identifier(token)
|
544
|
+
break
|
545
|
+
when TkLPAREN, TkLBRACE
|
546
|
+
args.push ParamSpec.identifier(token)
|
547
|
+
break
|
548
|
+
else
|
549
|
+
MethodSpec.Raise UnrecognizedError, "不正な文字#{tk2}が入っています"
|
550
|
+
end
|
551
|
+
when TkMULT
|
552
|
+
case token2 = tokener.next
|
553
|
+
when nil
|
554
|
+
MethodSpec.Raise UnrecognizedError, "*で終わっています"
|
555
|
+
when TkIdentifier
|
556
|
+
args.push ParamSpec.identifier(token2, :mult)
|
557
|
+
break
|
558
|
+
else
|
559
|
+
MethodSpec.Raise UnrecognizedError, "*の後に#{token2}が入っています"
|
560
|
+
end
|
561
|
+
else # TkRPAREN, TkRBRACE
|
562
|
+
tokener.unget token
|
563
|
+
break
|
564
|
+
end
|
565
|
+
end
|
566
|
+
if args.empty?
|
567
|
+
nil
|
568
|
+
else
|
569
|
+
args
|
570
|
+
end
|
571
|
+
end
|
572
|
+
|
573
|
+
class Token; end
|
574
|
+
class TkIdentifier<Token
|
575
|
+
def initialize(name)
|
576
|
+
@name = name
|
577
|
+
end
|
578
|
+
attr_reader :name
|
579
|
+
|
580
|
+
def to_s
|
581
|
+
"#<#{self.class} #{@name}>"
|
582
|
+
end
|
583
|
+
end
|
584
|
+
|
585
|
+
TkMULT = "*"
|
586
|
+
TkLPAREN = "("
|
587
|
+
TkLBRACE = "{"
|
588
|
+
TkRPAREN = ")"
|
589
|
+
TkRBRACE = "}"
|
590
|
+
TkCOMMA = ","
|
591
|
+
|
592
|
+
class Tokener
|
593
|
+
def initialize(src)
|
594
|
+
@src = src.split(//)
|
595
|
+
@tokens = []
|
596
|
+
end
|
597
|
+
|
598
|
+
def next
|
599
|
+
return @tokens.shift unless @tokens.empty?
|
600
|
+
|
601
|
+
while /\s/ =~ @src[0]; @src.shift; end
|
602
|
+
|
603
|
+
case @src[0]
|
604
|
+
when nil
|
605
|
+
nil
|
606
|
+
when ",", "(", ")", "{", "}", "*"
|
607
|
+
reading = @src.shift
|
608
|
+
when /\w/
|
609
|
+
identify_identifier
|
610
|
+
else
|
611
|
+
MethodSpec.Raise UnrecognizedError, @src.join("")
|
612
|
+
end
|
613
|
+
end
|
614
|
+
|
615
|
+
def peek
|
616
|
+
@tokens.first unless @tokens.empty?
|
617
|
+
|
618
|
+
token = self.next
|
619
|
+
@tokens.push(token) if token
|
620
|
+
token
|
621
|
+
end
|
622
|
+
|
623
|
+
def unget(token)
|
624
|
+
@tokens.unshift token
|
625
|
+
end
|
626
|
+
|
627
|
+
def identify_identifier
|
628
|
+
toks = []
|
629
|
+
while s = @src.shift
|
630
|
+
if /[\w]/ =~ s
|
631
|
+
toks.push s
|
632
|
+
else
|
633
|
+
@src.unshift s
|
634
|
+
break
|
635
|
+
end
|
636
|
+
end
|
637
|
+
reading = toks.join("")
|
638
|
+
TkIdentifier.new(reading)
|
639
|
+
end
|
640
|
+
end
|
641
|
+
|
642
|
+
def self.mkkey(receiver, method_name)
|
643
|
+
if receiver.__deep_connect_reference?
|
644
|
+
receiver.class.name+"#"+method_name.to_s
|
645
|
+
elsif receiver.kind_of?(Class)
|
646
|
+
receiver.name+"."+method_name.to_s
|
647
|
+
else
|
648
|
+
receiver.class.name+"#"+method_name.to_s
|
649
|
+
end
|
650
|
+
end
|
651
|
+
end
|
652
|
+
end
|