contrib/jwrapper: reorganize and document the different names of a JavaType
[nit.git] / contrib / jwrapper / src / code_generator.nit
index 2ed3020..dfa5cab 100644 (file)
@@ -86,10 +86,13 @@ class CodeGenerator
                        end
 
                        # Attributes
-                       for id, java_type in jclass.attributes do
-                               generate_getter_setter(jclass, id, java_type)
+                       for id, attribute in jclass.attributes do if not attribute.is_static then
+                               generate_getter_setter(jclass, id, attribute)
                        end
 
+                       # JNI services
+                       generate_jni_services jclass.class_type
+
                        # Close the class
                        file_out.write "end\n\n"
 
@@ -102,6 +105,16 @@ class CodeGenerator
                                        file_out.write "\n"
                                end
                        end
+
+                       # Static attributes as top-level getters and setters
+                       for id, attribute in jclass.attributes do if attribute.is_static then
+                               generate_getter_setter(jclass, id, attribute)
+                       end
+
+                       # Primitive arrays
+                       for d in [1..opt_arrays.value] do
+                               generate_primitive_array(jclass, d)
+                       end
                end
 
                if stub_for_unknown_types then
@@ -134,8 +147,8 @@ class CodeGenerator
        private fun generate_class_header(jtype: JavaType)
        do
                var nit_type = model.java_to_nit_type(jtype)
-               file_out.write "# Java class: {jtype.to_package_name}\n"
-               file_out.write "extern class {nit_type} in \"Java\" `\{ {jtype.to_package_name} `\}\n"
+               file_out.write "# Java class: {jtype}\n"
+               file_out.write "extern class {nit_type} in \"Java\" `\{ {jtype.extern_equivalent} `\}\n"
                file_out.write "\tsuper JavaObject\n\n"
        end
 
@@ -143,7 +156,7 @@ class CodeGenerator
        do
                var nit_type = jtype.extern_name
 
-               file_out.write "extern class {nit_type} in \"Java\" `\{ {jtype.to_package_name} `\}\n"
+               file_out.write "extern class {nit_type} in \"Java\" `\{ {jtype.extern_equivalent} `\}\n"
                file_out.write "\tsuper JavaObject\n\nend\n"
        end
 
@@ -161,7 +174,6 @@ class CodeGenerator
                        var nit_type = model.java_to_nit_type(jparam)
 
                        if not nit_type.is_known and comment_unknown_types then c = "#"
-                       if jparam.is_primitive_array then c = "#"
 
                        java_args.add "{jparam.param_cast}{nit_id}{nit_id_no}"
                        nit_params.add "{nit_id}{nit_id_no}: {nit_type}"
@@ -184,7 +196,6 @@ class CodeGenerator
                        return_type = model.java_to_nit_type(java_return_type)
 
                        if not return_type.is_known and comment_unknown_types then c = "#"
-                       if java_return_type.is_primitive_array then c = "#"
 
                        nit_signature.add ": " + return_type.to_s
                end
@@ -192,7 +203,7 @@ class CodeGenerator
                # Build the call in Java
                var java_call
                if is_static == true then
-                       java_call = java_class.class_type.to_package_name
+                       java_call = java_class.class_type.package_name
                else java_call = "self"
                java_call += ".{java_method_id}({java_args.join(", ")})"
 
@@ -213,26 +224,40 @@ class CodeGenerator
        end
 
        # Generate getter and setter to access an attribute, of field
-       private fun generate_getter_setter(java_class: JavaClass, java_id: String, java_type: JavaType)
+       private fun generate_getter_setter(java_class: JavaClass, java_id: String,
+               attribute: JavaAttribute)
        do
+               var java_type = attribute.java_type
                var nit_type = model.java_to_nit_type(java_type)
