redparse 0.8.0
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/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
|
+
|