DeepConnect 0.4.06
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.
- 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
|