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>
--- /dev/null
+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/
--- /dev/null
+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?;
--- /dev/null
+# 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
--- /dev/null
+# 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
--- /dev/null
+# 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
--- /dev/null
+# 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