contrib/jwrapper: default name of Java primitive arrays are Java?Array
[nit.git] / contrib / jwrapper / src / types.nit
index f953d25..53d95b7 100644 (file)
@@ -20,28 +20,26 @@ module types
 import jtype_converter
 
 class JavaType
-       private var converter = new JavaTypeConverter
-       var identifier: Array[String] = new Array[String]
+       private var converter: JavaTypeConverter
+       var identifier = new Array[String]
        var generic_params: nullable Array[JavaType] = null
        var is_void = false
+
+       # Has some generic type to be resolved (T extends foo => T is resolved to foo)
+       var has_unresolved_types = false
+
+       # Dimension of primitive array: `int[][]` is 2d
        var array_dimension = 0
 
-       fun collections_list: Array[String] is cached do return ["List", "ArrayList", "LinkedList", "Vector", "Set", "SortedSet", "HashSet", "TreeSet", "LinkedHashSet", "Map", "SortedMap", "HashMap", "TreeMap", "Hashtable", "LinkedHashMap"]
-       fun iterable: Array[String] is cached do return ["ArrayList", "Set", "HashSet", "LinkedHashSet", "LinkedList", "Stack", "TreeSet", "Vector"]
-       fun maps: Array[String] is cached do return ["Map", "SortedMap", "HashMap", "TreeMap", "Hashtable", "LinkedHashMap"]
-       fun has_generic_params: Bool do return not generic_params == null
        fun is_primitive_array: Bool do return array_dimension > 0
+
+       fun has_generic_params: Bool do return not generic_params == null
        fun full_id: String do return identifier.join(".")
-       fun id: String do return identifier.last
+       fun id: String do return identifier.last.replace("$", "")
 
-       fun return_cast: String
-       do
-               if self.has_generic_params then
-                       return converter.cast_as_return(self.generic_params[0].id)
-               end
+       init(converter: JavaTypeConverter) do self.converter = converter
 
-               return converter.cast_as_return(self.id)
-       end
+       fun return_cast: String do return converter.cast_as_return(self.id)
 
        fun param_cast: String
        do
@@ -55,15 +53,14 @@ class JavaType
        fun to_nit_type: NitType
        do
                var nit_type: NitType
+               var type_id = null
 
-               if self.is_primitive_array then
-                       return self.convert_primitive_array
+               if not is_primitive_array then
+                       type_id = converter.to_nit_type(self.id)
                end
 
-               var type_id = converter.to_nit_type(self.id)
-
                if type_id == null then
-                       nit_type = new NitType(self.full_id)
+                       nit_type = self.extern_name
                        nit_type.is_complete = false
                else
                        nit_type = new NitType(type_id)
@@ -84,42 +81,39 @@ class JavaType
                return nit_type
        end
 
-       fun convert_primitive_array: NitType
-       do
-               var nit_type = new NitType("Array")
-
-               var last_nit_type = nit_type
+       fun is_iterable: Bool do return iterable.has(self.id)
 
-               for i in [1..array_dimension] do
-                       var temp: NitType
-                       last_nit_type.generic_params = new Array[NitType]
+       fun is_collection: Bool do return is_primitive_array or collections_list.has(self.id)
 
-                       if i == array_dimension then
-                               var temp_type = converter.to_nit_type(self.id)
+       fun is_map: Bool do return maps.has(self.id)
 
-                               if temp_type == null then 
-                                       temp_type = self.full_id
-                                       nit_type.is_complete = false
-                               end
+       fun is_wrapped: Bool do return find_extern_class != null
 
-                               temp = new NitType(temp_type)
-                       else
-                               temp = new NitType("Array")
-                       end
-
-                       last_nit_type.generic_params.add(temp)
+       fun extern_name: NitType
+       do
+               if is_wrapped then return new NitType.with_module(find_extern_class.as(not null).first, find_extern_class.as(not null).second)
 
-                       last_nit_type = temp
+               var name
+               if is_primitive_array then
+                       # Primitive arrays have a special naming convention
+                       name = "Native" + extern_class_name.join("").capitalized + "Array"
+               else
+                       name = "Native" + extern_class_name.join("")
                end
-               
+
+               var nit_type = new NitType(name)
+               nit_type.is_complete = false
                return nit_type
        end
 
-       fun is_iterable: Bool do return iterable.has(self.id)
-
-       fun is_collection: Bool do return is_primitive_array or collections_list.has(self.id)
+       fun to_cast(jtype: String, is_param: Bool): String
+       do
+               if is_param then
+                       return converter.cast_as_param(jtype)
+               end
 
-       fun is_map: Bool do return maps.has(self.id)
+               return converter.cast_as_return(jtype)
+       end
 
        redef fun to_s: String
        do
@@ -142,14 +136,106 @@ class JavaType
                return id
        end
 
-       fun to_cast(jtype: String, is_param: Bool): String
+       # To fully qualified package name
+       # Cuts the primitive array `[]`
+       fun to_package_name: String
        do
