Merge: jwrapper generates full APIs, with contructors, getters and setters
authorJean Privat <jean@pryen.org>
Sat, 25 Jul 2015 23:55:12 +0000 (19:55 -0400)
committerJean Privat <jean@pryen.org>
Sat, 25 Jul 2015 23:55:12 +0000 (19:55 -0400)
This PR is the second part to #1578, it updates the structure of jwrapper, adds a lot of features and creates usable APIs.

Main changes:
* Rewrite of the AST visitor, type conversion and entity naming.
* Generate constructors.
* Generate getter/setters to attributes.
* Add the -p option to choose the prefix of extern class names, use the namespace by default.
* Add the -i option to scan for existing wrappers in any directory or file.
* Add the -r option to filter the target classes from a Jar archive using a regular expression.
* Add more simple tests with javap outputs.
* Add a complete (and working) example of using a custom Java collection from Nit.
* Add an example of generating an API for Android using jwrapper. This API passes nitpick, but it has not been tested as it needs to be integrated in our Android framework.

What's to do next:
* Support for primitive arrays. (This is the main reason why ~10% of the functions are disabled)
* Add static functions as top-level methods.
* Generate class hierarchy.
* Use nitls with the -i option and to add importations to the generated module.
* Fix generic params usage.

Pull-Request: #1589
Reviewed-by: Jean Privat <jean@pryen.org>
Reviewed-by: Romain Chanoir <chanoir.romain@courrier.uqam.ca>

lib/standard/README.md [new file with mode: 0644]
lib/standard/kernel.nit
tests/sav/error_class_glob.res
tests/sav/nitce/fixme/base_gen_reassign_alt4.res
tests/sav/nitce/fixme/base_gen_reassign_alt5.res
tests/sav/nitce/fixme/base_gen_reassign_alt6.res

diff --git a/lib/standard/README.md b/lib/standard/README.md
new file mode 100644 (file)
index 0000000..cd780d0
--- /dev/null
@@ -0,0 +1,46 @@
+# Nit Core Library
+
+Core classes and methods used by default by Nit programs and libraries.
+
+## Core Basic Types and Operations
+
+[[doc:kernel]]
+
+### Object
+
+[[doc:Object]]
+
+#### Equality
+
+[[doc:Object::==]]
+[[doc:Object::!=]]
+[[doc:Object::hash]]
+[[doc:Object::is_same_instance]]
+[[doc:Object::object_id]]
+
+#### Debuging
+
+[[doc:Object::output]]
+[[doc:Object::output_class_name]]
+[[doc:Object::is_same_type]]
+
+### Sys
+
+[[doc:Sys]]
+
+#### Program Execution
+
+[[doc:Sys::main]]
+[[doc:Sys::run]]
+
+### Other
+
+[[list:kernel]]
+
+## Core Collections
+
+[[doc:collection]]
+
+## String and Text manipulation
+
+[[doc:text]]
index c7f0751..11c4419 100644 (file)
 # You  are  allowed  to  redistribute it and sell it, alone or is a part of
 # another product.
 
-# Most minimal classes and methods.
-# This module is the root of the standard module hierarchy.
+# Most basic classes and methods.
+#
+# This module is the root of the module hierarchy.
+# It provides a very minimal set of classes and services used as a
+# foundation to define other classes and methods.
 module kernel
 
 import end # Mark this module is a top level one. (must be only one)
