Merge: jwrapper: An extern class `in "Java"` generator
authorJean Privat <jean@pryen.org>
Tue, 22 Jul 2014 02:57:00 +0000 (22:57 -0400)
committerJean Privat <jean@pryen.org>
Tue, 22 Jul 2014 02:57:00 +0000 (22:57 -0400)
Consider as Work In Progress. This is an overview of what has been done so far on the java wrapper generator. Most of the features are implemented, but there's still a lot of work to do. In its actual form, the tool takes javap output stored in a file and wraps all methods and attributes (not really useful, but implemented) to generate a nit extern class in a .nit file. Up to one collection parameter and one collection return type are copied. Methods containing non-convertible types are auto-commented.

Features to come :
* Auto-generation of extern class for non-convertible types
* User interface with options
* Static overload support

Pull-Request: #571
Reviewed-by: Jean Privat <jean@pryen.org>

contrib/jwrapper/Makefile [new file with mode: 0644]
contrib/jwrapper/grammar/javap.sablecc [new file with mode: 0644]
contrib/jwrapper/src/code_generator.nit [new file with mode: 0644]
contrib/jwrapper/src/javap_visitor.nit [new file with mode: 0644]
contrib/jwrapper/src/jtype_converter.nit [new file with mode: 0644]
contrib/jwrapper/src/types.nit [new file with mode: 0644]
tests/sav/javap_visitor.res [new file with mode: 0644]