-               var nit_id = java_id.to_nit_method_name
+
+               var nit_id = java_id
+               if attribute.is_static then nit_id = java_class.class_type.extern_name.to_snake_case + "_" + nit_id
+               nit_id = nit_id.to_nit_method_name
                nit_id = java_class.nit_name_for(nit_id, [java_type], false)
 
                var c = ""
                if not nit_type.is_known and comment_unknown_types then c = "#"
-               if java_type.is_primitive_array then c = "#"
+
+               var recv
+               if attribute.is_static then
+                       recv = java_class.class_type.package_name
+               else recv = "self"
+
+               # Tabulation
+               var t = "\t"
+               if attribute.is_static then t = ""
+               var ct = c+t
 
                file_out.write """
-       # Java getter: {{{java_class}}}.{{{java_id}}}
-{{{c}}}        fun {{{nit_id}}}: {{{nit_type}}} in "Java" `{
-{{{c}}}                return self.{{{java_id}}};
-{{{c}}}        `}
+{{{t}}}# Java getter: {{{java_class}}}.{{{java_id}}}
+{{{ct}}}fun {{{nit_id}}}: {{{nit_type}}} in "Java" `{
+{{{ct}}}       return {{{recv}}}.{{{java_id}}};
+{{{ct}}}`}
 
-       # Java setter: {{{java_class}}}.{{{java_id}}}
-{{{c}}}        fun {{{nit_id}}}=(value: {{{nit_type}}}) in "Java" `{
-{{{c}}}                self.{{{java_id}}} = value;
-{{{c}}}        `}
+{{{t}}}# Java setter: {{{java_class}}}.{{{java_id}}}
+{{{ct}}}fun {{{nit_id}}}=(value: {{{nit_type}}}) in "Java" `{
+{{{ct}}}       {{{recv}}}.{{{java_id}}} = value;
+{{{ct}}}`}
 
 """
        end
@@ -257,7 +282,6 @@ class CodeGenerator
                                param_id = param_id.successor(1)
 
                                if not nit_type.is_known and comment_unknown_types then c = "#"
-                               if java_type.is_primitive_array then c = "#"
                        end
 
                        nit_params_s = "(" + nit_params.join(", ") + ")"
@@ -272,6 +296,57 @@ class CodeGenerator
 
 """
        end
+
+       private fun generate_primitive_array(java_class: JavaClass, dimensions: Int)
+       do
+               var base_java_type = java_class.class_type
+               var java_type = base_java_type.clone
+               java_type.array_dimension = dimensions
+
+               var base_nit_type = model.java_to_nit_type(base_java_type)
+               var nit_type = model.java_to_nit_type(java_type)
+
+               file_out.write """
+# Java primitive array: {{{java_type}}}
+extern class {{{nit_type}}} in "Java" `{ {{{java_type.extern_equivalent}}} `}
+       super AbstractJavaArray[{{{base_nit_type}}}]
+
+       # Get a new array of the given `size`
+       new(size: Int) in "Java" `{ return new {{{base_java_type}}}[(int)size]; `}
+
+       redef fun [](i) in "Java" `{ return self[(int)i]; `}
+
+       redef fun []=(i, e) in "Java" `{ self[(int)i] = e; `}
+
+       redef fun length in "Java" `{ return self.length; `}
+
+"""
+               generate_jni_services(java_type)
+               file_out.write """
+end
+
+"""
+       end
+
+       # Generate JNI related services
+       #
+       # For now, mostly avoid issue #845, but more services could be generated as needed.
+       private fun generate_jni_services(java_type: JavaType)
+       do
+               var nit_type = model.java_to_nit_type(java_type)
+
+               file_out.write """
+       redef fun new_global_ref import sys, Sys.jni_env `{
+               Sys sys = {{{nit_type}}}_sys(self);
+               JNIEnv *env = Sys_jni_env(sys);
+               return (*env)->NewGlobalRef(env, self);
+       `}
+
+       redef fun pop_from_local_frame_with_env(jni_env) `{
+               return (*jni_env)->PopLocalFrame(jni_env, self);
+       `}
+"""
+       end
 end
 
 redef class Sys