@@ -27,9 +30,13 @@ in "C" `{
 ###############################################################################
 
 # The root of the class hierarchy.
-# Each class implicitly specialize Object.
 #
-# Currently, Object is also used to collect all top-level methods.
+# Each other class implicitly specializes Object,
+# therefore the services of Object are inherited by every other class and are usable
+# on each value, including primitive types like integers (`Int`), strings (`String`) and arrays (`Array`).
+#
+# Note that `nullable Object`, not `Object`, is the root of the type hierarchy
+# since the special value `null` is not considered as an instance of Object.
 interface Object
        # Type of this instance, automatically specialized in every class
        #
@@ -53,33 +60,124 @@ interface Object
        # `SELF`, pretty much the same things as you would do with parameter types.
        type SELF: Object
 
-       # The unique object identifier in the class.
-       # Unless specific code, you should not use this method.
-       # The identifier is used internally to provide a hash value.
+       # An internal hash code for the object based on its identity.
+       #
+       # Unless specific code, you should not use this method but
+       # use `hash` instead.
+       #
+       # As its name hints it, the internal hash code, is used internally
+       # to provide a hash value.
+       # It is also used by the `inspect` method to loosely identify objects
+       # and helps debugging.
+       #
+       # ~~~
+       # var a = "Hello"
+       # var b = a
+       # assert a.object_id == b.object_id
+       # ~~~
+       #
+       # The specific details of the internal hash code it let to the specific
+       # engine. The rules are the following:
+       #
+       # * The `object_id` MUST be invariant for the whole life of the object.
+       # * Two living instances of the same classes SHOULD NOT share the same `object_id`.
+       # * Two instances of different classes MIGHT share the same `object_id`.
+       # * The `object_id` of a garbage-collected instance MIGHT be reused by new instances.
+       # * The `object_id` of an object MIGHT be non constant across different executions.
+       #
+       # For instance, the `nitc` compiler uses the address of the object in memory
+       # as its `object_id`.
+       #
+       # TODO rename in something like `internal_hash_code`
        fun object_id: Int is intern
 
        # Return true if `self` and `other` have the same dynamic type.
-       # Unless specific code, you should not use this method.
+       #
+       # ~~~
+       # assert 1.is_same_type(2)
+       # assert "Hello".is_same_type("World")
+       # assert not "Hello".is_same_type(2)
+       # ~~~
+       #
+       # The method returns false if the dynamic type of `other` is a subtype of the dynamic type of `self`
+       # (or the other way around).
+       #
+       # Unless specific code, you should not use this method because it is inconsistent
+       # with the fact that a subclass can be used in lieu of a superclass.
        fun is_same_type(other: Object): Bool is intern
 
-       # Return true if `self` and `other` are the same instance.
-       # Unless specific code, you should use `==` instead.
+       # Return true if `self` and `other` are the same instance (i.e. same identity).
+       #
+       # ~~~
+       # var a = new Buffer
+       # var b = a
+       # var c = new Buffer
+       # assert a.is_same_instance(b)
+       # assert not a.is_same_instance(c)
+       # assert a == c # because both buffers are empty
+       # ~~~
+       #
+       # Obviously, the identity of an object is preserved even if the object is mutated.
+       #
+       # ~~~
+       # var x = [1]
+       # var y = x
+       # x.add 2
+       # assert x.is_same_instance(y)
+       # ~~~
+       #
+       # Unless specific code, you should use `==` instead of `is_same_instance` because
+       # most of the time is it the semantic (and user-defined) comparison that make sense.
+       #
+       # Moreover, relying on `is_same_instance` on objects you do not control
+       # might have unexpected effects when libraries reuse objects or intern them.
        fun is_same_instance(other: nullable Object): Bool is intern
 
        # Have `self` and `other` the same value?
        #
-       # The exact meaning of "same value" is left to the subclasses.
-       # Implicitly, the default implementation, is `is_same_instance`
+       # ~~~
+       # assert 1 + 1 == 2
+       # assert not 1 == "1"
+       # assert 1.to_s == "1"
+       # ~~~
+       #
+       # The exact meaning of *same value* is left to the subclasses.
+       # Implicitly, the default implementation, is `is_same_instance`.
+       #
+       # The laws of `==` are the following:
+       #
+       # * reflexivity `a.is_same_instance(b) implies a == b`
+       # * symmetry: `(a == b) == (b == a)`
+       # * transitivity: `(a == b) and (b == c) implies (a == c)`
+       #
+       # `==` might not be constant on some objects overtime because of their evolution.
+       #
+       # ~~~
+       # var a = [1]
+       # var b = [1]
+       # var c = [1,2]
+       # assert a == b and not a == c
+       # a.add 2
+       # assert not a == b and a == c
+       # ~~~
+       #
+       # Lastly, `==` is highly linked with `hash` and a specific redefinition of `==` should
+       # usually be associated with a specific redefinition of `hash`.
+       #
+       # ENSURE `result implies self.hash == other.hash`
        fun ==(other: nullable Object): Bool do return self.is_same_instance(other)
 
        # Have `self` and `other` different values?
        #
-       # != is equivalent with "not ==".
+       # `!=` is equivalent with `not ==`.
        fun !=(other: nullable Object): Bool do return not (self == other)
 
        # Display self on stdout (debug only).
+       #
        # This method MUST not be used by programs, it is here for debugging
-       # only and can be removed without any notice
+       # only and can be removed without any notice.
+       #
+       # TODO: rename to avoid blocking a good identifier like `output`.
        fun output
        do
                '<'.output
@@ -88,26 +186,112 @@ interface Object
        end
 
        # Display class name on stdout (debug only).
+       #
        # This method MUST not be used by programs, it is here for debugging
-       # only and can be removed without any notice
+       # only and can be removed without any notice.
+       #
+       # TODO: rename to avoid blocking a good identifier like `output`.
        fun output_class_name is intern
 
        # The hash code of the object.
-       # Assuming that a == b -> a.hash == b.hash
        #
-       # Without redefinition, it is based on the `object_id` of the instance.
+       # The hash code is used in many data-structures and algorithms to identify objects that might be equal.
+       # Therefore, the precise semantic of `hash` is highly linked with the semantic of `==`
+       # and the only law of `hash` is that `a == b implies a.hash == b.hash`.
+       #
+       # ~~~
+       # assert (1+1).hash == 2.hash
+       # assert 1.to_s.hash == "1".hash
+       # ~~~
+       #
+       # `hash` (like `==`) might not be constant on some objects over time because of their evolution.
+       #
+       # ~~~
+       # var a = [1]
+       # var b = [1]
+       # var c = [1,2]
+       # assert a.hash == b.hash
+       # a.add 2
+       # assert a.hash == c.hash
+       # # There is a very high probability that `b.hash != c.hash`
+       # ~~~
+       #
+       # A specific redefinition of `==` should usually be associated with a specific redefinition of `hash`.
+       # Note that, unfortunately, a correct definition of `hash` that is lawful with `==` is sometime tricky
+       # and a cause of bugs.
+       #
+       # Without redefinition, `hash` is based on the `object_id` of the instance.
        fun hash: Int do return object_id / 8
 end
 
 # The main class of the program.
-# `Sys` is a singleton class, its only instance is `sys` defined in `Object`.
-# `sys` is used to invoke methods on the program on the system.
+#
+# `Sys` is a singleton class, its only instance is accessible from everywhere with `sys`.
+#
+# Because of this, methods that should be accessible from everywhere, like `print` or `exit`,
+# are defined in `Sys`.
+# Moreover, unless there is an ambiguity with `self`, the receiver of a call to these methods is implicitly `sys`.
+# Basically it means that the two following instructions are equivalent.
+#
+# ~~~nit
+# print "Hello World"
+# sys.print "Hello World"
+# ~~~
+#
+# ## Methods Implicitly Defined in Sys
+#
+# `Sys` is the class where are defined top-level methods,
+# i.e. those defined outside of any class like in a procedural language.
+# Basically it means that
+#
+# ~~~nitish
+# redef class Sys
+#    fun foo do print "hello"
+# end
+# ~~~
+#
+# is equivalent with
+#
+# ~~~nitish
+# fun foo print "hello"
+# ~~~
+#
+# As a corollary, in a top-level method, `self` (the current receiver) is always `sys`.
 class Sys
-       # Instructions outside classes implicitly redefine this method.
+       # The main method of a program.
+       #
+       # In a module, the instructions defined outside any classes or methods
+       # (usually called the *main* of the module) is
+       # an implicit definition of this `main` method.
+       # Basically it means that the following program
+       #
+       # ~~~nit
+       # print "Hello World"
+       # ~~~
+       #
+       # is equivalent with
+       #
+       # ~~~nit
+       # redef class Sys
+       #    redef fun main do
+       #       print "Hello World"
+       #    end
+       # end
+       # ~~~
        fun main do end
 
        # The entry point for the execution of the whole program.
-       # Its job is to call `main` but some modules may want to refine it
+       #
+       # When a program starts, the following implicit sequence of instructions is executed
+       #
+       # ~~~nitish
+       # sys = new Sys
+       # sys.run
+       # ~~~
+       #
+       # Whereas the job of the `run` method is just to execute `main`.
+       #
+       # The only reason of the existence of `run` is to allow modules to refine it
        # and inject specific work before or after the main part.
        fun run do main
 
index 87aeaec..a1946e2 100644 (file)
@@ -1,12 +1,12 @@
-../lib/standard/kernel.nit:29,1--100,3: Error: `kernel#Object` does not specialize `module_0#Object`. Possible duplication of the root class `Object`?
-../lib/standard/kernel.nit:102,1--116,3: Error: `kernel#Sys` does not specialize `module_0#Object`. Possible duplication of the root class `Object`?
-../lib/standard/kernel.nit:129,1--187,3: Error: `kernel#Comparable` does not specialize `module_0#Object`. Possible duplication of the root class `Object`?
-../lib/standard/kernel.nit:189,1--226,3: Error: `kernel#Discrete` does not specialize `module_0#Object`. Possible duplication of the root class `Object`?
-../lib/standard/kernel.nit:228,1--245,3: Error: `kernel#Cloneable` does not specialize `module_0#Object`. Possible duplication of the root class `Object`?
-../lib/standard/kernel.nit:247,1--302,3: Error: `kernel#Numeric` does not specialize `module_0#Object`. Possible duplication of the root class `Object`?
-../lib/standard/kernel.nit:308,1--331,3: Error: `kernel#Bool` does not specialize `module_0#Object`. Possible duplication of the root class `Object`?
-../lib/standard/kernel.nit:333,1--415,3: Error: `kernel#Float` does not specialize `module_0#Object`. Possible duplication of the root class `Object`?
-../lib/standard/kernel.nit:417,1--519,3: Error: `kernel#Byte` does not specialize `module_0#Object`. Possible duplication of the root class `Object`?
-../lib/standard/kernel.nit:521,1--712,3: Error: `kernel#Int` does not specialize `module_0#Object`. Possible duplication of the root class `Object`?
-../lib/standard/kernel.nit:714,1--867,3: Error: `kernel#Char` does not specialize `module_0#Object`. Possible duplication of the root class `Object`?
-../lib/standard/kernel.nit:869,1--876,3: Error: `kernel#Pointer` does not specialize `module_0#Object`. Possible duplication of the root class `Object`?
+../lib/standard/kernel.nit:32,1--225,3: Error: `kernel#Object` does not specialize `module_0#Object`. Possible duplication of the root class `Object`?
+../lib/standard/kernel.nit:227,1--300,3: Error: `kernel#Sys` does not specialize `module_0#Object`. Possible duplication of the root class `Object`?
+../lib/standard/kernel.nit:313,1--371,3: Error: `kernel#Comparable` does not specialize `module_0#Object`. Possible duplication of the root class `Object`?
+../lib/standard/kernel.nit:373,1--410,3: Error: `kernel#Discrete` does not specialize `module_0#Object`. Possible duplication of the root class `Object`?
+../lib/standard/kernel.nit:412,1--429,3: Error: `kernel#Cloneable` does not specialize `module_0#Object`. Possible duplication of the root class `Object`?
+../lib/standard/kernel.nit:431,1--486,3: Error: `kernel#Numeric` does not specialize `module_0#Object`. Possible duplication of the root class `Object`?
+../lib/standard/kernel.nit:492,1--515,3: Error: `kernel#Bool` does not specialize `module_0#Object`. Possible duplication of the root class `Object`?
+../lib/standard/kernel.nit:517,1--599,3: Error: `kernel#Float` does not specialize `module_0#Object`. Possible duplication of the root class `Object`?
+../lib/standard/kernel.nit:601,1--703,3: Error: `kernel#Byte` does not specialize `module_0#Object`. Possible duplication of the root class `Object`?
+../lib/standard/kernel.nit:705,1--896,3: Error: `kernel#Int` does not specialize `module_0#Object`. Possible duplication of the root class `Object`?
+../lib/standard/kernel.nit:898,1--1051,3: Error: `kernel#Char` does not specialize `module_0#Object`. Possible duplication of the root class `Object`?
+../lib/standard/kernel.nit:1053,1--1060,3: Error: `kernel#Pointer` does not specialize `module_0#Object`. Possible duplication of the root class `Object`?
index d93978e..e462629 100644 (file)
@@ -1,4 +1,4 @@
-Runtime error: Cast failed. Expected `OTHER`, got `Float` (../lib/standard/kernel.nit:542)
+Runtime error: Cast failed. Expected `OTHER`, got `Float` (../lib/standard/kernel.nit:726)
 11
 21
 31
index d93978e..e462629 100644 (file)
@@ -1,4 +1,4 @@
-Runtime error: Cast failed. Expected `OTHER`, got `Float` (../lib/standard/kernel.nit:542)
+Runtime error: Cast failed. Expected `OTHER`, got `Float` (../lib/standard/kernel.nit:726)
 11
 21
 31
index d93978e..e462629 100644 (file)
@@ -1,4 +1,4 @@
-Runtime error: Cast failed. Expected `OTHER`, got `Float` (../lib/standard/kernel.nit:542)
+Runtime error: Cast failed. Expected `OTHER`, got `Float` (../lib/standard/kernel.nit:726)
 11
 21
 31