redparse 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- data/COPYING.LGPL +165 -0
- data/Manifest.txt +40 -0
- data/README.txt +461 -0
- data/Rakefile +26 -0
- data/lib/redparse.rb +1083 -0
- data/lib/redparse/babynodes.rb +137 -0
- data/lib/redparse/babyparser.rb +276 -0
- data/lib/redparse/decisiontree.rb +372 -0
- data/lib/redparse/node.rb +3808 -0
- data/lib/redparse/problemfiles.rb +84 -0
- data/lib/redparse/reg_more_sugar.rb +99 -0
- data/nurli/test_control.nurli +261 -0
- data/redparse.vpj +92 -0
- data/redparse.vpw +8 -0
- data/test/data/__end.rb +5 -0
- data/test/data/__f.rb +2 -0
- data/test/data/be.rb +3 -0
- data/test/data/be2.rb +6 -0
- data/test/data/bqhd.rb +3 -0
- data/test/data/bqhd2.rb +3 -0
- data/test/data/case.rb +8 -0
- data/test/data/datetime.rb +66 -0
- data/test/data/defd.rb +9 -0
- data/test/data/hd-def.rb +8 -0
- data/test/data/hd.rb +3 -0
- data/test/data/hd2.rb +3 -0
- data/test/data/hd3.rb +3 -0
- data/test/data/hd4.rb +75 -0
- data/test/data/hd5.rb +4 -0
- data/test/data/hdcat.rb +4 -0
- data/test/data/hdx.rb +3 -0
- data/test/data/heredoc.rb +3 -0
- data/test/data/if.rb +7 -0
- data/test/data/jbridge.rb +779 -0
- data/test/data/mod.rb +3 -0
- data/test/data/nl_as_strdelim.rb +7 -0
- data/test/data/pw.rb +2 -0
- data/test/data/wvt.rb +2 -0
- data/test/rp-locatetest.rb +344 -0
- data/test/test_redparse.rb +3319 -0
- metadata +113 -0
data/redparse.vpw
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
<!DOCTYPE Workspace SYSTEM "http://www.slickedit.com/dtd/vse/10.0/vpw.dtd">
|
2
|
+
<Workspace Version="10.0" VendorName="SlickEdit">
|
3
|
+
<Projects>
|
4
|
+
<Project File="redparse.vpj" />
|
5
|
+
<Project File="/rubylexer/rubylexer.vpj" />
|
6
|
+
<Project File="/rubymacros/rubymacros.vpj" />
|
7
|
+
</Projects>
|
8
|
+
</Workspace>
|
data/test/data/__f.rb
ADDED
data/test/data/be.rb
ADDED
data/test/data/be2.rb
ADDED
data/test/data/bqhd.rb
ADDED
data/test/data/bqhd2.rb
ADDED
data/test/data/case.rb
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
=begin
|
2
|
+
= xmlrpc/datetime.rb
|
3
|
+
Copyright (C) 2001, 2002, 2003 by Michael Neumann (mneumann@ntecs.de)
|
4
|
+
|
5
|
+
Released under the same term of license as Ruby.
|
6
|
+
|
7
|
+
= Classes
|
8
|
+
* ((<XMLRPC::DateTime>))
|
9
|
+
|
10
|
+
= XMLRPC::DateTime
|
11
|
+
== Description
|
12
|
+
This class is important to handle XMLRPC (('dateTime.iso8601')) values,
|
13
|
+
correcly, because normal UNIX-dates (class (({Date}))) only handle dates
|
14
|
+
from year 1970 on, and class (({Time})) handles dates without the time
|
15
|
+
component. (({XMLRPC::DateTime})) is able to store a XMLRPC
|
16
|
+
(('dateTime.iso8601')) value correctly.
|
17
|
+
|
18
|
+
== Class Methods
|
19
|
+
--- XMLRPC::DateTime.new( year, month, day, hour, min, sec )
|
20
|
+
Creates a new (({XMLRPC::DateTime})) instance with the
|
21
|
+
parameters ((|year|)), ((|month|)), ((|day|)) as date and
|
22
|
+
((|hour|)), ((|min|)), ((|sec|)) as time.
|
23
|
+
Raises (({ArgumentError})) if a parameter is out of range, or ((|year|)) is not
|
24
|
+
of type (({Integer})).
|
25
|
+
|
26
|
+
== Instance Methods
|
27
|
+
--- XMLRPC::DateTime#year
|
28
|
+
--- XMLRPC::DateTime#month
|
29
|
+
--- XMLRPC::DateTime#day
|
30
|
+
--- XMLRPC::DateTime#hour
|
31
|
+
--- XMLRPC::DateTime#min
|
32
|
+
--- XMLRPC::DateTime#sec
|
33
|
+
Return the value of the specified date/time component.
|
34
|
+
|
35
|
+
--- XMLRPC::DateTime#mon
|
36
|
+
Alias for ((<XMLRPC::DateTime#month>)).
|
37
|
+
|
38
|
+
--- XMLRPC::DateTime#year=( value )
|
39
|
+
--- XMLRPC::DateTime#month=( value )
|
40
|
+
--- XMLRPC::DateTime#day=( value )
|
41
|
+
--- XMLRPC::DateTime#hour=( value )
|
42
|
+
--- XMLRPC::DateTime#min=( value )
|
43
|
+
--- XMLRPC::DateTime#sec=( value )
|
44
|
+
Set ((|value|)) as the new date/time component.
|
45
|
+
Raises (({ArgumentError})) if ((|value|)) is out of range, or in the case
|
46
|
+
of (({XMLRPC::DateTime#year=})) if ((|value|)) is not of type (({Integer})).
|
47
|
+
|
48
|
+
--- XMLRPC::DateTime#mon=( value )
|
49
|
+
Alias for ((<XMLRPC::DateTime#month=>)).
|
50
|
+
|
51
|
+
--- XMLRPC::DateTime#to_time
|
52
|
+
Return a (({Time})) object of the date/time which (({self})) represents.
|
53
|
+
If the (('year')) is below 1970, this method returns (({nil})),
|
54
|
+
because (({Time})) cannot handle years below 1970.
|
55
|
+
The used timezone is GMT.
|
56
|
+
|
57
|
+
--- XMLRPC::DateTime#to_date
|
58
|
+
Return a (({Date})) object of the date which (({self})) represents.
|
59
|
+
The (({Date})) object do ((*not*)) contain the time component (only date).
|
60
|
+
|
61
|
+
--- XMLRPC::DateTime#to_a
|
62
|
+
Returns all date/time components in an array.
|
63
|
+
Returns (({[year, month, day, hour, min, sec]})).
|
64
|
+
=end
|
65
|
+
|
66
|
+
|
data/test/data/defd.rb
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
proc{q=1;def q.foo; end} #q should be varnametoken, both times
|
2
|
+
module Defined_p_syntax_tests
|
3
|
+
def self.defined?(foo) :baz end #should be methname
|
4
|
+
def defined?(foo) :bar end #should be methname
|
5
|
+
def ameth
|
6
|
+
p(defined? 44) #should be keyword
|
7
|
+
p(self.defined? 44) #should be methname
|
8
|
+
end
|
9
|
+
end
|
data/test/data/hd-def.rb
ADDED
data/test/data/hd.rb
ADDED
data/test/data/hd2.rb
ADDED
data/test/data/hd3.rb
ADDED
data/test/data/hd4.rb
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
p <<end
|
2
|
+
#{compile_body}#{outvar}
|
3
|
+
end
|
4
|
+
|
5
|
+
p <<end
|
6
|
+
#{compile_body}
|
7
|
+
#{outvar}
|
8
|
+
end
|
9
|
+
|
10
|
+
p <<end
|
11
|
+
#{compile_body}\
|
12
|
+
#{outvar}
|
13
|
+
end
|
14
|
+
|
15
|
+
p <<end
|
16
|
+
#{compile_body}\
|
17
|
+
\
|
18
|
+
\
|
19
|
+
\
|
20
|
+
\
|
21
|
+
\
|
22
|
+
#{outvar}
|
23
|
+
end
|
24
|
+
|
25
|
+
p "\
|
26
|
+
"
|
27
|
+
|
28
|
+
p "\
|
29
|
+
#{x}
|
30
|
+
"
|
31
|
+
|
32
|
+
p "
|
33
|
+
#{x}a\
|
34
|
+
"
|
35
|
+
|
36
|
+
p "
|
37
|
+
#{x}\
|
38
|
+
b"
|
39
|
+
|
40
|
+
p "\
|
41
|
+
#{x}\
|
42
|
+
"
|
43
|
+
|
44
|
+
p "
|
45
|
+
#{x}\
|
46
|
+
"
|
47
|
+
|
48
|
+
p "
|
49
|
+
#{x}"
|
50
|
+
|
51
|
+
|
52
|
+
|
53
|
+
p "
|
54
|
+
#$x\
|
55
|
+
"
|
56
|
+
|
57
|
+
p "
|
58
|
+
#@x\
|
59
|
+
"
|
60
|
+
|
61
|
+
p "
|
62
|
+
#@@x\
|
63
|
+
"
|
64
|
+
|
65
|
+
p "
|
66
|
+
#$x"
|
67
|
+
|
68
|
+
p "
|
69
|
+
#@x"
|
70
|
+
|
71
|
+
p "
|
72
|
+
#@@x"
|
73
|
+
|
74
|
+
p " #$a #@b #@@c "
|
75
|
+
p "#$a#@b#@@c"
|
data/test/data/hd5.rb
ADDED
data/test/data/hdcat.rb
ADDED
data/test/data/hdx.rb
ADDED
@@ -0,0 +1,779 @@
|
|
1
|
+
catch (:f){}
|
2
|
+
__END__
|
3
|
+
if !RUBY_PLATFORM["cyg"].nil? then
|
4
|
+
ret = `cygpath -w #{ret}`.gsub(/\\/,"/").chomp
|
5
|
+
end
|
6
|
+
|
7
|
+
##########################################################################
|
8
|
+
# Low level API area
|
9
|
+
##########################################################################
|
10
|
+
|
11
|
+
def __build_bridge
|
12
|
+
return if defined?(@@object_table)
|
13
|
+
|
14
|
+
@@driver = nil
|
15
|
+
if defined?(JBRIDGE_OPTIONS) then
|
16
|
+
@@options = JBRIDGE_OPTIONS
|
17
|
+
else
|
18
|
+
@@options = Hash.new
|
19
|
+
end
|
20
|
+
|
21
|
+
@@object_table = Hash.new # proxy_id -> object
|
22
|
+
@@gc_manager = JGCManager.instance
|
23
|
+
|
24
|
+
@@debug_out = __jbopt(:bridge_log)
|
25
|
+
|
26
|
+
print_debug("JavaBridge: Startup communication bridge...")
|
27
|
+
|
28
|
+
case __jbopt(:bridge_driver)
|
29
|
+
when :xmlrpc
|
30
|
+
@@driver = XMLRPCBridge.instance
|
31
|
+
when :bstream
|
32
|
+
@@driver = BinStreamBridge.instance
|
33
|
+
else
|
34
|
+
raise "Driver #{__jbopt(:bridge_driver).to_s} not found."
|
35
|
+
end
|
36
|
+
@@driver.set_debugout( lambda{|a| print_debug(a)} )
|
37
|
+
|
38
|
+
__startup_JVM
|
39
|
+
@@driver.startup_server(@@opt_proc, lambda { |*args| __called_by_java(*args)})
|
40
|
+
@@class_repository = JClassRepository.new
|
41
|
+
|
42
|
+
print_debug("JavaBridge: Finished initialized.")
|
43
|
+
end
|
44
|
+
|
45
|
+
def __startup_JVM
|
46
|
+
#JVM CLASSPATH
|
47
|
+
cp = `echo "#{__jbopt(:classpath)}"`.chomp
|
48
|
+
cp = "#{cp}#{__cpseparator}#{@@driver.get_bridge_classpath(__search_libpath)}"
|
49
|
+
print_debug("CLASSPATH: #{cp}")
|
50
|
+
#JVM PATH
|
51
|
+
path = __jbopt(:jvm_path)
|
52
|
+
return unless path
|
53
|
+
#JVM VM ARGS
|
54
|
+
vmarg = __jbopt(:jvm_vm_args)
|
55
|
+
|
56
|
+
#JVM LOG
|
57
|
+
if __jbopt(:jvm_log_file).nil? then
|
58
|
+
logfile = ""
|
59
|
+
else
|
60
|
+
logfile = " -logfile:#{__jbopt(:jvm_log_file)} "
|
61
|
+
end
|
62
|
+
loglevel = __jbopt(:jvm_log_level)
|
63
|
+
|
64
|
+
#DRIVER ARGS
|
65
|
+
driver_args = @@driver.get_bridge_args(@@opt_proc)
|
66
|
+
return if driver_args.nil?
|
67
|
+
|
68
|
+
cmd = "#{path} #{vmarg} -classpath \"#{cp}\" #{driver_args} -logLevel:#{loglevel} #{logfile}"
|
69
|
+
print_debug(cmd)
|
70
|
+
|
71
|
+
#EXEC COMMAND AND WAIT FOR INIT
|
72
|
+
io = IO.popen(cmd,"r")
|
73
|
+
while true
|
74
|
+
line = io.gets
|
75
|
+
puts "JVM: #{line}" if @@debug_out
|
76
|
+
abort "Can not start JVM: \n#{cmd}" if line.nil?
|
77
|
+
break if line =~ /^OK/
|
78
|
+
end
|
79
|
+
|
80
|
+
#START STDOUT PUTTER
|
81
|
+
if __jbopt(:jvm_stdout) != :never then
|
82
|
+
Thread.start(io) {|java_io|
|
83
|
+
loop {
|
84
|
+
if __jbopt(:jvm_stdout) then
|
85
|
+
puts java_io.gets
|
86
|
+
else
|
87
|
+
java_io.gets
|
88
|
+
end
|
89
|
+
}
|
90
|
+
}
|
91
|
+
end
|
92
|
+
|
93
|
+
#REGISTER JVM KILLER
|
94
|
+
at_exit {
|
95
|
+
print_debug " EXIT JavaBridge..."
|
96
|
+
begin
|
97
|
+
break_bridge
|
98
|
+
rescue => e
|
99
|
+
puts e.message
|
100
|
+
puts e.backtrace.join("\n")
|
101
|
+
ensure
|
102
|
+
begin
|
103
|
+
Process.kill(:QUIT, io.pid)
|
104
|
+
rescue
|
105
|
+
puts e.message
|
106
|
+
puts e.backtrace.join("\n")
|
107
|
+
end
|
108
|
+
end
|
109
|
+
print_debug " EXIT JavaBridge..."
|
110
|
+
}
|
111
|
+
print_debug("JVM: Initialized.")
|
112
|
+
end
|
113
|
+
|
114
|
+
def __register(obj)
|
115
|
+
@@object_table[obj.__object_id] = obj
|
116
|
+
obj
|
117
|
+
end
|
118
|
+
|
119
|
+
def print_debug(out)
|
120
|
+
puts out if @@debug_out
|
121
|
+
end
|
122
|
+
|
123
|
+
# Called by java
|
124
|
+
def __called_by_java(sid,obj_id,method_name,args)
|
125
|
+
print_debug "%% Received: #{obj_id}.#{method_name} : #{args.join(", ")}"
|
126
|
+
obj = @@object_table[obj_id]
|
127
|
+
if obj.nil? then
|
128
|
+
# not found extended object
|
129
|
+
raise "Object: #{obj_id} not found."
|
130
|
+
else
|
131
|
+
# OK
|
132
|
+
Thread.current[:__jb_session] = sid
|
133
|
+
begin
|
134
|
+
ret = obj.__jsend__(method_name,*args)
|
135
|
+
return ret
|
136
|
+
rescue => ev
|
137
|
+
print_debug "EXCEPTION (for debug): #{ev} -------------"
|
138
|
+
print_debug ev.backtrace
|
139
|
+
sa = args.join(",")
|
140
|
+
print_debug "sid:#{sid} object:#{obj.__classname} method:#{method_name} args:#{sa}:#{args.size}"
|
141
|
+
print_debug "------------------------------------------"
|
142
|
+
raise ev
|
143
|
+
ensure
|
144
|
+
Thread.current[:__jb_session] = nil
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
# calling the JavaBridge API
|
150
|
+
def __send_message_to_java(method,*args)
|
151
|
+
sid = Thread.current[:__jb_session]
|
152
|
+
if sid then
|
153
|
+
# session thread logic
|
154
|
+
print_debug "## SESSION[#{sid}] SendMessage: #{method}( #{args.join(", ")} )"
|
155
|
+
args.insert(0,sid,method)
|
156
|
+
return @@driver.send_message_to_java("sessionCall",*args)
|
157
|
+
else
|
158
|
+
# normal calling
|
159
|
+
print_debug "## SendMessage: #{method}( #{args.join(", ")} )"
|
160
|
+
return @@driver.send_message_to_java(method,*args)
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
##########################################################################
|
165
|
+
# Public API area
|
166
|
+
##########################################################################
|
167
|
+
|
168
|
+
public
|
169
|
+
|
170
|
+
# Sending a shutdown message to the JVM.
|
171
|
+
def break_bridge()
|
172
|
+
return unless defined?(@@object_table)
|
173
|
+
@@gc_manager.cancel_all_finalizer
|
174
|
+
@@driver.shutdown_server if @@driver.connected?
|
175
|
+
nil
|
176
|
+
end
|
177
|
+
|
178
|
+
# Resuming the main thread.
|
179
|
+
def wakeup_thread()
|
180
|
+
@@main_thread.wakeup
|
181
|
+
nil
|
182
|
+
end
|
183
|
+
|
184
|
+
def stop_thread()
|
185
|
+
return unless defined?(@@object_table)
|
186
|
+
@@main_thread = Thread.current
|
187
|
+
Thread.stop
|
188
|
+
nil
|
189
|
+
end
|
190
|
+
|
191
|
+
def jnew(classname,*args)
|
192
|
+
__build_bridge
|
193
|
+
obj = JCreatedObject.new(__to_s(classname),*args)
|
194
|
+
@@gc_manager.register_finalizer(obj)
|
195
|
+
return obj
|
196
|
+
end
|
197
|
+
|
198
|
+
def jextend(classnames,*args,&impl)
|
199
|
+
__build_bridge
|
200
|
+
ret = __register(JExtendedClass.new(__to_s(classnames),*args))
|
201
|
+
ret.set_default_dispatcher(impl) if impl
|
202
|
+
return ret
|
203
|
+
end
|
204
|
+
|
205
|
+
def jstatic(classname)
|
206
|
+
__build_bridge
|
207
|
+
obj = JClass.new(__to_s(classname))
|
208
|
+
return obj
|
209
|
+
end
|
210
|
+
|
211
|
+
def jimport(lines)
|
212
|
+
__build_bridge
|
213
|
+
__send_message_to_java("import",lines)
|
214
|
+
nil
|
215
|
+
end
|
216
|
+
|
217
|
+
def junlink(proxy)
|
218
|
+
__build_bridge
|
219
|
+
if proxy.kind_of?(JExtendedClass) then
|
220
|
+
key = proxy.__object_id
|
221
|
+
__send_message_to_java("unlink",key)
|
222
|
+
else
|
223
|
+
print_debug("The object #{proxy.__object_id} will be garbage_collected automatically.")
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
#return all proxy objects in the object repositry.
|
228
|
+
def jdump_object_list
|
229
|
+
__build_bridge
|
230
|
+
return __send_message_to_java("allObjects")
|
231
|
+
end
|
232
|
+
|
233
|
+
##########################################################################
|
234
|
+
# private API
|
235
|
+
##########################################################################
|
236
|
+
|
237
|
+
private
|
238
|
+
|
239
|
+
def __jclassname(key)
|
240
|
+
__send_message_to_java("classname",key)
|
241
|
+
end
|
242
|
+
|
243
|
+
# creating a proxy object.
|
244
|
+
def jproxy(classname,key)
|
245
|
+
__build_bridge
|
246
|
+
obj = JProxyObject.new(__to_s(classname),key)
|
247
|
+
@@gc_manager.register_finalizer(obj)
|
248
|
+
return obj
|
249
|
+
end
|
250
|
+
|
251
|
+
def __to_s(classname)
|
252
|
+
return classname if classname.instance_of? String
|
253
|
+
classname.to_s.gsub(/_/,".")
|
254
|
+
end
|
255
|
+
|
256
|
+
def __classinfo(classname)
|
257
|
+
__send_message_to_java("classinfo",__to_s(classname)).split(",")
|
258
|
+
end
|
259
|
+
|
260
|
+
##########################################################################
|
261
|
+
# JClass area
|
262
|
+
##########################################################################
|
263
|
+
|
264
|
+
#
|
265
|
+
# Abstract proxy class: a subclass should initialize @__classname, @__object_id
|
266
|
+
# and @__classinfo.
|
267
|
+
#
|
268
|
+
class JObject
|
269
|
+
|
270
|
+
def method_missing(name,*args)
|
271
|
+
print_debug "#### method_missing : #{name}( #{args.join(", ")} )"
|
272
|
+
name = name.to_s
|
273
|
+
if args.size == 0 then
|
274
|
+
#property get?
|
275
|
+
return __ref__(name) if __define_jfield?(name)
|
276
|
+
else
|
277
|
+
args = __obj2ids__(args)
|
278
|
+
#property set?
|
279
|
+
if !(name =~ /^.*=$/).nil? then
|
280
|
+
fname = name[0,name.length-1]
|
281
|
+
return __set__(fname,args[0]) if __define_jfield?(fname)
|
282
|
+
end
|
283
|
+
end
|
284
|
+
#method call
|
285
|
+
return __id2obj__(__call__(name,*args)) if __define_jmethod?(name)
|
286
|
+
#not found
|
287
|
+
#super(name,*args)
|
288
|
+
as = args.join(",")
|
289
|
+
raise NoMethodError.new("Not found method: #{name}(#{as}) in #{__classname}",name, args)
|
290
|
+
end
|
291
|
+
|
292
|
+
def __define_jfield?(name)
|
293
|
+
return false if __define_jmethod?(name)
|
294
|
+
@__classinfo.define_jfield?(name)
|
295
|
+
end
|
296
|
+
|
297
|
+
def __define_jmethod?(name)
|
298
|
+
@__classinfo.define_jmethod?(name)
|
299
|
+
end
|
300
|
+
|
301
|
+
# called by java
|
302
|
+
def __jsend__(method,*args)
|
303
|
+
args = __id2objs__(args)
|
304
|
+
return __send__(method,*args).to_trans_obj
|
305
|
+
end
|
306
|
+
|
307
|
+
def to_trans_obj
|
308
|
+
@__object_id
|
309
|
+
end
|
310
|
+
|
311
|
+
attr_reader :__object_id,:__classname,:__classinfo
|
312
|
+
|
313
|
+
private
|
314
|
+
|
315
|
+
def __obj2ids__(args)
|
316
|
+
args.map{|i| i.to_trans_obj }
|
317
|
+
end
|
318
|
+
|
319
|
+
def __id2obj__(arg)
|
320
|
+
return nil if (arg.nil?)
|
321
|
+
return __id2objs__(arg) if arg.instance_of?(Array)
|
322
|
+
return arg unless arg.instance_of?(String)
|
323
|
+
return arg if arg["\n"]
|
324
|
+
cn = __jclassname(arg)
|
325
|
+
if !cn.nil? then
|
326
|
+
return @@object_table[arg] if @@object_table.key?(arg)
|
327
|
+
jproxy(cn,arg)
|
328
|
+
else
|
329
|
+
arg
|
330
|
+
end
|
331
|
+
end
|
332
|
+
|
333
|
+
def __id2objs__(args)
|
334
|
+
args.map {|i| __id2obj__(i)}
|
335
|
+
end
|
336
|
+
|
337
|
+
def __call__(method,*args)
|
338
|
+
args = __obj2ids__(args)
|
339
|
+
__id2obj__(__send_message_to_java("call",@__object_id,method,*args))
|
340
|
+
end
|
341
|
+
|
342
|
+
def __ref__(fieldname)
|
343
|
+
__id2obj__(__send_message_to_java("ref",@__object_id,fieldname))
|
344
|
+
end
|
345
|
+
|
346
|
+
def __set__(fieldname,value)
|
347
|
+
__send_message_to_java("set",@__object_id,fieldname,value)
|
348
|
+
nil
|
349
|
+
end
|
350
|
+
|
351
|
+
public
|
352
|
+
|
353
|
+
def to_s
|
354
|
+
"JB:ProxyObject class:#{@__classname}, value:#{__call__('toString')}"
|
355
|
+
end
|
356
|
+
|
357
|
+
def inspect
|
358
|
+
to_s
|
359
|
+
end
|
360
|
+
|
361
|
+
def methods
|
362
|
+
return @accessible_methods if @accessible_methods
|
363
|
+
@accessible_methods = super
|
364
|
+
@accessible_methods |= @__classinfo.get_accessible_methods
|
365
|
+
return @accessible_methods
|
366
|
+
end
|
367
|
+
|
368
|
+
end # class JObject
|
369
|
+
|
370
|
+
# the object created by ruby
|
371
|
+
class JCreatedObject < JObject
|
372
|
+
def initialize(classname,*args)
|
373
|
+
if args.size > 0 then
|
374
|
+
args = __obj2ids__(args)
|
375
|
+
end
|
376
|
+
@__object_id = __send_message_to_java("new",classname,*args)
|
377
|
+
@__classname = __jclassname(@__object_id)
|
378
|
+
@__classinfo = @@class_repository.get_classinfo(@__classname)
|
379
|
+
end
|
380
|
+
end
|
381
|
+
|
382
|
+
# the extended object created by ruby
|
383
|
+
class JExtendedClass < JObject
|
384
|
+
|
385
|
+
def initialize(_classnames,*args)
|
386
|
+
if args.size > 0 then
|
387
|
+
args = __obj2ids__(args)
|
388
|
+
end
|
389
|
+
@__object_id = __send_message_to_java("extend",_classnames,*args)
|
390
|
+
@__classname = __jclassname(@__object_id)
|
391
|
+
@__classinfo = @@class_repository.get_classinfo(@__classname)
|
392
|
+
@table_impl_proc = Hash.new
|
393
|
+
@default_proc = nil
|
394
|
+
end
|
395
|
+
|
396
|
+
def __jsend__(method,*args)
|
397
|
+
if respond_to?(method) then
|
398
|
+
return super(method,*args)
|
399
|
+
elsif @default_proc then
|
400
|
+
return @default_proc.call(method,args)
|
401
|
+
else
|
402
|
+
raise "BUG: called not implemented method."
|
403
|
+
end
|
404
|
+
end
|
405
|
+
|
406
|
+
def __super__(method,*args)
|
407
|
+
args = __obj2ids__(args)
|
408
|
+
__id2obj__(__send_message_to_java("superCall",@__object_id,method,*args))
|
409
|
+
end
|
410
|
+
|
411
|
+
def __call__(method,*args)
|
412
|
+
__super__(method,*args)
|
413
|
+
end
|
414
|
+
|
415
|
+
def singleton_method_added(name)
|
416
|
+
__send_message_to_java("impl",@__object_id,name.to_s,true)
|
417
|
+
end
|
418
|
+
|
419
|
+
def singleton_method_removed(name)
|
420
|
+
__send_message_to_java("impl",@__object_id,name.to_s,false)
|
421
|
+
end
|
422
|
+
|
423
|
+
def singleton_method_undefined(name)
|
424
|
+
__send_message_to_java("impl",@__object_id,name.to_s,false)
|
425
|
+
end
|
426
|
+
|
427
|
+
#the easy method implementation by the block notation.
|
428
|
+
#users can write the event handler with the java-like variable scope.
|
429
|
+
def jdef(name,&aproc)
|
430
|
+
@table_impl_proc[name] = aproc
|
431
|
+
instance_eval %Q{
|
432
|
+
def #{name.to_s}(*args)
|
433
|
+
return @table_impl_proc[:#{name.to_s}].call(*args)
|
434
|
+
end
|
435
|
+
}
|
436
|
+
end
|
437
|
+
|
438
|
+
def set_default_dispatcher(aproc)
|
439
|
+
@default_proc = aproc
|
440
|
+
end
|
441
|
+
|
442
|
+
end
|
443
|
+
|
444
|
+
# the object created in the JVM
|
445
|
+
class JProxyObject < JObject
|
446
|
+
def initialize(classname,key)
|
447
|
+
@__object_id = key
|
448
|
+
@__classname = classname
|
449
|
+
@__classinfo = @@class_repository.get_classinfo(@__classname)
|
450
|
+
end
|
451
|
+
end
|
452
|
+
|
453
|
+
# the static class object
|
454
|
+
class JClass < JObject
|
455
|
+
|
456
|
+
attr_reader :__metainfo
|
457
|
+
|
458
|
+
def initialize(classname)
|
459
|
+
@__object_id = __send_message_to_java("static",classname)
|
460
|
+
@__classname = __jclassname(@__object_id)
|
461
|
+
@__classinfo = @@class_repository.get_classinfo(@__classname)
|
462
|
+
@__metainfo = @@class_repository.get_classinfo("java.lang.Class")
|
463
|
+
end
|
464
|
+
|
465
|
+
def __define_jmethod?(name)
|
466
|
+
@__classinfo.define_jmethod?(name) || @__metainfo.define_jmethod?(name)
|
467
|
+
end
|
468
|
+
|
469
|
+
def methods
|
470
|
+
return @accessible_methods if @accessible_methods
|
471
|
+
@accessible_methods = super
|
472
|
+
@accessible_methods |= @__classinfo.get_accessible_methods
|
473
|
+
@accessible_methods |= @__metainfo.get_accessible_methods
|
474
|
+
return @accessible_methods
|
475
|
+
end
|
476
|
+
|
477
|
+
end
|
478
|
+
|
479
|
+
##########################################################################
|
480
|
+
# JClassRepository and JClassInfo area
|
481
|
+
##########################################################################
|
482
|
+
|
483
|
+
#
|
484
|
+
# JClassRepository manages the class information represented by JClassInfo.
|
485
|
+
#
|
486
|
+
class JClassRepository
|
487
|
+
def initialize
|
488
|
+
@classtable = Hash.new
|
489
|
+
end
|
490
|
+
|
491
|
+
def get_classinfo(classname)
|
492
|
+
return nil if classname.nil?
|
493
|
+
info = @classtable[classname]
|
494
|
+
return info if info
|
495
|
+
info = JClassInfo.new(classname)
|
496
|
+
@classtable[classname] = info
|
497
|
+
info
|
498
|
+
end
|
499
|
+
end
|
500
|
+
|
501
|
+
#
|
502
|
+
# JClassInfo treats superclass, public fields, public and protected methods.
|
503
|
+
# The instances of JClassInfo make a tree form in which the subclass
|
504
|
+
# makes a branche.
|
505
|
+
#
|
506
|
+
class JClassInfo
|
507
|
+
|
508
|
+
attr_reader :jsuperclass,:jclassname,:jfields,:jmethods,:protected_jmethods,:jinterfaces
|
509
|
+
|
510
|
+
def initialize(_classname)
|
511
|
+
info = __classinfo(_classname)
|
512
|
+
@jclassname = _classname
|
513
|
+
@jinterfaces = []
|
514
|
+
@jfields = Hash.new
|
515
|
+
@jmethods = Hash.new
|
516
|
+
@protected_jmethods = Hash.new
|
517
|
+
_superclass = nil
|
518
|
+
mode = nil
|
519
|
+
info.each{|i|
|
520
|
+
case i
|
521
|
+
when "====Superclass"
|
522
|
+
mode = :superclass
|
523
|
+
when "====Interfaces"
|
524
|
+
mode = :interfaces
|
525
|
+
when "====Field"
|
526
|
+
mode = :fields
|
527
|
+
when "====PublicMethod"
|
528
|
+
mode = :methods
|
529
|
+
when "====ProtectedMethod"
|
530
|
+
mode = :protected_methods
|
531
|
+
else
|
532
|
+
case mode
|
533
|
+
when :superclass
|
534
|
+
_superclass = i
|
535
|
+
when :interfaces
|
536
|
+
@jinterfaces << @@class_repository.get_classinfo(i)
|
537
|
+
when :fields
|
538
|
+
@jfields[i] = :t
|
539
|
+
when :methods
|
540
|
+
@jmethods[i] = :t
|
541
|
+
when :protected_methods
|
542
|
+
@protected_jmethods[i] = :t
|
543
|
+
end
|
544
|
+
end
|
545
|
+
}
|
546
|
+
if _superclass then
|
547
|
+
@jsuperclass = @@class_repository.get_classinfo(_superclass)
|
548
|
+
else
|
549
|
+
@jsuperclass = nil
|
550
|
+
end
|
551
|
+
|
552
|
+
@public_jmethods = @jmethods.keys
|
553
|
+
@public_jmethods |= @jsuperclass.get_accessible_methods if @jsuperclass
|
554
|
+
@jinterfaces.each {|i| @public_jmethods |= i.get_accessible_methods }
|
555
|
+
end
|
556
|
+
|
557
|
+
def define_jfield?(name)
|
558
|
+
return true if @jfields.key?(name)
|
559
|
+
if (!@jsuperclass.nil?) then
|
560
|
+
return true if @jsuperclass.define_jfield?(name)
|
561
|
+
end
|
562
|
+
@jinterfaces.each {|i|
|
563
|
+
return true if i.define_jfield?(name)
|
564
|
+
}
|
565
|
+
false
|
566
|
+
end
|
567
|
+
|
568
|
+
def define_jmethod?(name)
|
569
|
+
return true if @jmethods.key?(name)
|
570
|
+
if @jsuperclass then
|
571
|
+
return true if @jsuperclass.define_jmethod?(name)
|
572
|
+
end
|
573
|
+
@jinterfaces.each {|i|
|
574
|
+
return true if i.define_jmethod?(name)
|
575
|
+
}
|
576
|
+
false
|
577
|
+
end
|
578
|
+
|
579
|
+
def define_protected_jmethod?(name)
|
580
|
+
return true if @protected_jmethods.key?(name)
|
581
|
+
return @jsuperclass.define_protected_jmethod?(name) if @jsuperclass
|
582
|
+
@jinterfaces.each {|i|
|
583
|
+
return true if i.define_jmethod?(name)
|
584
|
+
}
|
585
|
+
false
|
586
|
+
end
|
587
|
+
|
588
|
+
#return public java methods
|
589
|
+
def get_accessible_methods
|
590
|
+
return @public_jmethods
|
591
|
+
end
|
592
|
+
|
593
|
+
def dump
|
594
|
+
puts "========: #{@jclassname}"
|
595
|
+
puts " == Superclass: #{@jsuperclass.jclassname}" if @jsuperclass
|
596
|
+
putter = lambda {|i| puts " #{i}" }
|
597
|
+
puts " == Interface"
|
598
|
+
@jinterfaces.each {|i| puts " #{i.jclassname}"}
|
599
|
+
puts " == Field"
|
600
|
+
@jfields.each_key(putter)
|
601
|
+
puts " == Public Method"
|
602
|
+
@jmethods.each_key(putter)
|
603
|
+
puts " == ProtectedMethod Method"
|
604
|
+
@protected_jmethods.each_key(putter)
|
605
|
+
end
|
606
|
+
end
|
607
|
+
|
608
|
+
##########################################################################
|
609
|
+
# Exception holder for the exceptions occurred in Java
|
610
|
+
##########################################################################
|
611
|
+
|
612
|
+
class JException < RuntimeError
|
613
|
+
|
614
|
+
attr_reader :klass,:message,:detail
|
615
|
+
|
616
|
+
def initialize(klass,message,detail)
|
617
|
+
@klass = klass
|
618
|
+
@message = message
|
619
|
+
@detail = detail
|
620
|
+
end
|
621
|
+
|
622
|
+
def message
|
623
|
+
ret = ""
|
624
|
+
ret += @klass if @klass
|
625
|
+
ret += "\n"+@message if @message
|
626
|
+
ret += "\n"+@detail if @detail
|
627
|
+
return ret
|
628
|
+
end
|
629
|
+
|
630
|
+
alias :to_s :message
|
631
|
+
|
632
|
+
end
|
633
|
+
|
634
|
+
private
|
635
|
+
|
636
|
+
##########################################################################
|
637
|
+
# GC manager: send unlink message to Java for removing the object reference
|
638
|
+
##########################################################################
|
639
|
+
|
640
|
+
class JGCManager
|
641
|
+
include Singleton
|
642
|
+
|
643
|
+
def initialize
|
644
|
+
@@object_id_table = Hash.new # __id__ -> proxy_id
|
645
|
+
@@object_ref_counter = Hash.new # proxy_id -> refcounter
|
646
|
+
@@object_lock = Monitor.new # lock for finalizer registration and deregistration
|
647
|
+
|
648
|
+
# I'm not sure that using lists without locking...
|
649
|
+
@@using_list1 = false
|
650
|
+
@@finalizable_id_list1 = []
|
651
|
+
@@using_list2 = false
|
652
|
+
@@finalizable_id_list2 = []
|
653
|
+
|
654
|
+
@@later_registration_list = []
|
655
|
+
end
|
656
|
+
|
657
|
+
public
|
658
|
+
def exec_finalizable_objects
|
659
|
+
@@object_lock.synchronize do
|
660
|
+
@@using_list1 = true
|
661
|
+
@@finalizable_id_list1.each {|i| finalize_jobject(i)}
|
662
|
+
@@finalizable_id_list1 = []
|
663
|
+
@@using_list1 = false
|
664
|
+
@@using_list2 = true
|
665
|
+
@@finalizable_id_list2.each {|i| finalize_jobject(i)}
|
666
|
+
@@finalizable_id_list2 = []
|
667
|
+
@@using_list2 = false
|
668
|
+
end
|
669
|
+
end
|
670
|
+
|
671
|
+
private
|
672
|
+
def finalize_jobject(proxy_id)
|
673
|
+
begin
|
674
|
+
counter = @@object_ref_counter[proxy_id]
|
675
|
+
if counter > 1 then
|
676
|
+
counter = counter - 1
|
677
|
+
@@object_ref_counter[proxy_id] = counter
|
678
|
+
print_debug " ----GC: decrease ref count [#{counter}] : #{proxy_id}"
|
679
|
+
return nil
|
680
|
+
end
|
681
|
+
@@object_ref_counter.delete(proxy_id)
|
682
|
+
print_debug " ----GC: sending unlink... : #{proxy_id}"
|
683
|
+
__send_message_to_java("unlink",proxy_id)
|
684
|
+
print_debug " ----GC: sent ok."
|
685
|
+
rescue Exception => e
|
686
|
+
p e
|
687
|
+
raise RuntimeError.new("Failed to finalize object: [#{proxy_id}] => #{e.class.to_s} : #{e.message}")
|
688
|
+
ensure
|
689
|
+
print_debug " ----GC: exiting finalizer."
|
690
|
+
end
|
691
|
+
end
|
692
|
+
|
693
|
+
def self.register_gc_object_id(pid)
|
694
|
+
if !@@using_list1 then
|
695
|
+
@@finalizable_id_list1 << pid
|
696
|
+
if @@later_registration_list.size > 0 then
|
697
|
+
@@finalizable_id_list1.concat @later_registration_list
|
698
|
+
@@later_registration_list = []
|
699
|
+
end
|
700
|
+
elsif !@@using_list2 then
|
701
|
+
@@finalizable_id_list2 << pid
|
702
|
+
if @@later_registration_list.size > 0 then
|
703
|
+
@@finalizable_id_list2.concat @later_registration_list
|
704
|
+
@@later_registration_list = []
|
705
|
+
end
|
706
|
+
else
|
707
|
+
print_debug " ----GC: finalize later: #{pid}"
|
708
|
+
@@later_registration_list << pid
|
709
|
+
end
|
710
|
+
end
|
711
|
+
|
712
|
+
def self.get_finalizer_proc
|
713
|
+
return Proc.new {|id|
|
714
|
+
proxy_id = @@object_id_table[id]
|
715
|
+
begin
|
716
|
+
print_debug " ----GC: register unlink: #{proxy_id}"
|
717
|
+
JGCManager.register_gc_object_id( proxy_id )
|
718
|
+
rescue Exception => e
|
719
|
+
p e
|
720
|
+
ensure
|
721
|
+
@@object_id_table.delete(id)
|
722
|
+
end
|
723
|
+
}
|
724
|
+
end
|
725
|
+
|
726
|
+
public
|
727
|
+
def register_finalizer(proxy)
|
728
|
+
@@object_lock.synchronize {
|
729
|
+
@@object_id_table[proxy.__id__] = proxy.__object_id
|
730
|
+
counter = @@object_ref_counter[proxy.__object_id]
|
731
|
+
if counter then
|
732
|
+
counter += 1
|
733
|
+
else
|
734
|
+
counter = 1
|
735
|
+
end
|
736
|
+
print_debug " ----GC: #{counter} : #{proxy.__object_id}"
|
737
|
+
@@object_ref_counter[proxy.__object_id] = counter
|
738
|
+
if (!proxy.kind_of?(JObject)) then
|
739
|
+
raise RuntimeError.new("GC: different object: #{proxy.to_s}")
|
740
|
+
end
|
741
|
+
ObjectSpace.define_finalizer(proxy, JGCManager.get_finalizer_proc)
|
742
|
+
}
|
743
|
+
exec_finalizable_objects
|
744
|
+
end
|
745
|
+
|
746
|
+
public
|
747
|
+
def cancel_all_finalizer
|
748
|
+
@@object_lock.synchronize {
|
749
|
+
print_debug " ----GC: begin cancelling finalizer: #{@@object_id_table.size}"
|
750
|
+
@@object_id_table.reject! {|key,value|
|
751
|
+
begin
|
752
|
+
obj = ObjectSpace._id2ref(key)
|
753
|
+
ObjectSpace.undefine_finalizer(obj)
|
754
|
+
print_debug " ----GC: cancel: #{obj.__object_id}"
|
755
|
+
rescue RangeError => e
|
756
|
+
end
|
757
|
+
true
|
758
|
+
}
|
759
|
+
}
|
760
|
+
end
|
761
|
+
end
|
762
|
+
|
763
|
+
end #module
|
764
|
+
|
765
|
+
# Ruby like new methods
|
766
|
+
class Symbol
|
767
|
+
def jext(*args,&impl)
|
768
|
+
JavaBridge::jextend(self, *args, &impl)
|
769
|
+
end
|
770
|
+
|
771
|
+
def jnew(*args)
|
772
|
+
JavaBridge::jnew(self, *args)
|
773
|
+
end
|
774
|
+
|
775
|
+
def jclass
|
776
|
+
JavaBridge::jstatic(self)
|
777
|
+
end
|
778
|
+
end
|
779
|
+
|