diff --git a/contrib/jwrapper/Makefile b/contrib/jwrapper/Makefile
new file mode 100644 (file)
index 0000000..b9d9b00
--- /dev/null
@@ -0,0 +1,14 @@
+default:
+       mkdir -p bin
+       make -C ../nitcc
+       cp ../nitcc/src/nitcc bin/
+       ./bin/nitcc ./grammar/javap.sablecc
+       ../../bin/nitg ./src/javap_visitor.nit -o ./bin/jwrapper
+       mv *.nit ./src/
+       mkdir -p gen
+       mv javap* ./gen/
+
+clean:
+       rm -f bin/javap_test_parser bin/jwrapper
+       rm -f gen/*
+       rm -rf .nit_compile/
diff --git a/contrib/jwrapper/grammar/javap.sablecc b/contrib/jwrapper/grammar/javap.sablecc
new file mode 100644 (file)
index 0000000..4e9165a
--- /dev/null
@@ -0,0 +1,61 @@
+Grammar javap;
+
+Lexer
+
+identifier = ('a'..'z'|'A'..'Z'|'_'|'$') ('a'..'z'|'A'..'Z'|'_'|'$'|'0'..'9')*;
+blank = (' '|'\n'|'\t'|'\r')+;
+separator = ('.'|'/');
+
+Parser
+Ignored blank;
+
+multi_files = class_or_interface*;
+
+class_or_interface = class_declaration | interface_declaration;
+
+class_declaration = class_header '{' field_declaration* '}';
+
+class_header = modifier* 'class' full_class_name extends_declaration?
+                          implements_declaration? throws_declaration?;
+interface_declaration = modifier* 'interface' full_class_name extends_interface_declaration?
+                                               '{' field_declaration* '}';
+
+modifier = 'public'|'private'|'protected'|'static'|'final'|'native'|'synchronized'|'abstract'|'threadsafe'|'transient'|'volatile';
+type = type_specifier '[]'*;
+type_specifier = 'boolean'|'byte'|'char'|'short'|'int'|'float'|'long'|'double' | type_ref;
+
+type_ref = full_class_name | generic_identifier 'extends' full_class_name | '?';
+type_refs = {tail:} type_refs ',' type_ref | {head:} type_ref;
+
+generic_param = '<' generic_parameter_list '>';
+generic_parameter_list = {tail:} generic_parameter_list ',' parameter | {head:} parameter;
+generic_identifier = full_class_name | '?';
+
+full_class_name = full_class_name separator class_name | class_name;
+class_name = identifier generic_param?;
+
+interface_name = full_class_name;
+interface_list = {tail:} interface_list ',' interface_name | {head:} interface_name;
+
+parameter = type '...'?;
+parameter_list_comp = {tail:} parameter_list_comp ',' parameter | {head:} parameter;
+parameter_list = parameter_list_comp;
+
+exception = type;
+exception_list = exception_list ',' exception | exception;
+
+statement = variable_declaration | statement_block | ';';
+statement_block = '{' statement* '}';
+
+variable_id = identifier '[]'*;
+method_id = identifier;
+
+field_declaration = method_declaration | constructor_declaration | variable_declaration | static_declaration | ';';
+variable_declaration = modifier* type variable_id throws_declaration? ';';
+method_declaration = modifier* generic_param? type method_id '(' parameter_list? ')' throws_declaration? ';';
+constructor_declaration = modifier* full_class_name '(' parameter_list? ')' throws_declaration? ';';
+implements_declaration = 'implements' interface_list*;
+extends_interface_declaration = 'extends' interface_list*;
+extends_declaration = 'extends' type;
+static_declaration = modifier* '{' '}' ';';
+throws_declaration = 'throws' exception_list?;
diff --git a/contrib/jwrapper/src/code_generator.nit b/contrib/jwrapper/src/code_generator.nit
new file mode 100644 (file)
index 0000000..e7c471a
--- /dev/null
@@ -0,0 +1,333 @@
+# This file is part of NIT (http://www.nitlanguage.org).
+#
+# Copyright 2014 Frédéric Vachon <fredvac@gmail.com>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Services to generate extern class `in "Java"`
+module code_generator
+
+intrude import types
+
+class CodeGenerator
+
+       var file_out: OFStream
+       var java_class: JavaClass
+       fun code_warehouse: CodeWarehouse do return once new CodeWarehouse
+
+       init (file_name: String, jclass: JavaClass) 
+       do
+               file_out = new OFStream.open(file_name)
+               self.java_class = jclass
+       end
+
+       fun generate
+       do
+               var jclass = self.java_class
+
+               file_out.write("import mnit_android\n")
+               gen_class_header(jclass.name)
+
+               # Attributes generation
+               for id, jtype in jclass.attributes do gen_attribute(id, jtype)
+
+               for id, methods_info in jclass.methods do
+                       for method_info in methods_info do
+                               var nid = id
+                               if methods_info.length > 1 then nid += "{methods_info.index_of(method_info)}"
+                               gen_method(id, nid, method_info.return_type, method_info.params)
+                       end
+               end
+
+               file_out.write("\nend")
+       end
+
+       fun gen_class_header(full_class_name: Array[String])
+       do
+               file_out.write("extern class Native{full_class_name.last} in \"Java\" `\{ {full_class_name.join(".")} `\}\n")
+               file_out.write("\tsuper JavaObject\n\tredef type SELF: Native{full_class_name.last}\n\n")
+       end
+
+       fun gen_attribute(jid: String, jtype: JavaType)
+       do
+               file_out.write("\tvar {jid.to_snake_case}: {jtype.to_nit_type}\n")
+       end
+       
+       fun gen_method(jmethod_id: String, nmethod_id: String, jreturn_type: JavaType, jparam_list: Array[JavaType])
+       do
+               var java_params = ""
+               var nit_params  = ""
+               var nit_id = "arg"
+               var nit_id_no = 0
+               var nit_types = new Array[NitType]
+               var comment = "" 
+
+               # Parameters
+               for i in [0..jparam_list.length[ do
+                       var jparam = jparam_list[i]
+                       var nit_type = jparam.to_nit_type
+                       var cast = ""
+
+                       if not jparam.is_collection then cast = jparam.param_cast
+
+                       nit_types.add(nit_type)
+                       nit_type.arg_id = "{nit_id}{nit_id_no}"
+
+                       if i == jparam_list.length - 1 then
+                               java_params += "{cast}{nit_id}{nit_id_no}"
+                               nit_params  += "{nit_id}{nit_id_no}: {nit_type}"
+                       else
+                               java_params += "{cast}{nit_id}{nit_id_no}" + ", "
+                               nit_params  += "{nit_id}{nit_id_no}: {nit_type}, "
+                       end
+
+                       nit_id_no += 1
+                       # Comment if one type is unknown
+                       if not nit_type.is_complete then comment = "#"
+               end
+
+               # Method identifier
+               var method_id = nmethod_id.to_snake_case
+               var nit_signature = new Array[String]
+
+               nit_signature.add "\tfun {method_id}"
+
+               if not jparam_list.is_empty then
+                       nit_signature.add "({nit_params})"
+               end
+
+               var return_type = null
+
+               if not jreturn_type.is_void then
+                       return_type = jreturn_type.to_nit_type
+                       if not return_type.is_complete then comment = "#"
+                       nit_signature.add ": {return_type} "
+               end
+
+               file_out.write(comment + nit_signature.join(""))
+
+               var param_to_copy = param_to_copy(jparam_list, nit_types)
+
+               # Copy one parameter, the return value, one parameter and the return value or nothing
+               if return_type != null then
+                       if return_type.is_complete and jreturn_type.is_collection then
+                               if param_to_copy != null then
+                                       var rtype_couple = new Couple[JavaType, NitType](jreturn_type, return_type)
+                                       file_out.write(code_warehouse.param_return_copy(rtype_couple, param_to_copy, jmethod_id, java_params))
+                               else
+                                       file_out.write(code_warehouse.return_type_copy(jreturn_type, return_type, jmethod_id, java_params))
+                               end
+                       else if param_to_copy != null then
+                               file_out.write(code_warehouse.param_type_copy(param_to_copy.first, param_to_copy.second, jmethod_id, java_params, true))
+                       else
+                               file_out.write(" in \"Java\" `\{\n\t\t{comment}return {jreturn_type.return_cast} recv.{jmethod_id}({java_params}); \n\t{comment}`\}\n")
+                       end
+               else if jreturn_type.is_void then
+                       if param_to_copy != null then
+                               file_out.write(code_warehouse.param_type_copy(param_to_copy.first, param_to_copy.second, jmethod_id, java_params, false))
+                       else
+                               file_out.write(" in \"Java\" `\{\n\t\t{comment}recv.{jmethod_id}({java_params}); \n\t{comment}`\}\n")
+                       end
+               else
+                       file_out.write(" in \"Java\" `\{\n\t\t{comment}recv.{jmethod_id}({java_params}); \n\t{comment}`\}\n")
+               end
+       end
+
+       # Only one collection type parameter can be copied
+       # If there's none or more than one then `null` is returned
+       fun param_to_copy(jtypes: Array[JavaType], ntypes: Array[NitType]): nullable Couple[JavaType, NitType]
+       do
+               var counter = 0
+               var couple = null
+               for i in [0..jtypes.length[ do
+                       if jtypes[i].is_collection and ntypes[i].is_complete then
+                               counter += 1
+                               if counter > 1 then return null
+                               couple = new Couple[JavaType, NitType](jtypes[i], ntypes[i])
+                       end
+               end
+
+               return couple
+       end
+end
+
+# Contains raw code mostly used to copy collections
+class CodeWarehouse
+
+       # Collection as return value
+       fun return_type_copy(java_type: JavaType, nit_type: NitType, jmethod_id, params_id: String): String
+       do
+               var narray_id = "nit_array"
+               var loop_ = create_loop(java_type, nit_type, false, "java_array", narray_id)
+               var imports = create_imports(nit_type, false)
+
+               return """{{{imports}}} in "Java" `{ 
+               {{{java_type.to_s}}} java_array = recv.{{{jmethod_id}}}({{{params_id}}});
+               int {{{narray_id}}} = new_{{{nit_type.id}}}_of_{{{nit_type.generic_params.join("_")}}}();
+
+               {{{loop_}}}
+
+               return {{{narray_id}}};
+       `}
+       """
+       end
+
+       # Collection as parameter
+       fun param_type_copy(java_type: JavaType, nit_type: NitType, jmethod_id, params_id: String, has_return: Bool): String
+       do
+               var narray_id = "nit_array"
+               var jarray_id = "java_array"
+               var loop_ = create_loop(java_type, nit_type, true, jarray_id, narray_id)
+               var imports = create_imports(nit_type, true)
+               var jtype = java_type.to_s
+               var jinstanciation = create_array_instance(java_type, nit_type, jarray_id)
+               var return_str = ""
+               
+               if has_return then
+                       return_str = "return "
+               end
+
+               params_id = params_id.replace(nit_type.arg_id, jarray_id)
+
+               return """{{{imports}}} in "Java" `{ 
+               {{{jinstanciation}}}
+               int {{{narray_id}}} = new_{{{nit_type.id}}}_of_{{{nit_type.generic_params.join("_")}}}();
+
+               {{{loop_}}}
+
+               {{{return_str}}}recv.{{{jmethod_id}}}({{{params_id}}});
+       `}
+       """
+       end
+
+       # One collection parameter and the return type will be copied
+       fun param_return_copy(return_types, param_types: Couple[JavaType, NitType], jmethod_id, params_id: String): String
+       do
+               var narray_id = "nit_array"
+               var narray_id2 = "nit_array2"
+
+               var r_jtype = return_types.first
+               var r_ntype = return_types.second
+
+               var p_jtype = param_types.first
+               var p_ntype = param_types.second
+
+               var r_loop = create_loop(r_jtype, r_ntype, false, "java_array", narray_id)
+               var p_loop = create_loop(p_jtype, p_ntype, true, "java_array2", narray_id2)
+
+               var imports = new Array[String]
+               
+               # Avoid import duplication
+               if p_ntype.to_s != r_ntype.to_s then
+                       imports.add create_imports(p_ntype, true)
+               end
+
+               imports.add create_imports(r_ntype, false)
+
+               params_id = params_id.replace(p_ntype.arg_id, narray_id)
+
+               var jinstanciation = create_array_instance(p_jtype, p_ntype, "java_array")
+
+               return """{{{imports.join(", ")}}} in "Java" `{
+               {{{jinstanciation}}}
+
+               {{{p_loop}}}
+
+               {{{r_jtype.to_s}}} java_array2 = recv.{{{jmethod_id}}}({{{params_id}}});
+               int {{{narray_id2}}} = new_{{{r_ntype.id}}}_of_{{{r_ntype.generic_params.join("_")}}}();
+
+               {{{r_loop}}}
+
+               return {{{narray_id2}}};
+       `}
+       """
+       end
+
+       private fun create_array_instance(java_type: JavaType, nit_type: NitType, jarray_id: String): String
+       do
+               var jtype = java_type.to_s
+               var instanciation = ""
+
+               if java_type.is_primitive_array then
+                       instanciation = "{jtype} {jarray_id} = new {java_type.full_id}[Array_of_{nit_type.generic_params[0]}_length({nit_type.arg_id})];"
+               else
+                       instanciation = "{jtype} {jarray_id} = new {jtype}();"
+               end
+
+               return instanciation
+       end
+
+       private fun create_imports(nit_type: NitType, is_param: Bool): String
+       do
+               var imports = ""
+               var ntype = nit_type.to_s
+               var gen_type = nit_type.generic_params.join(", ")
+
+               if not is_param then
+                       if nit_type.is_map then
+                               imports = """import {{{ntype}}}, {{{ntype}}}.[]="""
+                       else
+                               imports = """import {{{ntype}}}, {{{ntype}}}.add"""
+                       end
+               else if nit_type.id == "Array" then
+                       imports = """import {{{ntype}}}.length, {{{ntype}}}.[]"""
+               else if nit_type.is_map then
+                       imports = """import {{{ntype}}}.iterator, Iterator[{{{gen_type}}}].is_ok, Iterator[{{{gen_type}}}].next, Iterator[{{{gen_type}}}].item, Iterator[{{{gen_type}}}].key"""
+               else
+                       imports = """import {{{ntype}}}.iterator, Iterator[{{{gen_type}}}].is_ok, Iterator[{{{gen_type}}}].next, Iterator[{{{gen_type}}}].item"""
+               end
+               
+               return imports
+       end
+
+       private fun create_loop(java_type: JavaType, nit_type: NitType, is_param: Bool, jarray_id, narray_id: String): String
+       do
+               var loop_header = ""
+               var loop_body = ""
+               var gen_type = nit_type.generic_params.join("_")
+
+               if is_param then
+                       if java_type.is_primitive_array then
+                               loop_header = "for(int i=0; i < {jarray_id}.length; ++i)"
+                               loop_body   = """\t\t\t{{{jarray_id}}}[i] = {{{java_type.param_cast}}}Array_of_{{{gen_type}}}__index({{{nit_type.arg_id}}}, i);"""
+                       else if nit_type.id == "Array" then
+                               loop_header = """int length = Array_of_{{{gen_type}}}_length({{{nit_type.arg_id}}});\n\t\tfor(int i=0; i < length; ++i)"""
+                               loop_body   = """\t\t\t{{{jarray_id}}}.add({{{java_type.param_cast}}}Array_of_{{{gen_type}}}__index({{{narray_id}}}, i));"""
+                       else
+                               loop_header = """int itr = {{{nit_type.id}}}_of_{{{gen_type}}}_iterator({{{nit_type.arg_id}}});\n\t\twhile(Iterator_of_{{{gen_type}}}_is_ok(itr)) {"""
+                               if nit_type.is_map then
+                                       var key_cast = java_type.to_cast(java_type.generic_params[0].id, true)
+                                       var value_cast = java_type.to_cast(java_type.generic_params[1].id, true)
+                                       loop_body   = """\t\t\t{{{jarray_id}}}[{{{key_cast}}}iterator_of_{{{nit_type.id}}}_key(itr)] = {{{value_cast}}}iterator_of_{{{nit_type.id}}}_item(itr);\n\t\t\titerator_of_{{{gen_type}}}_next(itr);\n\t\t}"""
+                               else
+                                       loop_body   = """\t\t\t{{{jarray_id}}}.add({{{java_type.param_cast}}}iterator_of_{{{nit_type.id}}}_item(itr));\n\t\t\titerator_of_{{{gen_type}}}_next(itr);\n\t\t}"""
+                               end
+                       end
+               else
+                       if nit_type.is_map then
+                               var key_cast = java_type.to_cast(java_type.generic_params[0].id, false)
+                               var value_cast = java_type.to_cast(java_type.generic_params[1].id, false)
+                               loop_header = """for (java.util.Map.Entry<{{{java_type.generic_params[0]}}}, {{{java_type.generic_params[1]}}}> e: {{{jarray_id}}})"""
+                               loop_body   = """\t\t\t{{{nit_type.id}}}_of_{{{gen_type}}}_{{{nit_type.generic_params[1]}}}__index_assign({{{narray_id}}}, {{{key_cast}}}e.getKey(), {{{value_cast}}}e.getValue()); """
+                       else if java_type.is_iterable then
+                               loop_header = """for ({{{java_type.generic_params[0]}}} e: {{{jarray_id}}})"""
+                               loop_body   = """\t\t\t{{{nit_type.id}}}_of_{{{gen_type}}}_add({{{narray_id}}}, {{{java_type.return_cast}}}e);"""
+                       else
+                               loop_header = "for(int i=0; i < {jarray_id}.length; ++i)"
+                               loop_body   = """\t\t\t{{{nit_type.id}}}_of_{{{gen_type}}}_add({{{narray_id}}}, {{{java_type.return_cast}}}{{{jarray_id}}}[i]);"""
+                       end
+               end
+
+               return loop_header + "\n" + loop_body
+       end
+end
diff --git a/contrib/jwrapper/src/javap_visitor.nit b/contrib/jwrapper/src/javap_visitor.nit
new file mode 100644 (file)
index 0000000..5e9896b
--- /dev/null
@@ -0,0 +1,493 @@
+# This file is part of NIT (http://www.nitlanguage.org).
+#
+# Copyright 2014 Frédéric Vachon <fredvac@gmail.com>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Uses a visitor to extract data from the javap output AST
+# It sends the data to `code_generator` module
+module javap_visitor
+
+import javap_test_parser
+import code_generator
+intrude import types
+
+class JavaVisitor
+       super Visitor
+
+       var java_class = new JavaClass
+       var declaration_type: nullable String =  null
+       var declaration_element: nullable String = null
+       var full_class_name = new Array[String]
+
+       var variable_id = ""
+       var variable_type = new JavaType
+
+       var is_generic_param = false
+       var gen_params_index = 0
+
+       var is_primitive_array = false
+
+       var method_id = ""
+       var method_return_type = new JavaType
+       var method_params = new Array[JavaType]
+       var param_index = 0
+
+       redef fun visit(n) do n.accept_visitor(self)
+end
+
+redef class Node
+       fun accept_visitor(v: JavaVisitor) do visit_children(v)
+end
+
+redef class Nidentifier
+       redef fun accept_visitor(v)
+       do
+               if v.declaration_type == "class_header" then
+
+                       if v.declaration_element == "id" then
+                               v.full_class_name.add(self.text)
+                       end
+
+               else if v.declaration_type == "variable" then
+
+                       if v.declaration_element == "id" then
+                               v.variable_id += self.text
+                       else if v.declaration_element == "type" then
+                               if v.is_generic_param then
+                                       v.variable_type.generic_params[v.gen_params_index].identifier.add(self.text)
+                               else
+                                       v.variable_type.identifier.add(self.text)
+                               end
+                       end
+
+               else if v.declaration_type == "method" then
+
+                       if v.declaration_element == "id" then
+                               v.method_id = self.text
+                       else if v.declaration_element == "return_type" then
+                               if self.text == "void" then 
+                                       v.method_return_type.is_void = true
+                               else if v.is_generic_param then
+                                       v.method_return_type.generic_params[v.gen_params_index].identifier.add(self.text)
+                               else
+                                       v.method_return_type.identifier.add(self.text)
+                               end
+                       else if v.declaration_element == "parameter_list" then
+                               if v.is_generic_param then
+                                       v.method_params[v.param_index].generic_params[v.gen_params_index].identifier.add(self.text)
+                               else
+                                       v.method_params[v.param_index].identifier.add(self.text)
+                               end
+                       end
+
+               end
+
+               super
+       end
+end
+
+# Primitive array node
+redef class N_39d_91d_93d_39d
+       redef fun accept_visitor(v)
+       do
+               if v.declaration_type == "variable" then
+                       if v.declaration_element == "type" then
+                               if v.is_generic_param then
+                                       v.variable_type.generic_params[v.gen_params_index].array_dimension += 1
+                               else
+                                       v.variable_type.array_dimension += 1
+                               end
+                       end
+
+               else if v.declaration_type == "method" then
+
+                       if v.declaration_element == "return_type" then
+                               if v.is_generic_param then
+                                       v.method_return_type.generic_params[v.gen_params_index].array_dimension += 1
+                               else
+                                       v.method_return_type.array_dimension += 1
+                               end
+                       else if v.declaration_element == "parameter_list" then
+                               if v.is_generic_param then
+                                       v.method_params[v.param_index].generic_params[v.gen_params_index].array_dimension += 1
+                               else
+                                       v.method_params[v.param_index].array_dimension += 1
+                               end
+                       end
+
+               end
+
+               super
+       end
+end
+
+redef class N_39dchar_39d
+       redef fun accept_visitor(v)
+       do
+               if v.declaration_type == "variable" then
+                       if v.declaration_element == "type" then
+                               v.variable_type.identifier.add(self.text)
+                       end
+               else if v.declaration_type == "method" then
+                       if v.declaration_element == "return_type" then
+                               v.method_return_type.identifier.add(self.text)
+                       else if v.declaration_element == "parameter_list" then
+                               v.method_params[v.param_index].identifier.add(self.text)
+                       end
+               end
+       end
+end
+
+redef class N_39dboolean_39d
+       redef fun accept_visitor(v)
+       do
+               if v.declaration_type == "variable" then
+                       if v.declaration_element == "type" then
+                               v.variable_type.identifier.add(self.text)
+                       end
+               else if v.declaration_type == "method" then
+                       if v.declaration_element == "return_type" then
+                               v.method_return_type.identifier.add(self.text)
+                       else if v.declaration_element == "parameter_list" then
+                               v.method_params[v.param_index].identifier.add(self.text)
+                       end
+               end
+       end
+end
+
+redef class N_39dfloat_39d
+       redef fun accept_visitor(v)
+       do
+               if v.declaration_type == "variable" then
+                       if v.declaration_element == "type" then
+                               v.variable_type.identifier.add(self.text)
+                       end
+               else if v.declaration_type == "method" then
+                       if v.declaration_element == "return_type" then
+                               v.method_return_type.identifier.add(self.text)
+                       else if v.declaration_element == "parameter_list" then
+                               v.method_params[v.param_index].identifier.add(self.text)
+                       end
+               end
+       end
+end
+
+redef class N_39ddouble_39d
+       redef fun accept_visitor(v)
+       do
+               if v.declaration_type == "variable" then
+                       if v.declaration_element == "type" then
+                               v.variable_type.identifier.add(self.text)
+                       end
+               else if v.declaration_type == "method" then
+                       if v.declaration_element == "return_type" then
+                               v.method_return_type.identifier.add(self.text)
+                       else if v.declaration_element == "parameter_list" then
+                               v.method_params[v.param_index].identifier.add(self.text)
+                       end
+               end
+       end
+end
+
+redef class N_39dbyte_39d
+       redef fun accept_visitor(v)
+       do
+               if v.declaration_type == "variable" then
+                       if v.declaration_element == "type" then
+                               v.variable_type.identifier.add(self.text)
+                       end
+               else if v.declaration_type == "method" then
+                       if v.declaration_element == "return_type" then
+                               v.method_return_type.identifier.add(self.text)
+                       else if v.declaration_element == "parameter_list" then
+                               v.method_params[v.param_index].identifier.add(self.text)
+                       end
+               end
+       end
+end
+
+redef class N_39dshort_39d
+       redef fun accept_visitor(v)
+       do
+               if v.declaration_type == "variable" then
+                       if v.declaration_element == "type" then
+                               v.variable_type.identifier.add(self.text)
+                       end
+               else if v.declaration_type == "method" then
+                       if v.declaration_element == "return_type" then
+                               v.method_return_type.identifier.add(self.text)
+                       else if v.declaration_element == "parameter_list" then
+                               v.method_params[v.param_index].identifier.add(self.text)
+                       end
+               end
+       end
+end
+
+redef class N_39dint_39d
+       redef fun accept_visitor(v)
+       do
+               if v.declaration_type == "variable" then
+                       if v.declaration_element == "type" then
+                               v.variable_type.identifier.add(self.text)
+                       end
+               else if v.declaration_type == "method" then
+                       if v.declaration_element == "return_type" then
+                               v.method_return_type.identifier.add(self.text)
+                       else if v.declaration_element == "parameter_list" then
+                               v.method_params[v.param_index].identifier.add(self.text)
+                       end
+               end
+       end
+end
+
+redef class N_39dlong_39d
+       redef fun accept_visitor(v)
+       do
+               if v.declaration_type == "variable" then
+                       if v.declaration_element == "type" then
+                               v.variable_type.identifier.add(self.text)
+                       end
+               else if v.declaration_type == "method" then
+                       if v.declaration_element == "return_type" then
+                               v.method_return_type.identifier.add(self.text)
+                       else if v.declaration_element == "parameter_list" then
+                               v.method_params[v.param_index].identifier.add(self.text)
+                       end
+               end
+       end
+end
+
+#                                  #
+#    C L A S S     H E A D E R     #
+#                                  #
+redef class Nclass_header
+       redef fun accept_visitor(v)
+       do
+               v.declaration_type = "class_header"
+               v.declaration_element = "id"
+               super
+
+               # Exit class declaration
+               v.declaration_type = null
+               v.declaration_element = null
+
+               v.java_class.name = v.full_class_name
+       end
+end
+
+# Extends declaration in the class header
+redef class Nextends_declaration
+       redef fun accept_visitor(v)
+       do
+               v.declaration_element = "extends"
+               super
+               v.declaration_element = null
+       end
+end
+
+# Implements declaration in the class header
+redef class Nimplements_declaration
+       redef fun accept_visitor(v)
+       do
+               v.declaration_element = "implements"
+               super
+               v.declaration_element = null
+       end
+end
+
+#                                          #
+#   F I E L D    D E C L A R A T I O N S   #
+#                                          #
+
+# Method declaration in the field declarations
+redef class Nmethod_declaration
+       redef fun accept_visitor(v)
+       do
+               v.declaration_type = "method"
+               super
+               v.declaration_type = null
+
+               v.java_class.add_method(v.method_id, v.method_return_type, v.method_params)
+
+               v.method_params.clear
+               v.method_id = ""
+               v.method_return_type = new JavaType
+       end
+end
+
+# Constructor declaration in the field declarations
+redef class Nconstructor_declaration
+       redef fun accept_visitor(v)
+       do
+               v.declaration_type = "constructor"
+               super
+               v.declaration_type = null
+       end
+end
+
+# Variable declaration in the field declarations
+redef class Nvariable_declaration
+       redef fun accept_visitor(v)
+       do
+               v.declaration_type = "variable"
+               super
+               v.declaration_type = null
+
+               v.java_class.attributes[v.variable_id] = v.variable_type
+
+               v.variable_id = ""
+               v.variable_type = new JavaType
+       end
+end
+
+# Static declaration in the field declarations
+redef class Nstatic_declaration
+       redef fun accept_visitor(v)
+       do
+               v.declaration_type = "static"
+               super
+               v.declaration_type = null
+       end
+end
+
+# Identifier of the field
+redef class Nvariable_id
+       redef fun accept_visitor(v)
+       do
+               v.declaration_element = "id"
+               super
+               v.declaration_element = null
+       end
+end
+
+# Identifier of the method
+redef class Nmethod_id
+       redef fun accept_visitor(v)
+       do
+               v.declaration_element = "id"
+               super
+               v.declaration_element = null
+       end
+end
+
+redef class Ntype
+       redef fun accept_visitor(v)
+       do
+               if v.declaration_type == "variable" and v.declaration_element != "id" then
+                       v.declaration_element = "type"
+               end
+
+               if v.declaration_type == "method" and v.declaration_element == null then
+                       v.declaration_element = "return_type"
+               end
+
+               super
+
+               if v.declaration_element == "variable" then
+                       v.declaration_element = null
+               end
+       end
+end
+
+redef class Ngeneric_param
+       redef fun accept_visitor(v)
+       do
+               # Ignore the weird generic return type declaration
+               if v.declaration_type == "method" then
+                       if v.declaration_element == null then
+                               v.declaration_element = "ignore"
+                       else
+                               v.is_generic_param = true
+                               v.gen_params_index = 0
+
+                               if v.declaration_element == "return_type" then
+                                       v.method_return_type.generic_params = new Array[JavaType]
+                               else if v.declaration_element == "parameter_list" then
+                                       v.method_params[v.param_index].generic_params = new Array[JavaType]
+                               end
+                       end
+               else if v.declaration_type == "variable" then
+                       if v.declaration_element == "type" then
+                               v.is_generic_param = true
+                               v.gen_params_index = 0
+                               v.variable_type.generic_params = new Array[JavaType]
+                       end
+               end
+
+               super
+
+               v.declaration_element = null
+               v.is_generic_param = false
+       end
+end
+
+redef class Nparameter_list
+       redef fun accept_visitor(v)
+       do
+               v.declaration_element = "parameter_list"
+               v.param_index = 0
+               super
+               v.declaration_element = null
+               v.param_index = 0
+       end
+end
+
+redef class Nparameter
+       redef fun accept_visitor(v)
+       do
+               if v.declaration_type == "method" then
+                       if v.declaration_element == "parameter_list" then
+                               if v.is_generic_param then
+                                       v.method_params[v.param_index].generic_params.add(new JavaType)
+
+                                       super
+
+                                       v.gen_params_index += 1
+                               else
+                                       v.method_params.add(new JavaType)
+
+                                       super
+
+                                       v.param_index += 1
+                               end
+                       else if v.declaration_element == "return_type" and v.is_generic_param then
+
+                               v.method_return_type.generic_params.add(new JavaType)
+
+                               super
+
+                               v.gen_params_index += 1
+                       end
+               else if v.declaration_type == "variable" then
+                       if v.declaration_element == "type" and v.is_generic_param then
+                               v.variable_type.generic_params.add(new JavaType)
+
+                               super
+
+                               v.gen_params_index += 1
+                       end
+               else
+                       super
+               end
+       end
+end
+
+var p = new TestParser_javap
+var tree = p.main
+
+var visitor = new JavaVisitor
+visitor.enter_visit(tree)
+
+var generator = new CodeGenerator("bundle.nit", visitor.java_class)
+generator.generate
diff --git a/contrib/jwrapper/src/jtype_converter.nit b/contrib/jwrapper/src/jtype_converter.nit
new file mode 100644 (file)
index 0000000..95adbb4
--- /dev/null
@@ -0,0 +1,99 @@
+# This file is part of NIT (http://www.nitlanguage.org).
+#
+# Copyright 2014 Frédéric Vachon <fredvac@gmail.com>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Services to convert java type to nit type and get casts if needed
+module jtype_converter
+
+class JavaTypeConverter
+
+       var type_map = new HashMap[String, String]
+       var param_cast_map = new HashMap[String, String]
+       var return_cast_map = new HashMap[String, String]
+
+       init
+       do
+               # Java type to nit type
+               type_map["byte"] = "Int"
+               type_map["Byte"] = "Int"
+               type_map["short"] = "Int"
+               type_map["Short"] = "Int"
+               type_map["int"] = "Int"
+               type_map["Integer"] = "Int"
+               type_map["long"] = "Int"
+               type_map["Long"] = "Int"
+               type_map["char"] = "Char"
+               type_map["Character"] = "Char"
+               type_map["float"] = "Float"
+               type_map["Float"] = "Float"
+               type_map["double"] = "Float"
+               type_map["Double"] = "Float"
+               type_map["boolean"] = "Bool"
+               type_map["Boolean"] = "Bool"
+               type_map["Object"] = "JavaObject"
+               type_map["Bundle"] = "NativeBundle"
+               type_map["String"] = "JavaString"
+               type_map["CharSequence"] = "JavaString"
+
+               # Collections
+               type_map["List"] = "Array"
+               type_map["ArrayList"] = "Array"
+               type_map["LinkedList"] = "List"
+               type_map["Vector"] = "Array"
+       
+               type_map["Set"] = "HashSet"
+               type_map["SortedSet"] = "Still have to make my mind on this one"
+               type_map["HashSet"] = "HashSet"
+               type_map["TreeSet"] = "HashSet"
+               type_map["LinkedHashSet"] = "HashSet"
+               type_map["Map"] = "HashMap"
+               type_map["SortedMap"] = "RBTreeMap"
+               type_map["HashMap"] = "HashMap"
+               type_map["TreeMap"] = "RBTreeMap"
+               type_map["Hashtable"] = "HashMap"
+               type_map["LinkedHashMap"] = "HashMap"
+
+               # Cast if the type is given as a parameter
+               param_cast_map["byte"] = "(byte)"
+               param_cast_map["Byte"] = "(Byte)"
+               param_cast_map["short"] = "(short)"
+               param_cast_map["Short"] = "(short)"
+               param_cast_map["float"] = "(float)"
+               param_cast_map["Float"] = "(float)"
+               # FIXME: Uncomment as soon as Nit `Int` will be equivalent to Java `long`
+               # param_cast_map["int"] = "int"
+               # param_cast_map["Integer"] = "int"
+
+               # Cast if the type is given as a return value
+               return_cast_map["CharSequence"] = "(String)"
+               # FIXME: Erase as soon as the Nit `Int` type will become a Java `long`
+               return_cast_map["long"] = "(int)"
+       end
+
+       fun to_nit_type(java_type: String): nullable String
+       do
+               return self.type_map.get_or_null(java_type)
+       end
+
+       fun cast_as_param(java_type: String): String
+       do
+               return self.param_cast_map.get_or_default(java_type, "")
+       end
+       
+       fun cast_as_return(java_type: String): String
+       do
+               return self.return_cast_map.get_or_default(java_type, "")
+       end
+end
diff --git a/contrib/jwrapper/src/types.nit b/contrib/jwrapper/src/types.nit
new file mode 100644 (file)
index 0000000..f953d25
--- /dev/null
@@ -0,0 +1,216 @@
+# This file is part of NIT (http://www.nitlanguage.org).
+#
+# Copyright 2014 Frédéric Vachon <fredvac@gmail.com>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Contains the java and nit type representation used to convert java to nit code
+module types
+
+import jtype_converter
+
+class JavaType
+       private var converter = new JavaTypeConverter
+       var identifier: Array[String] = new Array[String]
+       var generic_params: nullable Array[JavaType] = null
+       var is_void = false
+       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 full_id: String do return identifier.join(".")
+       fun id: String do return identifier.last
+
+       fun return_cast: String
+       do
+               if self.has_generic_params then
+                       return converter.cast_as_return(self.generic_params[0].id)
+               end
+
+               return converter.cast_as_return(self.id)
+       end
+
+       fun param_cast: String
+       do
+               if self.has_generic_params then
+                       return converter.cast_as_param(self.generic_params[0].id)
+               end
+
+               return converter.cast_as_param(self.id)
+       end
+
+       fun to_nit_type: NitType
+       do
+               var nit_type: NitType
+
+               if self.is_primitive_array then
+                       return self.convert_primitive_array
+               end
+
+               var type_id = converter.to_nit_type(self.id)
+
+               if type_id == null then
+                       nit_type = new NitType(self.full_id)
+                       nit_type.is_complete = false
+               else
+                       nit_type = new NitType(type_id)
+               end
+
+               if not self.has_generic_params then return nit_type
+               
+               nit_type.generic_params = new Array[NitType]
+
+               for param in generic_params do
+                       var nit_param = param.to_nit_type
+
+                       nit_type.generic_params.add(nit_param)
+
+                       if not nit_param.is_complete then nit_type.is_complete = false
+               end
+
+               return nit_type
+       end
+
+       fun convert_primitive_array: NitType
+       do
+               var nit_type = new NitType("Array")
+
+               var last_nit_type = nit_type
+
+               for i in [1..array_dimension] do
+                       var temp: NitType
+                       last_nit_type.generic_params = new Array[NitType]
+
+                       if i == array_dimension then
+                               var temp_type = converter.to_nit_type(self.id)
+
+                               if temp_type == null then 
+                                       temp_type = self.full_id
+                                       nit_type.is_complete = false
+                               end
+
+                               temp = new NitType(temp_type)
+                       else
+                               temp = new NitType("Array")
+                       end
+
+                       last_nit_type.generic_params.add(temp)
+
+                       last_nit_type = temp
+               end
+               
+               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 is_map: Bool do return maps.has(self.id)
+
+       redef fun to_s: String
+       do
+               var id = self.full_id
+
+               if self.is_primitive_array then
+                       for i in [0..array_dimension[ do
+                               id += "[]"
+                       end
+               else 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 to_cast(jtype: String, is_param: Bool): String
+       do
+               if is_param then
+                       return converter.cast_as_param(jtype)
+               end
+
+               return converter.cast_as_return(jtype)
+       end
+end
+
+class NitType
+       var identifier: String
+       var arg_id: String
+       var generic_params: nullable Array[NitType] = null
+
+       # Returns `true` if all types have been successfully converted to Nit type
+       var is_complete: Bool = true
+
+       fun has_generic_params: Bool do return not generic_params == null
+       fun maps: Array[String] is cached do return ["HashMap", "RBTreeMap"]
+
+       fun id: String do return identifier
+
+       init (id: String)
+       do
+               self.identifier = id
+       end
+
+       fun is_map: Bool do return maps.has(self.identifier)
+
+       redef fun to_s: String
+       do
+               var id = self.identifier
+
+               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
+end
+
+class JavaClass
+       var name = new Array[String]
+       var attributes = new HashMap[String, JavaType]
+       var methods = new HashMap[String, Array[JReturnAndParams]]
+
+       fun add_method(id: String, return_type: JavaType, params: Array[JavaType])
+       do
+               var ret_and_params = methods.get_or_default(id, new Array[JReturnAndParams])
+               
+               ret_and_params.add(new JReturnAndParams(return_type, new Array[JavaType].from(params)))
+               methods[id] = ret_and_params
+       end
+end
+
+class JReturnAndParams
+       var return_type: JavaType
+       var params: Array[JavaType]
+
+       init(return_type: JavaType, params: Array[JavaType])
+       do
+               self.return_type = return_type
+               self.params = params
+       end
+end
diff --git a/tests/sav/javap_visitor.res b/tests/sav/javap_visitor.res
new file mode 100644 (file)
index 0000000..4ad3dc3
--- /dev/null
@@ -0,0 +1 @@
+UNDEFINED