# This file is part of NIT (http://www.nitlanguage.org).
#
# Copyright 2014 Frédéric Vachon <fredvac@gmail.com>
+# Copyright 2015 Alexis Laferrière <alexis.laf@xymus.net>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
class CodeGenerator
- var with_attributes: Bool
- var comment_unknown_types: Bool
- var file_out: FileWriter
- var java_class: JavaClass
- var nb_params: Int
- var module_name: nullable String = null
+ # Path to the output file
+ var file_name: String
- init (file_name: String, jclass: JavaClass, with_attributes, comment: Bool)
- do
- file_out = new FileWriter.open(file_name)
+ # Model of Java class being wrapped
+ var model: JavaModel
- var nit_ext = ".nit"
- if file_name.has_suffix(nit_ext) then
- # Output file ends with .nit, we expect it to be a valid name
- module_name = file_name.strip_extension(nit_ext)
+ # Comment out methods with unknown (unwrapped) types
+ var comment_unknown_types: Bool
- # Otherwise, it may be anything so do not declare a module
- end
+ # Generate stub classes for unknown types used in the generated module
+ var stub_for_unknown_types: Bool
- self.java_class = jclass
- self.with_attributes = with_attributes
- self.comment_unknown_types = comment
+ # Output file
+ var file_out: Writer = new FileWriter.open(file_name) is lazy, writable
+
+ # Name of the Nit module to generate
+ var module_name: nullable String is lazy do
+ if file_name.file_extension == "nit" then
+ # Output file ends with .nit, we expect it to be a valid name
+ return file_name.basename(".nit")
+ else return null
end
+ # Generate the Nit module into `file_out`
fun generate
do
- var jclass = self.java_class
+ # License
+ file_out.write license
- var class_content = new Array[String]
- class_content.add(gen_class_header(jclass.class_type))
-
- if with_attributes then
- for id, jtype in jclass.attributes do class_content.add(gen_attribute(id, jtype))
- end
+ # Module declaration
+ var module_name = module_name
+ if module_name != null then file_out.write "module {module_name}\n"
+ file_out.write "\n"
- 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)}"
- class_content.add gen_method(id, nid, method_info.return_type, method_info.params)
- end
+ # All importations
+ var imports = new HashSet[String]
+ imports.add "import mnit_android\n"
+ for jclass in model.classes do
+ for import_ in jclass.imports do imports.add "import android::{import_}\n"
end
- class_content.add("\nend\n")
+ file_out.write imports.join("\n")
- var wrappers = new Array[String]
- for jtype in jclass.unknown_types do
- if jtype == jclass.class_type then continue
- wrappers.add("\n")
- wrappers.add(gen_unknown_class_header(jtype))
- end
+ for jclass in model.classes do
- var imports = new Array[String]
- imports.add("import mnit_android\n")
- for import_ in jclass.imports do
- imports.add("import android::{import_}\n")
- end
+ file_out.write gen_class_header(jclass.class_type)
- file_out.write(gen_licence)
+ for id, signatures in jclass.methods do
+ var c = 0
+ for signature in signatures do
+ var nid = id
+ if c > 0 then nid += c.to_s
+ c += 1
- var module_name = module_name
- if module_name != null then file_out.write "module {module_name}\n"
+ file_out.write gen_method(jclass, id, nid, signature.return_type, signature.params)
+ file_out.write "\n"
+ end
+ end
+ file_out.write "end\n\n"
+ end
- file_out.write("\n")
- file_out.write(imports.join)
- file_out.write("\n")
- file_out.write(class_content.join)
- file_out.write(wrappers.join)
+ if stub_for_unknown_types then
+ for jtype in model.unknown_types do
+ file_out.write gen_unknown_class_header(jtype)
+ file_out.write "\n"
+ end
+ end
end
- fun gen_licence: String
- do
- return """
+ # License for the header of the generated Nit module
+ var license = """
# This file is part of NIT (http://www.nitlanguage.org).
#
# Licensed under the Apache License, Version 2.0 (the "License");
# limitations under the License.
# This code has been generated using `jwrapper`
-"""
- end
+""" is writable
fun gen_class_header(jtype: JavaType): String
do
var temp = new Array[String]
- temp.add("extern class Native{jtype.id} in \"Java\" `\{ {jtype} `\}\n")
- temp.add("\tsuper JavaObject\n\n")
+ var nit_type = jtype.to_nit_type
+ temp.add "# Java class: {jtype.to_package_name}\n"
+ temp.add "extern class {nit_type} in \"Java\" `\{ {jtype.to_package_name} `\}\n"
+ temp.add "\tsuper JavaObject\n\n"
return temp.join
end
return temp.join
end
- fun gen_attribute(jid: String, jtype: JavaType): String
- do
- 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
+ fun gen_method(java_class: JavaClass, jmethod_id, nmethod_id: String, jreturn_type: JavaType, jparam_list: Array[JavaType]): String
do
var java_params = ""
var nit_params = ""
if jparam.is_wrapped then
java_class.imports.add nit_type.mod.as(not null)
else
+ model.unknown_types.add jparam
if comment_unknown_types then
comment = "#"
else
nit_type = jparam.extern_name
- java_class.unknown_types.add(jparam)
end
end
end
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_id_no += 1
end
+ # Method documentation
+ var doc = "\t# Java implementation: {java_class}.{jmethod_id}\n"
+
# Method identifier
var method_id = nmethod_id.to_nit_method_name
var nit_signature = new Array[String]
if jreturn_type.is_wrapped then
java_class.imports.add return_type.mod.as(not null)
else
+ model.unknown_types.add jreturn_type
if comment_unknown_types then
comment = "#"
else
return_type = jreturn_type.extern_name
- java_class.unknown_types.add(jreturn_type)
end
end
end
var temp = new Array[String]
+ temp.add doc
temp.add(comment + nit_signature.join)
- # FIXME : This huge `if` block is only necessary to copy primitive arrays as long as there's no better way to do it
if comment == "#" then
temp.add(" in \"Java\" `\{\n{comment}\t\tself.{jmethod_id}({java_params});\n{comment}\t`\}\n")
# Methods with return type
end
end
+redef class Sys
+ # List of Nit keywords
+ #
+ # These may also be keywords in Java, but there they would be used capitalized.
+ private var nit_keywords: Array[String] = ["abort", "abstract", "and", "assert",
+ "break", "class", "continue", "do", "else", "end", "enum", "extern", "implies",
+ "import", "init", "interface", "intrude", "if", "in", "is", "isa", "for", "label",
+ "loop", "module", "new", "not", "null", "nullable", "or", "package", "private",
+ "protected", "public", "return", "self", "super", "then", "type", "var", "while"]
+end
+
redef class String
+
# Convert the Java method name `self` to the Nit style
#
# * Converts to snake case
if name.has_prefix("get_") then
name = name.substring_from(4)
else if name.has_prefix("set_") then
- name = name.substring_from(4) + "="
+ name = name.substring_from(4)
+ if nit_keywords.has(name) then name += "_"
+ name += "="
end
+ # Strip the '_' prefix
+ while name.has_prefix("_") do name = name.substring(1, name.length-1)
+
+ # Escape Nit keywords
+ if nit_keywords.has(name) then name += "_"
+
+ # If the name starts by something other than a letter, prefix with `java_`
+ if not name.chars.first.is_letter then name = "java_" + name
+
+ name = name.replace("$", "_")
+
return name
end
end