rubybreaker 0.0.8 → 0.0.9
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/NEWS +6 -0
- data/VERSION +1 -1
- data/bin/rubybreaker +3 -3
- data/lib/rubybreaker.rb +15 -11
- data/lib/rubybreaker/doc/rdoc.rb +1 -1
- data/lib/rubybreaker/runtime/monitor.rb +8 -6
- data/lib/rubybreaker/runtime/object_wrapper.rb +38 -16
- data/lib/rubybreaker/runtime/overrides.rb +42 -30
- data/lib/rubybreaker/runtime/type_system.rb +45 -14
- data/lib/rubybreaker/type/type_unparser.rb +4 -8
- data/lib/rubybreaker/typing/subtyping.rb +1 -0
- data/test/integrated/tc_original_behavior.rb +38 -0
- data/test/integrated/tc_simple1.rb +20 -0
- data/test/integrated/tc_simple_algorithms.rb +135 -0
- data/test/runtime/tc_obj_wrapper.rb +3 -3
- data/test/ts_integrated.rb +1 -0
- data/test/type/tc_parser.rb +24 -0
- data/webpage/rdoc/Object.html +0 -2
- data/webpage/rdoc/Rake.html +0 -2
- data/webpage/rdoc/Rake/RubyBreakerTestTask.html +0 -2
- data/webpage/rdoc/RubyBreaker.html +1 -3
- data/webpage/rdoc/RubyBreaker/Breakable.html +0 -2
- data/webpage/rdoc/RubyBreaker/Broken.html +0 -2
- data/webpage/rdoc/RubyBreaker/Context.html +0 -2
- data/webpage/rdoc/RubyBreaker/Errors.html +0 -2
- data/webpage/rdoc/RubyBreaker/Errors/ArgumentTypeError.html +0 -2
- data/webpage/rdoc/RubyBreaker/Errors/ArityError.html +0 -2
- data/webpage/rdoc/RubyBreaker/Errors/InternalError.html +0 -2
- data/webpage/rdoc/RubyBreaker/Errors/InvalidSubtypeCheck.html +0 -2
- data/webpage/rdoc/RubyBreaker/Errors/InvalidTypeConstruction.html +0 -2
- data/webpage/rdoc/RubyBreaker/Errors/ReturnTypeError.html +0 -2
- data/webpage/rdoc/RubyBreaker/Errors/TypeError.html +0 -2
- data/webpage/rdoc/RubyBreaker/Errors/UserError.html +0 -2
- data/webpage/rdoc/RubyBreaker/ObjectPosition.html +0 -2
- data/webpage/rdoc/RubyBreaker/Position.html +0 -2
- data/webpage/rdoc/RubyBreaker/RubyTypeUtils.html +0 -2
- data/webpage/rdoc/RubyBreaker/Runtime.html +7 -3
- data/webpage/rdoc/RubyBreaker/Runtime/Inspector.html +0 -2
- data/webpage/rdoc/RubyBreaker/Runtime/MethodInfo.html +0 -2
- data/webpage/rdoc/RubyBreaker/Runtime/Monitor.html +12 -13
- data/webpage/rdoc/RubyBreaker/Runtime/MonitorInstaller.html +6 -7
- data/webpage/rdoc/RubyBreaker/Runtime/MonitorSwitch.html +4 -6
- data/webpage/rdoc/RubyBreaker/Runtime/ObjectWrapper.html +21 -19
- data/webpage/rdoc/RubyBreaker/Runtime/Pluggable.html +0 -2
- data/webpage/rdoc/RubyBreaker/Runtime/TypeSigParser.html +0 -2
- data/webpage/rdoc/RubyBreaker/Runtime/TypeSigUnparser.html +0 -2
- data/webpage/rdoc/RubyBreaker/Runtime/TypeSystem.html +52 -23
- data/webpage/rdoc/RubyBreaker/TypeComparer.html +0 -2
- data/webpage/rdoc/RubyBreaker/TypeDefs.html +0 -2
- data/webpage/rdoc/RubyBreaker/TypeDefs/AnyType.html +0 -2
- data/webpage/rdoc/RubyBreaker/TypeDefs/BlockType.html +0 -2
- data/webpage/rdoc/RubyBreaker/TypeDefs/DuckType.html +0 -2
- data/webpage/rdoc/RubyBreaker/TypeDefs/FusionType.html +0 -2
- data/webpage/rdoc/RubyBreaker/TypeDefs/MethodListType.html +0 -2
- data/webpage/rdoc/RubyBreaker/TypeDefs/MethodType.html +0 -2
- data/webpage/rdoc/RubyBreaker/TypeDefs/NilType.html +0 -2
- data/webpage/rdoc/RubyBreaker/TypeDefs/NominalType.html +0 -2
- data/webpage/rdoc/RubyBreaker/TypeDefs/OptionalType.html +0 -2
- data/webpage/rdoc/RubyBreaker/TypeDefs/OrType.html +0 -2
- data/webpage/rdoc/RubyBreaker/TypeDefs/SelfType.html +0 -2
- data/webpage/rdoc/RubyBreaker/TypeDefs/Type.html +2 -4
- data/webpage/rdoc/RubyBreaker/TypeDefs/VarLengthType.html +0 -2
- data/webpage/rdoc/RubyBreaker/TypeUnparser.html +1 -3
- data/webpage/rdoc/RubyBreaker/Typing.html +1 -3
- data/webpage/rdoc/RubyBreaker/Util.html +0 -2
- data/webpage/rdoc/Test.html +0 -2
- data/webpage/rdoc/Test/Unit.html +0 -2
- data/webpage/rdoc/created.rid +10 -10
- data/webpage/rdoc/index.html +0 -2
- data/webpage/rdoc/js/search_index.js +1 -1
- data/webpage/rdoc/table_of_contents.html +31 -38
- metadata +3 -3
- data/webpage/rdoc/RubyBreaker/RDocSupport.html +0 -328
data/NEWS
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.9
|
data/bin/rubybreaker
CHANGED
@@ -9,10 +9,10 @@ module RubyBreaker
|
|
9
9
|
exit(1)
|
10
10
|
end
|
11
11
|
|
12
|
-
# This method prepares
|
12
|
+
# This method prepares the command mode execution of RubyBreaker.
|
13
13
|
def self.main()
|
14
14
|
RubyBreaker.setup_logger()
|
15
|
-
RubyBreaker.verbose("Running RubyBreaker in
|
15
|
+
RubyBreaker.verbose("Running RubyBreaker in the command mode")
|
16
16
|
|
17
17
|
# parse the command-line arguments
|
18
18
|
OPTION_PARSER.parse!
|
@@ -60,7 +60,7 @@ module RubyBreaker
|
|
60
60
|
self.verbose("Done importing #{lib}")
|
61
61
|
end
|
62
62
|
|
63
|
-
#
|
63
|
+
# Runs the main library code at this point
|
64
64
|
RubyBreaker.run()
|
65
65
|
|
66
66
|
# Run the program file!
|
data/lib/rubybreaker.rb
CHANGED
@@ -133,18 +133,22 @@ module RubyBreaker
|
|
133
133
|
if fname && OPTIONS[:save_output]
|
134
134
|
# Check if the file already exists--that is, if it was used for input
|
135
135
|
io_exist = File.exists?(fname)
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
136
|
+
if File.writable?(fname)
|
137
|
+
RubyBreaker.verbose("Saving it to #{fname}")
|
138
|
+
# Append the result to the input file (or create a new file)
|
139
|
+
fmode = OPTIONS[:append] ? "a" : "w"
|
140
|
+
open(fname, fmode) do |f|
|
141
|
+
# When append, do not write the header
|
142
|
+
unless OPTIONS[:append]
|
143
|
+
f.puts "# This file is auto-generated by RubyBreaker"
|
144
|
+
end
|
145
|
+
# But time stamp always
|
146
|
+
f.puts "# Last modified: #{Time.now}"
|
147
|
+
f.puts "require \"rubybreaker\"" unless OPTIONS[:append]
|
148
|
+
f.print code
|
143
149
|
end
|
144
|
-
|
145
|
-
|
146
|
-
f.puts "require \"rubybreaker\"" unless OPTIONS[:append]
|
147
|
-
f.print code
|
150
|
+
else
|
151
|
+
RubyBreaker.verbose("Cannot write to #{fname}.")
|
148
152
|
end
|
149
153
|
end
|
150
154
|
|
data/lib/rubybreaker/doc/rdoc.rb
CHANGED
@@ -94,14 +94,13 @@ module RubyBreaker
|
|
94
94
|
mm.check_before_method(obj, meth_info)
|
95
95
|
end
|
96
96
|
rescue ::Exception => e
|
97
|
+
RubyBreaker.log("Exception #{e.class} has been raised.", :debug, CONTEXT)
|
97
98
|
# Trap it, turn on the global monitor and then re-raise the
|
98
99
|
# exception
|
99
100
|
GLOBAL_MONITOR_SWITCH.turn_on()
|
100
101
|
raise e
|
101
102
|
end
|
102
103
|
|
103
|
-
RubyBreaker.log("break_before_method ended")
|
104
|
-
|
105
104
|
# we are going to turn the switch back on
|
106
105
|
GLOBAL_MONITOR_SWITCH.turn_on()
|
107
106
|
|
@@ -109,9 +108,10 @@ module RubyBreaker
|
|
109
108
|
retval = obj.send(stub_meth_name.to_sym, *meth_info.args,
|
110
109
|
&meth_info.blk)
|
111
110
|
|
112
|
-
# turn
|
111
|
+
# turn the switch off again
|
113
112
|
GLOBAL_MONITOR_SWITCH.turn_off()
|
114
113
|
|
114
|
+
# Remember the return value in the method info object.
|
115
115
|
meth_info.ret = retval
|
116
116
|
|
117
117
|
begin
|
@@ -124,6 +124,7 @@ module RubyBreaker
|
|
124
124
|
rescue ::Exception => e
|
125
125
|
# Trap it, turn on the global monitor and then re-raise the
|
126
126
|
# exception
|
127
|
+
RubyBreaker.log("Exception #{e.class} has been raised.", :debug, CONTEXT)
|
127
128
|
GLOBAL_MONITOR_SWITCH.turn_on()
|
128
129
|
raise e
|
129
130
|
end
|
@@ -143,7 +144,7 @@ module RubyBreaker
|
|
143
144
|
|
144
145
|
# This method returns the alternative (renamed) method name
|
145
146
|
def self.get_alt_meth_name(meth_name)
|
146
|
-
return "
|
147
|
+
return "__rubybreaker_#{meth_name}"
|
147
148
|
end
|
148
149
|
|
149
150
|
# This method returns the original method name
|
@@ -237,11 +238,11 @@ module RubyBreaker
|
|
237
238
|
# Installs an module (class) monitor to the object.
|
238
239
|
def self.install_monitor(monitor_type, mod)
|
239
240
|
|
240
|
-
RubyBreaker.log("Installing
|
241
|
+
RubyBreaker.log("Installing #{monitor_type} monitor for #{mod} started.")
|
241
242
|
|
242
243
|
# Do not re-install monitor if already done so.
|
243
244
|
if MONITOR_MAP[mod]
|
244
|
-
RubyBreaker.log("
|
245
|
+
RubyBreaker.log("#{mod} already has a monitor installed.")
|
245
246
|
return
|
246
247
|
end
|
247
248
|
|
@@ -266,6 +267,7 @@ module RubyBreaker
|
|
266
267
|
end
|
267
268
|
end
|
268
269
|
|
270
|
+
RubyBreaker.log("Installing #{monitor_type} monitor for #{mod} ended.")
|
269
271
|
end
|
270
272
|
|
271
273
|
end
|
@@ -35,13 +35,25 @@ module RubyBreaker
|
|
35
35
|
return @__rubybreaker_type
|
36
36
|
end
|
37
37
|
|
38
|
+
# This method computes the wrap level of any given wrapped object. In
|
39
|
+
# theory, this should always be 1.
|
40
|
+
#
|
41
|
+
# Used for internal debugging purpose only
|
42
|
+
def __rubybreaker_wrap_level() #:nodoc:
|
43
|
+
val = 1
|
44
|
+
if @__rubybreaker_obj.respond_to?(WRAPPED_INDICATOR)
|
45
|
+
val += @__rubybreaker_obj.__rubybreaker_wrap_level
|
46
|
+
end
|
47
|
+
return val
|
48
|
+
end
|
49
|
+
|
38
50
|
#--
|
39
51
|
# The following code generates the "serious problem" warning which is
|
40
52
|
# suppressed by the hack using $VERBOSE. This is ok. This meta
|
41
53
|
# programming code block re-defines BasicObject's methods to redirect
|
42
54
|
# to the actual object.
|
43
55
|
[:"!", :"!=", :"==", :"equal?", :"eql?", :"__id__", :"object_id",
|
44
|
-
:"send", :"__send__", :"instance_eval",
|
56
|
+
:"send", :"__send__", :"instance_eval", :class,
|
45
57
|
:"instance_exec"].each do |meth|
|
46
58
|
|
47
59
|
orig_verbose = $VERBOSE
|
@@ -65,14 +77,20 @@ module RubyBreaker
|
|
65
77
|
return true if mname.to_sym == WRAPPED_INDICATOR
|
66
78
|
return @__rubybreaker_obj.respond_to?(mname)
|
67
79
|
end
|
80
|
+
|
81
|
+
# # Keep track of methods that MUST NOT take wrapped arguments.
|
82
|
+
# WRAP_BLACKLIST = {
|
83
|
+
# ::Array => [:[], :[]=],
|
84
|
+
# ::Hash => [:[], :[]=],
|
85
|
+
# }
|
68
86
|
|
69
87
|
# This method missing method redirects all other method calls.
|
70
88
|
def method_missing(mname,*args,&blk)
|
71
|
-
::RubyBreaker.log("Method_missing for #{mname}")
|
72
89
|
if GLOBAL_MONITOR_SWITCH.switch
|
73
90
|
|
74
91
|
# Be safe and turn the switch off
|
75
92
|
GLOBAL_MONITOR_SWITCH.turn_off
|
93
|
+
::RubyBreaker.log("Object wrapper method_missing for #{mname} started")
|
76
94
|
|
77
95
|
# Must handle send method specially (do not track them)
|
78
96
|
if [:"__send__", :send].include?(mname)
|
@@ -88,16 +106,18 @@ module RubyBreaker
|
|
88
106
|
is_obj_mod = (obj.class == ::Class or obj.class == ::Module)
|
89
107
|
mod = is_obj_mod ? Runtime.eigen_class(obj) : obj.class
|
90
108
|
|
91
|
-
#
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
end
|
109
|
+
# # There are certain methods that should not take wrapped
|
110
|
+
# # argument(s) whatsoever. Use WRAP_BLACKLIST for these.
|
111
|
+
# if !MONITOR_MAP[mod] && WRAP_BLACKLIST[mod] &&
|
112
|
+
# WRAP_BLACKLIST[mod].include?(mname)
|
113
|
+
# args.map! do |arg|
|
114
|
+
# if arg.respond_to?(WRAPPED_INDICATOR)
|
115
|
+
# arg.__rubybreaker_obj
|
116
|
+
# else
|
117
|
+
# arg
|
118
|
+
# end
|
119
|
+
# end
|
120
|
+
# end
|
101
121
|
|
102
122
|
# Turn on the global switch again
|
103
123
|
GLOBAL_MONITOR_SWITCH.turn_on
|
@@ -105,13 +125,15 @@ module RubyBreaker
|
|
105
125
|
# And call the original method
|
106
126
|
retval = @__rubybreaker_obj.send(mname, *args, &blk)
|
107
127
|
|
108
|
-
# No need to wrap the object again...if it's wrapped already
|
109
|
-
unless retval.respond_to?(WRAPPED_INDICATOR)
|
110
|
-
|
111
|
-
end
|
128
|
+
# # No need to wrap the object again...if it's wrapped already
|
129
|
+
# unless retval.respond_to?(WRAPPED_INDICATOR)
|
130
|
+
# retval = ObjectWrapper.new(retval)
|
131
|
+
# end
|
112
132
|
else
|
133
|
+
::RubyBreaker.log("Object wrapper method_missing for #{mname} started")
|
113
134
|
retval = @__rubybreaker_obj.send(mname, *args, &blk)
|
114
135
|
end
|
136
|
+
::RubyBreaker.log("Object wrapper method_missing for #{mname} ended")
|
115
137
|
return retval
|
116
138
|
end
|
117
139
|
end
|
@@ -19,19 +19,31 @@ module RubyBreaker
|
|
19
19
|
# indicate overridden methods.
|
20
20
|
OVERRIDE_PREFIX = "__rubybreaker"
|
21
21
|
|
22
|
-
# Prohibit these module/class+method from being overriden
|
22
|
+
# Prohibit these module/class+method from being overriden.
|
23
23
|
BLACKLIST = {
|
24
24
|
String => [:to_s, :<<, :concat, :gsub],
|
25
25
|
}
|
26
26
|
|
27
|
+
# Allow certain methods of these classes/modules to be overrriden. That
|
28
|
+
# is, they will take unwrapped arguments whatsoever.
|
29
|
+
WHITELIST = {
|
30
|
+
Kernel => [:puts, :putc, :gets, :print, :printf, :raise],
|
31
|
+
IO => [:getc, :gets, :putc, :puts, :print, :printf,
|
32
|
+
:readlines, :readline, :read],
|
33
|
+
Object => [:"==", :equal?, :eql?, :"!="],
|
34
|
+
Enumerable => [:"==", :equal?, :eql?, :"!="],
|
35
|
+
Array => [:"==", :equal?, :eql?, :"!=", :[], :[]=],
|
36
|
+
Hash => [:"==", :equal?, :eql?, :"!=", :[], :[]=],
|
37
|
+
}
|
38
|
+
|
27
39
|
end
|
28
40
|
|
29
41
|
end
|
30
42
|
|
31
43
|
# TODO: More IO related stuff need to be overriden!
|
32
|
-
|
44
|
+
RubyBreaker::Runtime::WHITELIST.each_pair do |mod, mlist|
|
33
45
|
|
34
|
-
|
46
|
+
mlist.each do |meth_name|
|
35
47
|
|
36
48
|
mod.module_eval <<-EOS
|
37
49
|
|
@@ -58,7 +70,7 @@ end
|
|
58
70
|
|
59
71
|
end
|
60
72
|
|
61
|
-
[Symbol, Numeric, Fixnum, Float, Integer, Bignum, String].each do |mod|
|
73
|
+
[Exception, StandardError, ArgumentError, Symbol, Numeric, Fixnum, Float, Integer, Bignum, String].each do |mod|
|
62
74
|
mod.instance_methods(false).each do |meth_name|
|
63
75
|
black_list = RubyBreaker::Runtime::BLACKLIST
|
64
76
|
next if black_list[mod] && black_list[mod].include?(meth_name)
|
@@ -83,32 +95,32 @@ end
|
|
83
95
|
end
|
84
96
|
end
|
85
97
|
|
86
|
-
# TODO: add more modules here as necessary!
|
87
|
-
[Object, Enumerable, Array, Hash].each do |mod|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
end
|
98
|
+
# # TODO: add more modules here as necessary!
|
99
|
+
# [Object, Enumerable, Array, Hash].each do |mod|
|
100
|
+
#
|
101
|
+
# [:"==", :equal?, :eql?, :"!="].each do |meth_name|
|
102
|
+
#
|
103
|
+
# # Create a unique alias name for each module. (It causes some issue when
|
104
|
+
# # not done this way.)
|
105
|
+
# alias_name = "RubyBreaker::Runtime::OVERRIDE_PREFIX_#{mod.object_id}" +
|
106
|
+
# "_#{meth_name}"
|
107
|
+
#
|
108
|
+
# mod.module_eval <<-EOS
|
109
|
+
#
|
110
|
+
# alias :"#{alias_name}" :"#{meth_name}"
|
111
|
+
#
|
112
|
+
# def #{meth_name}(other)
|
113
|
+
# if other.respond_to?(RubyBreaker::Runtime::WRAPPED_INDICATOR)
|
114
|
+
# other = other.__rubybreaker_obj
|
115
|
+
# end
|
116
|
+
# return self.send(:"#{alias_name}",other)
|
117
|
+
# end
|
118
|
+
#
|
119
|
+
# EOS
|
120
|
+
#
|
121
|
+
# end
|
122
|
+
#
|
123
|
+
# end
|
112
124
|
|
113
125
|
|
114
126
|
|
@@ -41,21 +41,31 @@ module RubyBreaker
|
|
41
41
|
# most restrictive for the given test cases.
|
42
42
|
arg_types = []
|
43
43
|
|
44
|
+
# Resolve the argument types first.
|
44
45
|
exist_meth_type.arg_types.each_with_index do |exist_arg_type, i|
|
45
46
|
arg_type = nil
|
46
47
|
new_arg_type = new_meth_type.arg_types[i]
|
47
48
|
if !exist_arg_type
|
48
|
-
# nil means there hasn't been any type observed
|
49
|
+
# nil means there hasn't been any type observed so use the new
|
50
|
+
# argument type as "resolved".
|
49
51
|
arg_type = new_arg_type
|
50
52
|
elsif new_arg_type.subtype_of?(exist_arg_type)
|
53
|
+
# Pick the subtype argument since we are resolving in
|
54
|
+
# contra-variance
|
55
|
+
arg_type = new_arg_type
|
56
|
+
elsif exist_arg_type.subtype_of?(new_arg_type)
|
57
|
+
# Pick the subtype argument since we are resolving in
|
58
|
+
# contra-variance
|
51
59
|
arg_type = exist_arg_type
|
52
|
-
|
53
|
-
# No subtype relation between them, so OR them
|
60
|
+
else
|
61
|
+
# No subtype relation between them, so OR them.
|
54
62
|
arg_type = OrType.new([new_arg_type, exist_arg_type])
|
55
63
|
end
|
56
64
|
arg_types << arg_type
|
57
65
|
end
|
58
66
|
|
67
|
+
# Now, resolve the return type
|
68
|
+
|
59
69
|
new_ret_type = new_meth_type.ret_type
|
60
70
|
exist_ret_type = exist_meth_type.ret_type
|
61
71
|
|
@@ -63,10 +73,12 @@ module RubyBreaker
|
|
63
73
|
ret_type = new_ret_type
|
64
74
|
resolved = true
|
65
75
|
elsif exist_ret_type.subtype_of?(new_ret_type)
|
66
|
-
|
76
|
+
# Co-variance
|
77
|
+
ret_type = new_ret_type
|
67
78
|
resolved = true
|
68
79
|
elsif new_ret_type.subtype_of?(exist_ret_type)
|
69
|
-
|
80
|
+
# Co-variance
|
81
|
+
ret_type = exist_ret_type
|
70
82
|
resolved = true
|
71
83
|
else
|
72
84
|
resolved = false
|
@@ -213,6 +225,8 @@ module RubyBreaker
|
|
213
225
|
args = meth_info.args
|
214
226
|
# blk = meth_info.blk
|
215
227
|
|
228
|
+
RubyBreaker.log("check_before_method #{mod}##{meth_name} started")
|
229
|
+
|
216
230
|
# Get the registered method type for this method
|
217
231
|
meth_type = meth_type_map[meth_name]
|
218
232
|
|
@@ -263,6 +277,7 @@ module RubyBreaker
|
|
263
277
|
end
|
264
278
|
end
|
265
279
|
|
280
|
+
RubyBreaker.log("check_before_method #{mod}##{meth_name} ended")
|
266
281
|
end
|
267
282
|
|
268
283
|
# This method is invoked after the original method is executed.
|
@@ -270,13 +285,16 @@ module RubyBreaker
|
|
270
285
|
is_obj_mod = (obj.class == Class or obj.class == Module)
|
271
286
|
mod = is_obj_mod ? Runtime.eigen_class(obj) : obj.class
|
272
287
|
|
288
|
+
# Get the method type map for the module/class from the global map.
|
273
289
|
meth_type_map = TYPE_MAP[mod]
|
274
|
-
return unless meth_type_map
|
290
|
+
return unless meth_type_map
|
275
291
|
|
276
292
|
# Let's take things out of the MethodInfo object
|
277
293
|
meth_name = meth_info.meth_name
|
278
294
|
ret = meth_info.ret
|
279
295
|
|
296
|
+
RubyBreaker.log("check_after_method #{mod}##{meth_name} started")
|
297
|
+
|
280
298
|
# Get the registered method type for this method
|
281
299
|
meth_type = meth_type_map[meth_name]
|
282
300
|
|
@@ -286,6 +304,8 @@ module RubyBreaker
|
|
286
304
|
" return value does not have type #{ret_type.unparse()}."
|
287
305
|
raise Errors::ReturnTypeError.new(msg)
|
288
306
|
end
|
307
|
+
|
308
|
+
RubyBreaker.log("check_after_method #{mod}##{meth_name} started")
|
289
309
|
end
|
290
310
|
|
291
311
|
# This method occurs before every call to a "monitored" method in a
|
@@ -298,30 +318,37 @@ module RubyBreaker
|
|
298
318
|
is_obj_mod = (obj.class == Class or obj.class == Module)
|
299
319
|
mod = is_obj_mod ? Runtime.eigen_class(obj) : obj.class
|
300
320
|
|
301
|
-
meth_type_map = TYPE_MAP[mod]
|
302
|
-
|
303
321
|
# Let's take things out of the MethodInfo object
|
304
322
|
meth_name = meth_info.meth_name
|
305
323
|
args = meth_info.args
|
306
324
|
blk = meth_info.blk
|
307
325
|
ret = meth_info.ret
|
308
326
|
|
327
|
+
RubyBreaker.log("break_before_method #{mod}##{meth_name} started")
|
328
|
+
|
309
329
|
args = args.map do |arg|
|
310
330
|
if arg == nil || arg.kind_of?(TrueClass) || arg.kind_of?(FalseClass)
|
311
331
|
# XXX: would overrides resolve this issue?
|
312
332
|
arg
|
333
|
+
elsif arg.respond_to?(WRAPPED_INDICATOR)
|
334
|
+
# Don't need to wrap an object that is already wrapped
|
335
|
+
arg
|
313
336
|
else
|
314
337
|
ObjectWrapper.new(arg)
|
315
338
|
end
|
316
339
|
end
|
317
340
|
|
318
|
-
|
319
|
-
|
341
|
+
# Using this module object, retrieve the method type map which
|
342
|
+
# maps method names to method types.
|
343
|
+
meth_type_map = TYPE_MAP[mod]
|
344
|
+
|
345
|
+
# Using the method name, get the type of this method from the map.
|
320
346
|
meth_type = meth_type_map[meth_name]
|
321
347
|
|
322
348
|
if meth_type
|
323
349
|
# This means the method type has been created previously.
|
324
|
-
unless
|
350
|
+
unless !meth_type.instance_of?(MethodType) ||
|
351
|
+
(blk == nil && meth_type.blk_type == nil) &&
|
325
352
|
(!blk || blk.arity == meth_type.blk_type.arg_types.length)
|
326
353
|
raise Errors::TypeError.new("Block usage is inconsistent")
|
327
354
|
end
|
@@ -349,6 +376,8 @@ module RubyBreaker
|
|
349
376
|
|
350
377
|
meth_info.args = args
|
351
378
|
|
379
|
+
RubyBreaker.log("break_before_method #{mod}##{meth_name} ended")
|
380
|
+
|
352
381
|
end
|
353
382
|
|
354
383
|
# This method occurs after every call to a "monitored" method call of
|
@@ -359,16 +388,16 @@ module RubyBreaker
|
|
359
388
|
is_obj_mod = (obj.class == Class or obj.class == Module)
|
360
389
|
mod = is_obj_mod ? Runtime.eigen_class(obj) : obj.class
|
361
390
|
|
362
|
-
# Take things out
|
391
|
+
# Take things out of the method info object
|
363
392
|
meth_name = meth_info.meth_name
|
364
393
|
retval = meth_info.ret
|
365
394
|
args = meth_info.args
|
366
395
|
blk = meth_info.blk
|
367
396
|
|
368
|
-
RubyBreaker.log("
|
397
|
+
RubyBreaker.log("break_after_method #{mod}##{meth_name} started")
|
369
398
|
|
370
399
|
# Compute the least upper bound
|
371
|
-
lub(obj, TYPE_MAP[mod],meth_name,retval
|
400
|
+
lub(obj, TYPE_MAP[mod], meth_name, retval, *args, &blk)
|
372
401
|
|
373
402
|
if obj == retval
|
374
403
|
# It is possible that the method receiver is a wrapped object if
|
@@ -378,6 +407,8 @@ module RubyBreaker
|
|
378
407
|
meth_info.ret = obj
|
379
408
|
end
|
380
409
|
|
410
|
+
RubyBreaker.log("break_after_method #{mod}##{meth_name} ended")
|
411
|
+
|
381
412
|
end
|
382
413
|
|
383
414
|
end
|