-               if is_param then
-                       return converter.cast_as_param(jtype)
+               var str = self.to_s
+               var len = str.length
+
+               return str.substring(0, len - (2*array_dimension))
+       end
+
+       fun resolve_types(conversion_map: HashMap[String, Array[String]])
+       do
+               if identifier.length == 1 then
+                       var resolved_id = conversion_map.get_or_null(self.id)
+                       if resolved_id != null then self.identifier = new Array[String].from(resolved_id)
                end
 
-               return converter.cast_as_return(jtype)
+               if self.has_generic_params then
+                       for params in generic_params do params.resolve_types(conversion_map)
+               end
        end
+
+       private fun extern_class_name: Array[String]
+       do
+               var class_name = new Array[String]
+               class_name.add(self.id)
+
+               if not self.has_generic_params then return class_name
+
+               class_name.add "Of"
+
+               for param in generic_params do class_name.add_all param.extern_class_name
+
+               return class_name
+       end
+
+       # Search inside `lib/android` directory for already wrapped classes
+       # If found, contains the class identifier and the Nit Module name
+       var find_extern_class: nullable Couple[String, NitModule] = find_extern_class_fun is lazy
+
+       private fun find_extern_class_fun: nullable Couple[String, NitModule]
+       do
+               var regex = "extern class Native[a-zA-Z1-9]\\\+[ ]\\\+in[ ]\\\+\"Java\"[ ]*`\{[ ]*" + self.to_s + "\\\+[ ]*`\}"
+               var grep = new IProcess("grep", "-r", regex, "{"NIT_DIR".environ}/lib/android/")
+               var to_eat = ["private", "extern", "class"]
+
+               var output = grep.read_line
+
+               var output_class = output.substring_from(output.index_of(':') + 1)
+               var tokens = output_class.split(" ")
+
+               var nclass_name = ""
+
+               for token in tokens do
+                       if to_eat.has(token) then continue
+                       nclass_name = token
+                       break
+               end
+
+               if nclass_name == "" then return null
+
+               var str = output.substring(0, output.search(".nit").from)
+               str = str.substring_from(str.last_index_of('/') + 1)
+               var mod = new NitModule(str)
+
+               return new Couple[String, NitModule](nclass_name, mod)
+       end
+
+       # Comparison based on fully qualified named and generic params
+       # Ignores primitive array so `a.b.c[][] == a.b.c`
+       redef fun ==(other)
+       do
+               if other isa JavaType then
+                       return self.repr == other.repr
+               end
+               return false
+       end
+
+       redef fun hash do return self.repr.hash
+
+       private fun repr: String
+       do
+               var id = self.full_id
+
+               if self.has_generic_params then
+                       var gen_list = new Array[String]
+
+                       for param in generic_params do
+                               gen_list.add(param.to_s)
+                       end
+
+                       id += "<{gen_list.join(", ")}>"
+               end
+
+               return id
+       end
+
+       fun collections_list: Array[String] is cached do return ["List", "ArrayList", "LinkedList", "Vector", "Set", "SortedSet", "HashSet", "TreeSet", "LinkedHashSet", "Map", "SortedMap", "HashMap", "TreeMap", "Hashtable", "LinkedHashMap"]
+       fun iterable: Array[String] is cached do return ["ArrayList", "Set", "HashSet", "LinkedHashSet", "LinkedList", "Stack", "TreeSet", "Vector"]
+       fun maps: Array[String] is cached do return ["Map", "SortedMap", "HashMap", "TreeMap", "Hashtable", "LinkedHashMap"]
 end
 
 class NitType
@@ -157,6 +243,9 @@ class NitType
        var arg_id: String
        var generic_params: nullable Array[NitType] = null
 
+       # If this NitType was found in `lib/android`, contains the module name to import
+       var mod: nullable NitModule
+
        # Returns `true` if all types have been successfully converted to Nit type
        var is_complete: Bool = true
 
@@ -170,6 +259,19 @@ class NitType
                self.identifier = id
        end
 
+       init with_generic_params(id: String, gen_params: String...)
+       do
+               self.init(id)
+               self.generic_params = new Array[NitType]
+               for param in gen_params do self.generic_params.add new NitType(param)
+       end
+
+       init with_module(id: String, mod: NitModule)
+       do
+               self.init(id)
+               self.mod = mod
+       end
+
        fun is_map: Bool do return maps.has(self.identifier)
 
        redef fun to_s: String
@@ -191,9 +293,11 @@ class NitType
 end
 
 class JavaClass
-       var name = new Array[String]
+       var class_type = new JavaType(new JavaTypeConverter)
        var attributes = new HashMap[String, JavaType]
        var methods = new HashMap[String, Array[JReturnAndParams]]
+       var unknown_types = new HashSet[JavaType]
+       var imports = new HashSet[NitModule]
 
        fun add_method(id: String, return_type: JavaType, params: Array[JavaType])
        do
@@ -214,3 +318,13 @@ class JReturnAndParams
                self.params = params
        end
 end
+
+class NitModule
+       var value: String
+
+       init(str: String) do value = str
+
+       redef fun ==(other): Bool do return self.to_s == other.to_s
+       redef fun to_s: String do return self.value
+       redef fun hash: Int do return self.value.hash
+end