Module: Duby::JVM::MethodLookup
- Included in:
- Compiler::JVM, Types::Type, Typer::JavaTyper
- Defined in:
- lib/duby/jvm/method_lookup.rb
Instance Method Summary collapse
- #each_is_exact(incoming, target) ⇒ Object
- #each_is_exact_or_subtype_or_convertible(incoming, target) ⇒ Object
- #field_lookup(mapped_params, mapped_type, meta, name) ⇒ Object
- #find_jls(mapped_type, name, mapped_params, meta, constructor) ⇒ Object
- #find_method(mapped_type, name, mapped_params, meta) ⇒ Object
- #inner_class(params, type, meta, name) ⇒ Object
- #is_more_specific?(potential, current) ⇒ Boolean
-
#log(msg) ⇒ Object
dummy log; it’s expected the inclusion target will have it.
- #phase1(mapped_params, potentials) ⇒ Object
- #phase2(mapped_params, potentials) ⇒ Object
- #phase3(mapped_params, potentials) ⇒ Object
- #primitive_convertible?(in_type, target_type) ⇒ Boolean
Instance Method Details
#each_is_exact(incoming, target) ⇒ Object
167 168 169 170 171 172 173 174 175 |
# File 'lib/duby/jvm/method_lookup.rb', line 167 def each_is_exact(incoming, target) incoming.each_with_index do |in_type, i| target_type = target[i] # exact match return false unless target_type == in_type end return true end |
#each_is_exact_or_subtype_or_convertible(incoming, target) ⇒ Object
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 |
# File 'lib/duby/jvm/method_lookup.rb', line 177 def each_is_exact_or_subtype_or_convertible(incoming, target) incoming.each_with_index do |in_type, i| target_type = target[i] # exact match next if target_type == in_type # primitive is safely convertible if target_type.primitive? if in_type.primitive? next if primitive_convertible? in_type, target_type end return false end # object type is assignable return false unless target_type.assignable_from? in_type end return true end |
#field_lookup(mapped_params, mapped_type, meta, name) ⇒ Object
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 |
# File 'lib/duby/jvm/method_lookup.rb', line 124 def field_lookup(mapped_params, mapped_type, , name) log("Attempting #{ ? 'static' : 'instance'} field lookup for '#{name}' on class #{mapped_type}") # if we get to this point, the potentials do not match, so we ignore them # search for a field of the given name if name =~ /_set$/ # setter setter = true name = name[0..-5] field = mapped_type.field_setter(name) else # getter setter = false # field accesses don't take arguments return if mapped_params.size > 0 field = mapped_type.field_getter(name) end return nil unless field if ( && !field.static?) || (! && field.static?) field == nil end # check accessibility # TODO: protected field access check appropriate to current type if setter raise "cannot set final field '#{name}' on class #{mapped_type}" if field.final? end raise "cannot access field '#{name}' on class #{mapped_type}" unless field.public? field end |
#find_jls(mapped_type, name, mapped_params, meta, constructor) ⇒ Object
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
# File 'lib/duby/jvm/method_lookup.rb', line 40 def find_jls(mapped_type, name, mapped_params, , constructor) if constructor by_name = mapped_type..declared_constructors elsif by_name = mapped_type.declared_class_methods(name) else by_name = [] cls = mapped_type while cls by_name += cls.declared_instance_methods(name) cls = cls.superclass end end # filter by arity by_name_and_arity = by_name.select {|m| m.argument_types.size == mapped_params.size} phase1_methods = phase1(mapped_params, by_name_and_arity) if phase1_methods.size > 1 method_list = phase1_methods.map do |m| "#{m.name}(#{m.parameter_types.map(&:name).join(', ')})" end.join("\n") raise "Ambiguous targets invoking #{mapped_type}.#{name}:\n#{method_list}" end phase1_methods[0] || phase2(mapped_params, by_name) || phase3(mapped_params, by_name) || field_lookup(mapped_params, mapped_type, , name) || inner_class(mapped_params, mapped_type, , name) end |
#find_method(mapped_type, name, mapped_params, meta) ⇒ Object
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
# File 'lib/duby/jvm/method_lookup.rb', line 7 def find_method(mapped_type, name, mapped_params, ) raise ArgumentError if mapped_params.any? {|p| p.nil?} if name == 'new' if name = "<init>" constructor = true else constructor = false end end begin if constructor method = mapped_type.constructor(*mapped_params) else method = mapped_type.java_method(name, *mapped_params) end rescue NameError # exact args failed, do a deeper search log "No exact match for #{mapped_type.name}.#{name}(#{mapped_params.map(&:name).join ', '})" method = find_jls(mapped_type, name, mapped_params, , constructor) unless method log "Failed to locate method #{mapped_type.name}.#{name}(#{mapped_params.map(&:name).join ', '})" return nil end end log "Found method #{method.declaring_class.name}.#{name}(#{method.argument_types.map(&:name).join ', '}) from #{mapped_type.name}" return method end |
#inner_class(params, type, meta, name) ⇒ Object
161 162 163 164 165 |
# File 'lib/duby/jvm/method_lookup.rb', line 161 def inner_class(params, type, , name) return unless params.size == 0 && log("Attempting inner class lookup for '#{name}' on #{type}") type.inner_class_getter(name) end |
#is_more_specific?(potential, current) ⇒ Boolean
112 113 114 |
# File 'lib/duby/jvm/method_lookup.rb', line 112 def is_more_specific?(potential, current) each_is_exact_or_subtype_or_convertible(potential, current) end |
#log(msg) ⇒ Object
dummy log; it’s expected the inclusion target will have it
5 |
# File 'lib/duby/jvm/method_lookup.rb', line 5 def log(msg); end |
#phase1(mapped_params, potentials) ⇒ Object
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
# File 'lib/duby/jvm/method_lookup.rb', line 73 def phase1(mapped_params, potentials) log "Beginning JLS phase 1 search with params (#{mapped_params.map(&:name)})" # cycle through methods looking for more specific matches; gather matches of equal specificity methods = potentials.inject([]) do |currents, potential| method_params = potential.argument_types raise "Bad arguments for method #{potential.declaring_class}.#{potential.name}" unless method_params.all? # exact match always wins; duplicates not possible if each_is_exact(mapped_params, method_params) return [potential] end # otherwise, check for potential match and compare to current # TODO: missing ambiguity check; picks last method of equal specificity if each_is_exact_or_subtype_or_convertible(mapped_params, method_params) if currents.size > 0 if is_more_specific?(potential.argument_types, currents[0].argument_types) # potential is better, dump all currents currents = [potential] elsif is_more_specific?(currents[0].argument_types, potential.argument_types) # currents are better, try next potential #next else # equal specificity, append to currents currents << potential end else # no previous matches, use potential currents = [potential] end end currents end methods end |
#phase2(mapped_params, potentials) ⇒ Object
116 117 118 |
# File 'lib/duby/jvm/method_lookup.rb', line 116 def phase2(mapped_params, potentials) nil end |
#phase3(mapped_params, potentials) ⇒ Object
120 121 122 |
# File 'lib/duby/jvm/method_lookup.rb', line 120 def phase3(mapped_params, potentials) nil end |
#primitive_convertible?(in_type, target_type) ⇒ Boolean
198 199 200 |
# File 'lib/duby/jvm/method_lookup.rb', line 198 def primitive_convertible?(in_type, target_type) in_type.convertible_to?(target_type) end |