More clean up on jwrapper, improve terminology and add one feature from #794.
Pull-Request: #1086
Reviewed-by: Jean Privat <jean@pryen.org>
Reviewed-by: Alexandre Terrasa <alexandre@moz-code.org>
Reviewed-by: Frédéric Vachon <fredvac@gmail.com>
-default:
- mkdir -p bin
+all: nitcc grammar bin/jwrapper
+
+nitcc:
make -C ../nitcc
- ../nitcc/src/nitcc ./grammar/javap.sablecc
- ../../bin/nitc ./src/jwrapper.nit -o ./bin/jwrapper
- mv *.nit ./src/
- mkdir -p gen
- mv javap* ./gen/
+
+grammar:
+ ../nitcc/src/nitcc grammar/javap.sablecc
+ mkdir -p src gen
+ mv *.nit src/
+ mv javap* gen/
+
+bin/jwrapper:
+ mkdir -p bin
+ ../../bin/nitc src/jwrapper.nit -o bin/jwrapper
clean:
rm -f bin/javap_test_parser bin/jwrapper
rm -f gen/*
rm -rf .nit_compile/
rm src/javap_lexer.nit src/javap_parser.nit src/javap_test_parser.nit
+
+.PHONY: grammar bin/jwrapper
-# JWRAPPER : Extern classes generator from java .class
-## Description
-jwrapper is a code generator that creates Nit extern classes `in "Java"` from .class files.
+_jwrapper_, an extern class generator from Java class files
-## Installation
-jwrapper is designed to be installed from the `contrib` directory of Nit repository. (http://www.nitlanguage.org)
+# Description
+_jwrapper_ automates wrapping Java classes so they can be accessed from Nit code. It generates Nit extern classes by analyzing Java class files.
+
+_jwrapper_ reuse Nit types of already wrapped Java classes by searching in the `lib/java` and `lib/android` folders in the Nit repository. It won't wrap a class that are already is those folders.
+
+# Installation
+_jwrapper_ is designed to be installed from the `contrib` directory of Nit repository. (http://www.nitlanguage.org)
To initiate installation process, use `make` in the `contrib/jwrapper` directory.
-jwrapper relies on `nitcc` that will be automatically compiled from `contrib/nitcc`.
+_jwrapper_ relies on `nitcc` that will be automatically compiled from `contrib/nitcc`.
-## Usage
-The jwrapper binary can be found under `jwrapper/bin` directory.
+# Usage
+The _jwrapper_ binary can be found under `contrib/jwrapper/bin` directory.
-Since jwrapper uses `grep` to find existing libraries, make sure that the environment variable `NIT_DIR` is properly set to your Nit root directory.
+_jwrapper_ uses `grep` to find existing libraries, make sure that the environment variable `NIT_DIR` is properly set to your Nit root directory.
-Since jwrapper uses `javap` to extract data from .class files, the JDK7 or higher has to be installed and must be in your `$PATH`. (Older versions of `javap` do not show generic signatures)
+_jwrapper_ uses `javap` to extract data from .class files, the JDK7 or higher has to be installed and must be in your `$PATH`. (Older versions of `javap` do not show generic signatures)
Usage :
`-c, --comment`
-* When a method contains at least one unknown type, the code generator will comment the whole method and let the client manage it.
+* When a method contains at least one unknown type, the code generator will comment the whole method and let the client manage it. Unknown types are types that doesn't have an equivalent in Nit as of yet.
`-w, --wrap`
* Print the help message
-Unknown types are types that doesn't have an equivalent in Nit as of yet.
-
-Jwrapper won't wrap a class that already is in the `lib/android` directory.
-
Can't use both -c and -w together, either you comment unknown types or you wrap them.
class_or_interface = class_declaration | interface_declaration;
-class_declaration = class_header '{' field_declaration* '}';
+class_declaration = class_header '{' property_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* '}';
+ '{' property_declaration* '}';
modifier = 'public'|'private'|'protected'|'static'|'final'|'native'|'synchronized'|'abstract'|'threadsafe'|'transient'|'volatile';
type = type_specifier '[]'*;
variable_id = identifier '[]'*;
method_id = identifier;
-field_declaration = method_declaration | constructor_declaration | variable_declaration | static_declaration | ';';
+property_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? ';';
# Services to generate extern class `in "Java"`
module code_generator
-intrude import types
+intrude import model
class CodeGenerator
fun gen_attribute(jid: String, jtype: JavaType): String
do
- return "\tvar {jid.to_snake_case}: {jtype.to_nit_type}\n"
+ return "\tvar {jid.to_nit_method_name}: {jtype.to_nit_type}\n"
end
-
+
fun gen_method(jmethod_id: String, nmethod_id: String, jreturn_type: JavaType, jparam_list: Array[JavaType]): String
do
var java_params = ""
var nit_id = "arg"
var nit_id_no = 0
var nit_types = new Array[NitType]
- var comment = ""
+ var comment = ""
# Parameters
for i in [0..jparam_list.length[ do
end
# Method identifier
- var method_id = nmethod_id.to_snake_case
+ var method_id = nmethod_id.to_nit_method_name
var nit_signature = new Array[String]
nit_signature.add "\tfun {method_id}"
temp.add(" in \"Java\" `\{\n{comment}\t\trecv.{jmethod_id}({java_params});\n{comment}\t`\}\n")
# Methods with return type
else if return_type != null then
- temp.add(" in \"Java\" `\{\n{comment}\t\treturn {jreturn_type.return_cast} recv.{jmethod_id}({java_params});\n{comment}\t`\}\n")
+ temp.add(" in \"Java\" `\{\n{comment}\t\treturn {jreturn_type.return_cast}recv.{jmethod_id}({java_params});\n{comment}\t`\}\n")
# Methods without return type
else if jreturn_type.is_void then
temp.add(" in \"Java\" `\{\n{comment}\t\trecv.{jmethod_id}({java_params});\n{comment}\t`\}\n")
else
imports = """ import {{{ntype}}}.iterator, Iterator[{{{gen_type}}}].is_ok, Iterator[{{{gen_type}}}].next, Iterator[{{{gen_type}}}].item"""
end
-
+
return imports
end
+end
- private fun create_loop(java_type: JavaType, nit_type: NitType, is_param: Bool, jarray_id, narray_id: String): String
+redef class String
+ # Convert the Java method name `self` to the Nit style
+ #
+ # * Converts to snake case
+ # * Strips `Get` and `Set`
+ # * Add suffix `=` to setters
+ fun to_nit_method_name: 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((int){{{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
+ var name
+ if self.has_prefix("Get") then
+ name = self.substring_from(3)
+ else if self.has_prefix("Set") then
+ name = self.substring_from(3)
+ name += "="
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
+ name = self
end
- return loop_header + "\n" + loop_body
+ return name.to_snake_case
end
end
import javap_test_parser
import code_generator
import jtype_converter
-intrude import types
+intrude import model
class JavaVisitor
super Visitor
end
end
-# #
-# F I E L D D E C L A R A T I O N S #
-# #
+# #
+# P R O P E R T Y D E C L A R A T I O N S #
+# #
-# Method declaration in the field declarations
+# Method declaration
redef class Nmethod_declaration
redef fun accept_visitor(v)
do
end
end
-# Constructor declaration in the field declarations
+# Constructor declaration
redef class Nconstructor_declaration
redef fun accept_visitor(v)
do
end
end
-# Variable declaration in the field declarations
+# Variable property declaration
redef class Nvariable_declaration
redef fun accept_visitor(v)
do
end
end
-# Static declaration in the field declarations
+# Static property declaration
redef class Nstatic_declaration
redef fun accept_visitor(v)
do
end
end
-# Identifier of the field
+# Identifier of a variable
redef class Nvariable_id
redef fun accept_visitor(v)
do
# limitations under the License.
# Contains the java and nit type representation used to convert java to nit code
-module types
+module model
import jtype_converter
end
if not self.has_generic_params then return nit_type
-
+
nit_type.generic_params = new Array[NitType]
for param in generic_params do
for i in [0..array_dimension[ do
id += "[]"
end
- else if self.has_generic_params then
+ else if self.has_generic_params then
var gen_list = new Array[String]
for param in generic_params do
do
var id = self.identifier
- if self.has_generic_params then
+ if self.has_generic_params then
var gen_list = new Array[String]
for param in generic_params do
class JavaClass
var class_type = new JavaType(new JavaTypeConverter)
var attributes = new HashMap[String, JavaType]
- var methods = new HashMap[String, Array[JReturnAndParams]]
+
+ # Methods of this class organized by their name
+ var methods = new HashMap[String, Array[JavaMethod]]
+
var unknown_types = new HashSet[JavaType]
var imports = new HashSet[NitModule]
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
+ var signatures = methods.get_or_default(id, new Array[JavaMethod])
+ signatures.add(new JavaMethod(return_type, new Array[JavaType].from(params)))
+ methods[id] = signatures
end
end
-class JReturnAndParams
+# A Java method, with its signature
+class JavaMethod
+ # Type returned by the method
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
+ # Type of the arguments of the method
+ var params: Array[JavaType]
end
+# A Nit module, use to import the referenced extern classes
class NitModule
- var value: String
-
- init(str: String) do value = str
+ # Name of the module
+ var name: String
redef fun ==(other): Bool do return self.to_s == other.to_s
- redef fun to_s: String do return self.value
- redef fun hash: Int do return self.value.hash
+ redef fun to_s: String do return self.name
+ redef fun hash: Int do return self.name.hash
end