Class: Mirah::JVM::Types::TypeFactory
- Inherits:
-
SimpleTypes
- Object
- SimpleTypes
- Mirah::JVM::Types::TypeFactory
- Includes:
- Logging::Logged, TypeSystem
- Defined in:
- lib/mirah/jvm/types/factory.rb,
lib/mirah/jvm/types/basic_types.rb
Defined Under Namespace
Classes: ParanoidHash
Constant Summary
Constants included from Logging::Logged
Instance Attribute Summary collapse
-
#bootclasspath ⇒ Object
Returns the value of attribute bootclasspath.
-
#known_types ⇒ Object
readonly
Returns the value of attribute known_types.
-
#package ⇒ Object
Returns the value of attribute package.
Instance Method Summary collapse
- #_build_generic_type_future(bounds, position) ⇒ Object
- #_declare_method(target, name, args, type) ⇒ Object
- #_find_method_type(scope, target, name, argTypes, macroTypes, position) ⇒ Object
- #_handle_nested_generic_parameter(expectedType, providedType, type_parameter_map, position) ⇒ Object
-
#_handle_nested_generic_return(returnType, genericReturnType, type_parameter_map, position) ⇒ Object
TODO(shepheb): Handles only one level of nesting, it should handle arbitrary depth by recursion.
-
#addDefaultImports(scope) ⇒ Object
TypeSystem methods.
- #addMacro(klass, macro) ⇒ Object
- #base_classpath ⇒ Object
- #basic_type(scope, name) ⇒ Object
- #bootstrap_loader ⇒ Object
- #box(type) ⇒ Object
- #cache_and_wrap(resolved_type) ⇒ Object
- #cache_and_wrap_type(name) ⇒ Object
- #classpath ⇒ Object
- #classpath=(classpath) ⇒ Object
- #create_basic_types ⇒ Object
- #declare_type(scope, name) ⇒ Object
- #define_type(scope, node) ⇒ Object
- #define_types(builder) ⇒ Object
- #defineType(scope, node, name, superclass, interfaces) ⇒ Object
- #extendClass(classname, extensions) ⇒ Object
- #find_type(scope, name) ⇒ Object
- #get(scope, typeref) ⇒ Object
- #get_mirror(name) ⇒ Object
- #get_type(full_name) ⇒ Object
- #getAbstractMethods(type) ⇒ Object
- #getArrayLiteralType(type, position) ⇒ Object
- #getArrayType(type) ⇒ Object
- #getBaseExceptionType ⇒ Object
- #getBlockType ⇒ Object
- #getBooleanType ⇒ Object
- #getCharType(value) ⇒ Object
- #getDefaultExceptionType ⇒ Object
- #getFieldType(target, name, position) ⇒ Object
- #getFixnumType(value) ⇒ Object
- #getFloatType(value) ⇒ Object
- #getHashLiteralType(key_type, value_type, position) ⇒ Object
- #getHashType ⇒ Object
- #getImplicitNilType ⇒ Object
- #getLocalType(scope, name, position) ⇒ Object
- #getMainType(scope, script) ⇒ Object
- #getMetaType(type) ⇒ Object
- #getMethodDefType(target, name, argTypes, returnType, position) ⇒ Object
- #getMethodType(call) ⇒ Object
- #getNullType ⇒ Object
- #getRegexType ⇒ Object
- #getStringType ⇒ Object
- #getSuperClass(future) ⇒ Object
- #getVoidType ⇒ Object
- #infer_override_args(target, name, arg_types) ⇒ Object
- #infer_override_return_type(target, name, arg_types) ⇒ Object
-
#initialize ⇒ TypeFactory
constructor
A new instance of TypeFactory.
- #initialize_copy(other) ⇒ Object
- #known_type(scope, name) ⇒ Object
- #maybe_initialize_builtins(compiler) ⇒ Object
- #mirror_class(klass) ⇒ Object
- #package_search(name, scope) ⇒ Object
- #resource_loader ⇒ Object
- #type(scope, name, array = false, meta = false) ⇒ Object
- #wrap(resolved_type) ⇒ Object
Methods included from Logging::Logged
#error, #info, #log, #logger, #logger_name, #logging?, #vlog, #warning
Constructor Details
#initialize ⇒ TypeFactory
Returns a new instance of TypeFactory.
58 59 60 61 62 63 64 65 66 67 |
# File 'lib/mirah/jvm/types/factory.rb', line 58 def initialize super(":unused") @known_types = ParanoidHash.new @anonymous_classes = Hash.new {|h, k| h[k] = 0} @declarations = [] @mirrors = {} @futures = {} @fields = {} create_basic_types end |
Instance Attribute Details
#bootclasspath ⇒ Object
Returns the value of attribute bootclasspath.
762 763 764 |
# File 'lib/mirah/jvm/types/factory.rb', line 762 def bootclasspath @bootclasspath end |
#known_types ⇒ Object (readonly)
Returns the value of attribute known_types.
49 50 51 |
# File 'lib/mirah/jvm/types/factory.rb', line 49 def known_types @known_types end |
#package ⇒ Object
Returns the value of attribute package.
48 49 50 |
# File 'lib/mirah/jvm/types/factory.rb', line 48 def package @package end |
Instance Method Details
#_build_generic_type_future(bounds, position) ⇒ Object
353 354 355 356 357 358 359 360 361 |
# File 'lib/mirah/jvm/types/factory.rb', line 353 def _build_generic_type_future(bounds, position) typeName = "java.lang.Object" if bounds.size > 1 raise ArgumentError, "Multiple bounds on type variables are not supported." elsif bounds.size == 1 typeName = bounds[0].raw_type.getClassName end GenericTypeFuture.new(position, type(nil, typeName)) end |
#_declare_method(target, name, args, type) ⇒ Object
460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 |
# File 'lib/mirah/jvm/types/factory.rb', line 460 def _declare_method(target, name, args, type) return if args.any? {|a| a.isError } return unless type.kind_of?(MethodFuture) && type.returnType.isResolved resolved = type.returnType.resolve resolved = resolved.returnType if resolved.respond_to?(:returnType) log "Learned {0} method {1}.{2}({3}) = {4}", [ target. ? "static" : "instance", target.full_name, name, args.map{|a| a.full_name}.join(', '), resolved.full_name].to_java rewritten_name = name.sub(/=$/, '_set') if target. target..declare_static_method(rewritten_name, args, resolved, []) else target.declare_method(rewritten_name, args, resolved, []) end end |
#_find_method_type(scope, target, name, argTypes, macroTypes, position) ⇒ Object
271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 |
# File 'lib/mirah/jvm/types/factory.rb', line 271 def _find_method_type(scope, target, name, argTypes, macroTypes, position) if target.respond_to?(:isError) && target.isError return target end type = BaseTypeFuture.new(nil) target.find_method2(target, name, argTypes, macroTypes, target., scope) do |method| if method.nil? unless argTypes.any?{|t| t && t.isError && (type.resolved(t); true)} type.resolved(ErrorType.new([ ["Cannot find %s method %s(%s) on %s" % [ target. ? "static" : "instance", name, argTypes.map{|t| t ? t.full_name : "?"}.join(', '), target.full_name], position]])) end elsif method.kind_of?(Exception) type.resolved(ErrorType.new([[method., position]])) else result = method.return_type # Handle generics. begin if name == 'new' and target.type_parameters result = Mirah::JVM::Types::GenericType.new(result) # Upgrade to a generic type. target.type_parameters.each do |var| result.type_parameter_map.put(var.name, _build_generic_type_future(var.bounds, position)) end genericParameterTypes = method.member.generic_parameter_types if genericParameterTypes genericParameterTypes.each_index do |i| _handle_nested_generic_parameter(genericParameterTypes[i], argTypes[i], result.type_parameter_map, position) end end elsif target.generic? && method.respond_to?(:member) genericParameterTypes = method.member.generic_parameter_types if genericParameterTypes genericParameterTypes.each_index do |i| _handle_nested_generic_parameter(genericParameterTypes[i], argTypes[i], target.type_parameter_map, position) end end result = _handle_nested_generic_return(result, method.member.generic_return_type, target.type_parameter_map, position) result.resolve if result.respond_to?(:resolve) end rescue => ex Mirah.print_error("Error inferring generics: #{ex.}", position) log("Error inferring generics: #{ex.}\n#{ex.backtrace.join("\n")}") result = method.return_type end if result.kind_of?(TypeFuture) if result.isResolved type.resolved(result.resolve) else result.onUpdate {|x, resolved| type.resolved(resolved) } end else type.resolved(result) end # TODO(shepheb): This is modifying the argTypes of _find_method_type, and it shouldn't be. # Moved to the bottom so the generics code above can access the original argTypes that were passed to _find_method_type. argTypes = method.argument_types end end argTypes = argTypes.map do |t| if t.nil? t elsif t.isBlock type.position_set(position) if (position && type.position.nil?) # This should only happen if type is an error. type.resolve else t end end return_type = AssignableTypeFuture.new(nil) return_type.assign(type, position) MethodFuture.new(name, argTypes, return_type, false, position) end |
#_handle_nested_generic_parameter(expectedType, providedType, type_parameter_map, position) ⇒ Object
363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 |
# File 'lib/mirah/jvm/types/factory.rb', line 363 def _handle_nested_generic_parameter(expectedType, providedType, type_parameter_map, position) if expectedType.kind_of?(BiteScript::ASM::TypeVariable) gtf = type_parameter_map.get(expectedType.name) gtf.assign(SimpleFuture.new(providedType), position) elsif expectedType.kind_of?(BiteScript::ASM::Wildcard) && providedType.kind_of?(TypeFuture) # TODO(shepheb): Handle bounds here. gtf = type_parameter_map.get(expectedType.upper_bound.name) gtf.assign(providedType, position) elsif expectedType.kind_of?(BiteScript::ASM::ParameterizedType) # We can assume assignable_from? here, or this method would not have been called. expectedParameters = expectedType.type_arguments # Look up the values of the provided type's parameters. providedParameters = providedType.type_parameters.map do |var| if providedType.generic? providedType.type_parameter_map.get(var.name) else type_parameter_map.get(var.name) end end if expectedParameters && providedParameters && expectedParameters.size == providedParameters.size expectedParameters.each_index do |i| _handle_nested_generic_parameter(expectedParameters[i], providedParameters[i], type_parameter_map, position) end else raise ArgumentError, "Type parameter mismatch: Expected #{expectedParameters}, found #{providedParameters}." end end end |
#_handle_nested_generic_return(returnType, genericReturnType, type_parameter_map, position) ⇒ Object
TODO(shepheb): Handles only one level of nesting, it should handle arbitrary depth by recursion.
394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 |
# File 'lib/mirah/jvm/types/factory.rb', line 394 def _handle_nested_generic_return(returnType, genericReturnType, type_parameter_map, position) if genericReturnType.kind_of?(BiteScript::ASM::TypeVariable) type_parameter_map.get(genericReturnType.name) elsif genericReturnType.kind_of?(BiteScript::ASM::ParameterizedType) returnType = GenericType.new(returnType) expectedTypeParameters = returnType.jvm_type.type_parameters providedTypeParameters = genericReturnType.type_arguments if expectedTypeParameters && providedTypeParameters && expectedTypeParameters.size == providedTypeParameters.size expectedTypeParameters.each_index do |i| returnType.type_parameter_map.put(expectedTypeParameters[i].name, type_parameter_map.get(providedTypeParameters[i].name)) end else raise ArgumentError, "Type parameter mismatch: Expected #{expectedTypeParameters}, found #{providedTypeParameters}" end returnType else returnType end end |
#addDefaultImports(scope) ⇒ Object
TypeSystem methods
113 114 115 |
# File 'lib/mirah/jvm/types/factory.rb', line 113 def addDefaultImports(scope) scope.import('java.lang.*', '*') end |
#addMacro(klass, macro) ⇒ Object
515 516 517 |
# File 'lib/mirah/jvm/types/factory.rb', line 515 def addMacro(klass, macro) klass..add_compiled_macro(macro) end |
#base_classpath ⇒ Object
715 716 717 718 719 720 721 722 723 724 |
# File 'lib/mirah/jvm/types/factory.rb', line 715 def base_classpath if __FILE__.include? '.jar' Mirah::Env.encode_paths([__FILE__.split('!').first.split(Mirah::Env.path_separator).last]) else Mirah::Env.encode_paths(['.', File.dirname(__FILE__) + '/../../../../javalib/mirah-builtins.jar', File.dirname(__FILE__) + '/../../../../javalib/mirah-parser.jar', File.dirname(__FILE__) + '/../../../../javalib/mirah-bootstrap.jar']) end end |
#basic_type(scope, name) ⇒ Object
572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 |
# File 'lib/mirah/jvm/types/factory.rb', line 572 def basic_type(scope, name) if name.kind_of?(Type) || name.kind_of?(NarrowingType) return name.basic_type end orig = name if name.kind_of? Java::JavaClass #TODO is is possible to get here anymore? if name.array? return type(scope, name.component_type, true) else name = name.name end elsif name.respond_to? :java_class name = name.java_class.name end name = name.to_s unless name.kind_of?(::String) raise ArgumentError, "Bad Type #{orig}" if name =~ /Java::/ raise ArgumentError, "Bad Type #{orig.inspect}" if name == '' || name.nil? find_type(scope, name) end |
#bootstrap_loader ⇒ Object
741 742 743 744 745 746 747 748 749 750 751 752 753 754 |
# File 'lib/mirah/jvm/types/factory.rb', line 741 def bootstrap_loader @bootstrap_loader ||= begin parent = if bootclasspath Mirah::Util::IsolatedResourceLoader.new(Mirah::Env.make_urls(bootclasspath)) end if __FILE__ =~ /^(file:.+jar)!/ bootstrap_urls = [java.net.URL.new($1)].to_java(java.net.URL) else bootstrap_jar = File.("#{__FILE__}/../../../../../javalib/mirah-bootstrap.jar") bootstrap_urls = [java.io.File.new(bootstrap_jar).to_uri.to_url].to_java(java.net.URL) end URLClassLoader.new(bootstrap_urls, parent) end end |
#box(type) ⇒ Object
187 188 189 190 191 192 193 194 195 196 197 |
# File 'lib/mirah/jvm/types/factory.rb', line 187 def box(type) boxed = BaseTypeFuture.new(nil) type.on_update do |_, resolved| if resolved.isError || !resolved.primitive? boxed.resolved(resolved) else boxed.resolved(resolved.box_type) end end boxed end |
#cache_and_wrap(resolved_type) ⇒ Object
99 100 101 |
# File 'lib/mirah/jvm/types/factory.rb', line 99 def cache_and_wrap(resolved_type) @futures[resolved_type.name] ||= wrap(resolved_type) end |
#cache_and_wrap_type(name) ⇒ Object
103 104 105 106 107 108 109 110 |
# File 'lib/mirah/jvm/types/factory.rb', line 103 def cache_and_wrap_type(name) @futures[name] ||= begin type = type(nil, name) wrapper = wrap(type) wrapper.resolved(ErrorType.new([["Cannot find class #{name}"]])) if type.nil? wrapper end end |
#classpath ⇒ Object
726 727 728 |
# File 'lib/mirah/jvm/types/factory.rb', line 726 def classpath @classpath ||= base_classpath end |
#classpath=(classpath) ⇒ Object
730 731 732 733 734 735 |
# File 'lib/mirah/jvm/types/factory.rb', line 730 def classpath=(classpath) if classpath @classpath = Mirah::Env.encode_paths [classpath, base_classpath] end @resource_loader = nil end |
#create_basic_types ⇒ Object
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
# File 'lib/mirah/jvm/types/basic_types.rb', line 18 def create_basic_types @known_types.update( 'boolean' => BooleanType.new(self, 'boolean', java.lang.Boolean), 'byte' => IntegerType.new(self, 'byte', java.lang.Byte), 'char' => CharacterType.new(self, 'char', java.lang.Character), 'short' => IntegerType.new(self, 'short', java.lang.Short), 'int' => IntegerType.new(self, 'int', java.lang.Integer), 'long' => LongType.new(self, 'long', java.lang.Long), 'float' => FloatType.new(self, 'float', java.lang.Float), 'double' => DoubleType.new(self, 'double', java.lang.Double) ) @known_types['fixnum'] = @known_types['int'] @known_types['Object'] = type(nil, 'java.lang.Object') @known_types['string'] = @known_types['String'] = @known_types['java.lang.String'] = StringType.new(self, get_mirror('java.lang.String')) type(nil, 'java.lang.Class') @known_types['Iterable'] = @known_types['java.lang.Iterable'] = IterableType.new(self, get_mirror('java.lang.Iterable')) @known_types['void'] = VoidType.new(self) @known_types['null'] = NullType.new(self) @known_types['implicit_nil'] = ImplicitNilType.new(self) end |
#declare_type(scope, name) ⇒ Object
658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 |
# File 'lib/mirah/jvm/types/factory.rb', line 658 def declare_type(scope, name) full_name = name package = scope.package if !name.include?('.') if package && !package.empty? full_name = "#{package}.#{name}" else scope.on_package_change do full_name = "#{scope.package}.#{name}" scope.import(full_name, name) @known_types[full_name] = @known_types[name] end end end if @known_types.include? full_name @known_types[full_name] else scope.import(full_name, name) @known_types[full_name] = TypeDefinition.new(self, scope, full_name, nil) end end |
#define_type(scope, node) ⇒ Object
680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 |
# File 'lib/mirah/jvm/types/factory.rb', line 680 def define_type(scope, node) if node.name.nil? outer_node = node.find_ancestor {|n| (n != node && n.kind_of?(ClassDefinition)) || n.kind_of?(Script)} if outer_node.kind_of?(ClassDefinition) outer_name = outer_node.name.identifier else outer_name = Mirah::JVM::Compiler::JVMBytecode.classname_from_filename(node.position.source.name || 'DashE') end id = (@anonymous_classes[outer_name] += 1) node.name_set(SimpleString.new("#{outer_name}$#{id}")) end name = node.name.identifier full_name = name package = scope.package if !name.include?('.') && package && !package.empty? full_name = "#{package}.#{name}" end if @known_types.include?(full_name) && @known_types[full_name].kind_of?(TypeDefinition) existing = @known_types[full_name] unless existing.node existing.node = node existing.scope = scope end existing else if InterfaceDeclaration === node klass = InterfaceDefinition else klass = TypeDefinition end scope.import(full_name, name) @known_types[full_name] = klass.new(self, scope, full_name, node) end end |
#define_types(builder) ⇒ Object
550 551 552 553 554 |
# File 'lib/mirah/jvm/types/factory.rb', line 550 def define_types(builder) @declarations.each do |declaration| declaration.define(builder) end end |
#defineType(scope, node, name, superclass, interfaces) ⇒ Object
498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 |
# File 'lib/mirah/jvm/types/factory.rb', line 498 def defineType(scope, node, name, superclass, interfaces) # TODO what if superclass or interfaces change later? log("Defining type #{name} < #{superclass.resolve.name if superclass} #{interfaces.map{|i|i.resolve.name}.inspect}") type = define_type(scope, node) future = @futures[type.name] if future future.resolved(type) future else cache_and_wrap(type) end rescue => ex Mirah.print_error("Error defining type #{name}: #{ex.}", node.position) puts ex.backtrace.join("\n\t") ErrorType.new([["Internal error: #{ex}", node.position]]) end |
#extendClass(classname, extensions) ⇒ Object
519 520 521 |
# File 'lib/mirah/jvm/types/factory.rb', line 519 def extendClass(classname, extensions) get_type(classname).load_extensions(extensions) end |
#find_type(scope, name) ⇒ Object
593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 |
# File 'lib/mirah/jvm/types/factory.rb', line 593 def find_type(scope, name) type = get_type(name) return type if type if scope imports = scope.imports if imports.include?(name) name = imports[name] while imports.include?(name) type = get_type(name) return type if type end # TODO support inner class names if name !~ /\./ return package_search(name, scope) end end return nil end |
#get(scope, typeref) ⇒ Object
225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 |
# File 'lib/mirah/jvm/types/factory.rb', line 225 def get(scope, typeref) basic_type = if scope.nil? cache_and_wrap_type(typeref.name) else imports = scope.imports name = typeref.name name = imports[name] while imports.include?(name) types = [ cache_and_wrap_type(name), nil ] packages = [] packages << scope.package if scope.package && scope.package != '' (packages + scope.search_packages).each do |package| types << cache_and_wrap_type("#{package}.#{name}") types << nil end future = PickFirst.new(types, nil) future.position_set(typeref.position) future.("Cannot find class #{typeref.name}") future end if typeref.isArray getArrayType(basic_type) elsif typeref.isStatic getMetaType(basic_type) else basic_type end end |
#get_mirror(name) ⇒ Object
776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 |
# File 'lib/mirah/jvm/types/factory.rb', line 776 def get_mirror(name) @mirrors[name] ||= begin classname = name.tr('.', '/') stream = resource_loader.getResourceAsStream(classname + ".class") if stream mirror = BiteScript::ASM::ClassMirror.load(stream) mirror if mirror.type.class_name == name else # TODO(ribrdb) Should this use a separate sourcepath? url = resource_loader.getResource(classname + ".java") if url file = java.io.File.new(url.toURI) mirrors = JavaSourceMirror.load(file, self) rescue [] mirrors.each do |mirror| @mirrors[mirror.type.class_name] = mirror end if mirrors @mirrors[name] end end end end |
#get_type(full_name) ⇒ Object
630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 |
# File 'lib/mirah/jvm/types/factory.rb', line 630 def get_type(full_name) type = @known_types[full_name] return type.basic_type if type mirror = get_mirror(full_name) unless mirror if full_name =~ /^(.+)\.([^.]+)/ outer_name = $1 inner_name = $2 outer_type = get_type(outer_name) return nil unless outer_type full_name = "#{outer_type.name}$#{inner_name}" mirror = get_mirror(full_name) return nil unless mirror else return nil end end type = Type.new(self, mirror).load_extensions if full_name.include? '$' @known_types[full_name.gsub('$', '.')] = type end @known_types[full_name] = type end |
#getAbstractMethods(type) ⇒ Object
798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 |
# File 'lib/mirah/jvm/types/factory.rb', line 798 def getAbstractMethods(type) methods = [] unless type.isError object = get_type("java.lang.Object") interfaces = [type] until interfaces.empty? interface = interfaces.pop abstract_methods = interface.declared_instance_methods.select {|m| m.abstract?} methods += abstract_methods.select do |m| begin # Skip methods defined on Object object.java_method(m.name, *m.argument_types) false rescue NameError true end end interfaces.concat(interface.interfaces) end # TODO ensure this works with hierarchies of abstract classes # reject the methods implemented by the abstract class if type.abstract? implemented_methods = type.declared_instance_methods.reject{|m| m.abstract?}.map { |m| [m.name, m.argument_types, m.return_type] } methods = methods.reject{|m| implemented_methods.include? [m.name, m.argument_types, m.return_type] } end end methods.map do |method| MethodType.new(method.name, method.argument_types, method.return_type, false) end end |
#getArrayLiteralType(type, position) ⇒ Object
199 200 201 202 203 204 205 206 207 208 209 |
# File 'lib/mirah/jvm/types/factory.rb', line 199 def getArrayLiteralType(type, position) result = Mirah::JVM::Types::GenericType.new(type(nil, 'java.util.List')) # Upgrade to a generic type. variable = result.type_parameters[0] result.type_parameter_map[variable.name] = _build_generic_type_future(variable.bounds, position) result.type_parameter_map[variable.name].assign(box(type), position) wrap(result) rescue => ex Mirah.print_error("Error inferring generics: #{ex.}", position) log("Error inferring generics: #{ex.}\n#{ex.backtrace.join("\n")}") cache_and_wrap_type('java.util.List') end |
#getArrayType(type) ⇒ Object
177 178 179 180 181 182 183 184 185 |
# File 'lib/mirah/jvm/types/factory.rb', line 177 def getArrayType(type) if type.kind_of?(Type) type.array_type else future = BaseTypeFuture.new(nil) type.on_update {|_, resolved| future.resolved(resolved.array_type)} future end end |
#getBaseExceptionType ⇒ Object
120 |
# File 'lib/mirah/jvm/types/factory.rb', line 120 def getBaseExceptionType; cache_and_wrap_type('java.lang.Throwable') end |
#getBlockType ⇒ Object
626 627 628 |
# File 'lib/mirah/jvm/types/factory.rb', line 626 def getBlockType @block_type ||= BlockType.new end |
#getBooleanType ⇒ Object
125 |
# File 'lib/mirah/jvm/types/factory.rb', line 125 def getBooleanType; cache_and_wrap_type('boolean') end |
#getCharType(value) ⇒ Object
144 |
# File 'lib/mirah/jvm/types/factory.rb', line 144 def getCharType(value) cache_and_wrap_type('char') end |
#getDefaultExceptionType ⇒ Object
121 |
# File 'lib/mirah/jvm/types/factory.rb', line 121 def getDefaultExceptionType; cache_and_wrap_type('java.lang.Exception') end |
#getFieldType(target, name, position) ⇒ Object
479 480 481 482 483 484 485 486 487 488 489 490 |
# File 'lib/mirah/jvm/types/factory.rb', line 479 def getFieldType(target, name, position) # This is currently only used for fields in the current class klass = target.resolve key = [klass, name] t = @fields[key] unless t t = AssignableTypeFuture.new(position) @fields[key] = t t.on_update {|x, resolved| klass..declare_field(name, resolved, klass.)} end t end |
#getFixnumType(value) ⇒ Object
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
# File 'lib/mirah/jvm/types/factory.rb', line 127 def getFixnumType(value) long = java.lang.Long.new(value) if long.int_value != value cache_and_wrap_type('long') elsif long.short_value != value cache_and_wrap_type('int') elsif long.byte_value != value wide = type(nil, 'int') narrow = type(nil, 'short') NarrowingTypeFuture.new(nil, wide, narrow) else wide = type(nil, 'int') narrow = type(nil, 'byte') NarrowingTypeFuture.new(nil, wide, narrow) end end |
#getFloatType(value) ⇒ Object
146 147 148 149 150 151 152 153 154 155 |
# File 'lib/mirah/jvm/types/factory.rb', line 146 def getFloatType(value) d = java.lang.Double.new(value) if d.float_value != value cache_and_wrap_type('double') else wide = type(nil, 'double') narrow = type(nil, 'float') NarrowingTypeFuture.new(nil, wide, narrow) end end |
#getHashLiteralType(key_type, value_type, position) ⇒ Object
211 212 213 214 215 216 217 218 219 220 221 222 223 |
# File 'lib/mirah/jvm/types/factory.rb', line 211 def getHashLiteralType(key_type, value_type, position) result = Mirah::JVM::Types::GenericType.new(type(nil, 'java.util.HashMap')) # Upgrade to a generic type. generic_key, generic_value = result.type_parameters for variable, type in [[generic_key, key_type], [generic_value, value_type]] result.type_parameter_map[variable.name] = _build_generic_type_future(variable.bounds, position) result.type_parameter_map[variable.name].assign(box(type), position) end wrap(result) rescue => ex Mirah.print_error("Error inferring generics: #{ex.}", position) log("Error inferring generics: #{ex.}\n#{ex.backtrace.join("\n")}") cache_and_wrap_type('java.util.HashMap') end |
#getHashType ⇒ Object
122 |
# File 'lib/mirah/jvm/types/factory.rb', line 122 def getHashType; cache_and_wrap_type('java.util.HashMap') end |
#getImplicitNilType ⇒ Object
118 |
# File 'lib/mirah/jvm/types/factory.rb', line 118 def getImplicitNilType; cache_and_wrap_type('implicit_nil') end |
#getLocalType(scope, name, position) ⇒ Object
254 255 256 |
# File 'lib/mirah/jvm/types/factory.rb', line 254 def getLocalType(scope, name, position) scope.local_type(name, position) end |
#getMainType(scope, script) ⇒ Object
492 493 494 495 496 |
# File 'lib/mirah/jvm/types/factory.rb', line 492 def getMainType(scope, script) filename = File.basename(script.position.source.name || 'DashE') classname = Mirah::JVM::Compiler::JVMBytecode.classname_from_filename(filename) getMetaType(cache_and_wrap(declare_type(scope, classname))) end |
#getMetaType(type) ⇒ Object
157 158 159 160 161 162 163 164 165 166 167 |
# File 'lib/mirah/jvm/types/factory.rb', line 157 def getMetaType(type) if type.kind_of?(Type) type. else future = BaseTypeFuture.new(nil) type.on_update {|_, resolved| future.resolved(resolved.)} future.position_set(type.position) future.(type.) future end end |
#getMethodDefType(target, name, argTypes, returnType, position) ⇒ Object
414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 |
# File 'lib/mirah/jvm/types/factory.rb', line 414 def getMethodDefType(target, name, argTypes, returnType, position) if target.nil? return ErrorType.new([["No target", position]]) end unless argTypes.all? {|a| a.hasDeclaration} infer_override_args(target, name, argTypes) end if returnType.nil? returnType = infer_override_return_type(target, name, argTypes) end args = argTypes.map {|a| a.resolve} target = target.resolve type = _find_method_type(nil, target, name, args, nil, position) type.onUpdate do |m, resolved| _declare_method(target, name, args, type) end args.each_with_index do |arg, i| if arg.isError argTypes[i].onUpdate do |x, resolved| args[i] = resolved _declare_method(target, name, args, type) end end end if type.kind_of?(ErrorType) puts "Got error type for method #{name} on #{target.resolve} (#{target.resolve.class})" position = type.position rescue nil return_type = AssignableTypeFuture.new(position) return_type.declare(type, position) type = MethodFuture.new(name, args, return_type, false, position) elsif returnType type.returnType.declare(returnType, position) end type.to_java(MethodFuture) rescue => ex target_name = target.respond_to?(:name) ? target.name : target.resolve.name error("Error getting method def type #{target_name}.#{name}: #{ex.}\n#{ex.backtrace.join("\n\t")}") return_type = AssignableTypeFuture.new(nil) return_type.declare(ErrorType.new([["Internal error: #{ex}"]]), nil) MethodFuture.new(name, [], return_type, false, nil) end |
#getMethodType(call) ⇒ Object
258 259 260 261 262 263 264 265 266 267 268 269 |
# File 'lib/mirah/jvm/types/factory.rb', line 258 def getMethodType(call) target = call.resolved_target argTypes = call.resolved_parameters macro_types = call.parameter_nodes.map do |node| get_type(node.java_class.name) end if call.parameter_nodes _find_method_type(call.scope, target, call.name, argTypes, macro_types, call.position) rescue => ex Mirah.print_error("Error getting method type #{target.name}.#{call.name}: #{ex.}", call.position) puts ex.backtrace.join("\n\t") ErrorType.new([["Internal error: #{ex}", call.position]]) end |
#getNullType ⇒ Object
117 |
# File 'lib/mirah/jvm/types/factory.rb', line 117 def getNullType; cache_and_wrap_type('null') end |
#getRegexType ⇒ Object
123 |
# File 'lib/mirah/jvm/types/factory.rb', line 123 def getRegexType; cache_and_wrap_type('java.util.regex.Pattern') end |
#getStringType ⇒ Object
124 |
# File 'lib/mirah/jvm/types/factory.rb', line 124 def getStringType; cache_and_wrap_type('java.lang.String') end |
#getSuperClass(future) ⇒ Object
169 170 171 172 173 174 175 |
# File 'lib/mirah/jvm/types/factory.rb', line 169 def getSuperClass(future) superclass = BaseTypeFuture.new(nil) future.on_update do |_, type| superclass.resolved(type.superclass) end superclass end |
#getVoidType ⇒ Object
119 |
# File 'lib/mirah/jvm/types/factory.rb', line 119 def getVoidType; cache_and_wrap_type('void') end |
#infer_override_args(target, name, arg_types) ⇒ Object
523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 |
# File 'lib/mirah/jvm/types/factory.rb', line 523 def infer_override_args(target, name, arg_types) # TODO What if the method we're overriding hasn't been inferred yet? log("Infering argument types for #{name}") by_name = target.resolve.find_callable_methods(name, true) by_name_and_arity = by_name.select {|m| m.argument_types.size == arg_types.size} filtered_args = Set.new(by_name_and_arity.map {|m| m.argument_types}) if filtered_args.size == 1 arg_types.zip(filtered_args.first).each do |arg, super_arg| arg.declare(cache_and_wrap(super_arg), arg.position) end else log("Found method types:") filtered_args.each {|args| log(" #{args.map{|a|a.full_name}.inspect}")} arg_types.each {|arg| arg.declare(ErrorType.new([["Missing declaration"]]), nil)} # TODO else give a more useful error? end end |
#infer_override_return_type(target, name, arg_types) ⇒ Object
541 542 543 544 545 546 547 548 |
# File 'lib/mirah/jvm/types/factory.rb', line 541 def infer_override_return_type(target, name, arg_types) by_name = target.resolve.find_callable_methods(name, true) by_name_and_arity = {} by_name.each {|m| by_name_and_arity[m.argument_types] = m if m.argument_types.size == arg_types.size } resolved_args = arg_types.map {|a| a.resolve} match = by_name_and_arity[resolved_args] return cache_and_wrap(match.return_type) if match end |
#initialize_copy(other) ⇒ Object
69 70 71 72 73 74 75 76 77 |
# File 'lib/mirah/jvm/types/factory.rb', line 69 def initialize_copy(other) @known_types = other.known_types.dup @known_types.delete_if do |key, value| value.basic_type.kind_of?(Mirah::JVM::Types::TypeDefinition) end @declarations = [] @futures = {} @fields = {} end |
#known_type(scope, name) ⇒ Object
654 655 656 |
# File 'lib/mirah/jvm/types/factory.rb', line 654 def known_type(scope, name) basic_type(scope, name) end |
#maybe_initialize_builtins(compiler) ⇒ Object
79 80 81 82 83 84 85 86 87 88 89 90 91 |
# File 'lib/mirah/jvm/types/factory.rb', line 79 def maybe_initialize_builtins(compiler) if Builtins begin Builtins.initialize_builtins(compiler.type_system) rescue NativeException => ex error("Error initializing builtins", ex.cause) rescue => ex error("Error initializing builtins: #{ex.}\n\t#{ex.backtrace.join("\n\t")}") end else warning "Unable to initialize builtins" end end |
#mirror_class(klass) ⇒ Object
764 765 766 767 768 769 770 771 772 773 774 |
# File 'lib/mirah/jvm/types/factory.rb', line 764 def mirror_class(klass) name = klass.name.tr('.', '/') if klass.respond_to?(:resource_as_stream) stream = klass.resource_as_stream("/#{name}.class") elsif klass.respond_to?(:get_resource_as_stream) stream = klass.get_resource_as_stream("/#{name}.class") else return get_mirror(klass.name) end BiteScript::ASM::ClassMirror.load(stream) end |
#package_search(name, scope) ⇒ Object
613 614 615 616 617 618 619 620 621 622 623 624 |
# File 'lib/mirah/jvm/types/factory.rb', line 613 def package_search(name, scope) packages = [] current_package = scope.package packages << current_package unless current_package.nil? || current_package.empty? packages.concat(scope.search_packages) packages << 'java.lang' packages.each do |package| type = get_type("#{package}.#{name}") return type if type end return nil end |
#resource_loader ⇒ Object
737 738 739 |
# File 'lib/mirah/jvm/types/factory.rb', line 737 def resource_loader @resource_loader ||= URLClassLoader.new(Mirah::Env.make_urls(classpath), bootstrap_loader) end |
#type(scope, name, array = false, meta = false) ⇒ Object
556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 |
# File 'lib/mirah/jvm/types/factory.rb', line 556 def type(scope, name, array=false, =false) if name.kind_of?(BiteScript::ASM::Type) if name.getDescriptor[0] == ?[ return type(scope, name.getElementType, true, ) else name = name.getClassName end elsif name.kind_of?(Type) && name.array? array = true end type = basic_type(scope, name) type = type.array_type if type && array type = type. if type && return type end |
#wrap(resolved_type) ⇒ Object
93 94 95 96 97 |
# File 'lib/mirah/jvm/types/factory.rb', line 93 def wrap(resolved_type) future = BaseTypeFuture.new(nil) future.resolved(resolved_type) if resolved_type future end |