Merge: Activate C warnings in FFI code and revert `NativeString` to `char *`
authorJean Privat <jean@pryen.org>
Wed, 10 Jun 2015 01:47:19 +0000 (21:47 -0400)
committerJean Privat <jean@pryen.org>
Wed, 10 Jun 2015 01:47:19 +0000 (21:47 -0400)
The revert commit is partial, it affects only NativeString and does not touch Char.

Pull-Request: #1451
Reviewed-by: Jean Privat <jean@pryen.org>
Reviewed-by: Lucas Bajolet <r4pass@hotmail.com>

68 files changed:
contrib/benitlux/src/benitlux_daily.nit
contrib/rss_downloader/src/rss_downloader.nit
examples/rosettacode/24_game.nit [new file with mode: 0644]
lib/curl/curl.nit
lib/curl/examples/curl_http.nit
lib/curl/examples/curl_mail.nit [deleted file]
lib/curl/native_curl.nit [moved from lib/curl/curl_c.nit with 67% similarity]
lib/date.nit [new file with mode: 0755]
lib/github/github_curl.nit
lib/java/collections.nit
lib/neo4j/curl_json.nit
lib/neo4j/neo4j.nit
lib/standard/file.nit
src/compiler/abstract_compiler.nit
src/interpreter/naive_interpreter.nit
src/modelize/modelize_property.nit
src/rapid_type_analysis.nit
src/semantize/scope.nit
src/semantize/typing.nit
src/ssa.nit [new file with mode: 0644]
src/vm/compilation.nit [new file with mode: 0644]
src/vm/variables_numbering.nit
src/vm/vm.nit
tests/24_game.inputs [new file with mode: 0644]
tests/base_attr4.nit
tests/base_attr_abstract.nit
tests/base_attr_abstract2.nit
tests/base_attr_abstract3.nit [new file with mode: 0644]
tests/base_attr_abstract4.nit [new file with mode: 0644]
tests/base_attr_annot.nit [new file with mode: 0644]
tests/base_init_setter.nit [new file with mode: 0644]
tests/sav/24_game.res [new file with mode: 0644]
tests/sav/base_attr4.res
tests/sav/base_attr4_alt1.res
tests/sav/base_attr4_alt2.res
tests/sav/base_attr_abstract.res
tests/sav/base_attr_abstract3.res [new file with mode: 0644]
tests/sav/base_attr_abstract4.res [new file with mode: 0644]
tests/sav/base_attr_abstract_alt1.res
tests/sav/base_attr_abstract_alt2.res
tests/sav/base_attr_abstract_alt3.res
tests/sav/base_attr_abstract_alt4.res
tests/sav/base_attr_abstract_alt5.res [new file with mode: 0644]
tests/sav/base_attr_annot.res [new file with mode: 0644]
tests/sav/base_attr_annot_1alt1.res [new file with mode: 0644]
tests/sav/base_attr_annot_1alt1_alt1.res [new file with mode: 0644]
tests/sav/base_attr_annot_1alt1_alt2.res [new file with mode: 0644]
tests/sav/base_attr_annot_1alt1_alt3.res [new file with mode: 0644]
tests/sav/base_attr_annot_1alt1_alt4.res [new file with mode: 0644]
tests/sav/base_attr_annot_1alt1_alt5.res [new file with mode: 0644]
tests/sav/base_attr_annot_1alt1_alt6.res [new file with mode: 0644]
tests/sav/base_attr_annot_1alt1_alt7.res [new file with mode: 0644]
tests/sav/base_attr_annot_alt1.res [new file with mode: 0644]
tests/sav/base_attr_annot_alt2.res [new file with mode: 0644]
tests/sav/base_attr_annot_alt3.res [new file with mode: 0644]
tests/sav/base_attr_annot_alt4.res [new file with mode: 0644]
tests/sav/base_attr_annot_alt5.res [new file with mode: 0644]
tests/sav/base_attr_annot_alt6.res [new file with mode: 0644]
tests/sav/base_attr_annot_alt7.res [new file with mode: 0644]
tests/sav/base_init_setter.res [new file with mode: 0644]
tests/sav/curl_http.res
tests/sav/curl_http_args1.res
tests/sav/curl_http_args2.res
tests/sav/curl_http_args3.res
tests/sav/curl_mail.res [deleted file]
tests/sav/error_class_glob.res
tests/sav/niti/base_attr_annot_alt2.res [new file with mode: 0644]
tests/test_curl.nit

index bb6d1fa..1c1f4d6 100644 (file)
@@ -129,14 +129,11 @@ class Benitlux
        # Fetch the Web page at `url`
        fun download_html_page: String
        do
-               var curl = new Curl
-
-               var request = new CurlHTTPRequest(url, curl)
+               var request = new CurlHTTPRequest(url)
                var response = request.execute
 
                if response isa CurlResponseSuccess then
                        var body = response.body_str
-                       curl.destroy
                        return body
                else if response isa CurlResponseFailed then
                        print "Failed downloading URL '{url}' with: {response.error_msg} ({response.error_code})"
index eacaf79..ed5fc72 100644 (file)
@@ -62,16 +62,12 @@ class Element
        # Download this element to `path`
        fun download_to(path: Text)
        do
-               var curl = new Curl
-
-               var request = new CurlHTTPRequest(link, curl)
+               var request = new CurlHTTPRequest(link)
                var response = request.download_to_file(path.to_s)
 
-               if response isa CurlFileResponseSuccess then
-                       curl.destroy
-               else if response isa CurlResponseFailed then
+               if response isa CurlResponseFailed then
                        sys.stderr.write "Failed downloading URL '{link}' with: {response.error_msg} ({response.error_code})\n"
-               else abort
+               end
        end
 
        # Get an unique identifier for this element, uses `Config::unique_pattern`
@@ -232,16 +228,13 @@ redef class Text
        # Get the content of the RSS feed at `self`
        fun fetch_rss_content: Text
        do
-               var curl = new Curl
-
                if sys.verbose then print "\n# Downloading RSS file from '{self}'"
 
-               var request = new CurlHTTPRequest(to_s, curl)
+               var request = new CurlHTTPRequest(to_s)
                var response = request.execute
 
                if response isa CurlResponseSuccess then
                        var body = response.body_str
-                       curl.destroy
                        if sys.verbose then print "Download successful"
                        return body
                else if response isa CurlResponseFailed then
diff --git a/examples/rosettacode/24_game.nit b/examples/rosettacode/24_game.nit
new file mode 100644 (file)
index 0000000..e6fa12d
--- /dev/null
@@ -0,0 +1,157 @@
+#!/usr/bin/env nit
+#
+# This file is part of NIT ( http://www.nitlanguage.org ).
+# This program is public domain
+
+# Task: 24 game
+# SEE: <http://rosettacode.org/wiki/24_game>
+
+redef class Char
+       fun is_op: Bool do return "-+/*".has(self)
+end
+
+# Get `numbers` and `operands` from string `operation` collect with `gets` in `main` function
+# Fill `numbers` and `operands` array with previous extraction
+fun exportation(operation: String, numbers: Array[Int], operands: Array[Char]) do
+       var previous_char: nullable Char = null
+       var number: nullable Int = null
+       var negative = false
+
+       for i in operation.length.times do
+               var current_char = operation[i]
+               var current_int = current_char.to_i
+
+               if (previous_char == null or previous_char.is_op) and current_char == '-' then
+                       negative = true
+                       continue
+               end
+
+               if current_char.is_digit then
+                       if number == null then
+                               number = current_int
+                       else
+                               number = number * 10 + current_int
+                       end
+               end
+
+               if negative and (current_char.is_op or i == operation.length - 1) then
+                       number = number - number * 2
+                       negative = false
+               end
+
+               if (current_char.is_op or i == operation.length - 1) and number != null then
+                       numbers.add(number)
+                       number = null
+               end
+
+               if not negative and current_char.is_op then
+                       operands.add(current_char)
+               end
+               previous_char = current_char
+       end
+       # Update `numbers` and `operands` array in main function with pointer
+end
+
+# Create random numbers between 1 to 9
+fun random: Array[Int] do
+       return [for i in 4.times do 1 + 9.rand]
+end
+
+# Make mathematical operation with `numbers` and `operands` and add the operation result into `random_numbers`
+fun calculation(random_numbers, numbers: Array[Int], operands: Array[Char]) do
+       var number = 0
+       var temp_numbers = numbers.clone
+
+       while temp_numbers.length > 1 do
+               var operand = operands.shift
+               var a = temp_numbers.shift
+               var b = temp_numbers.shift
+
+               if operand == '+' then number = a + b
+               if operand == '-' then number = a - b
+               if operand == '*' then number = a * b
+               if operand == '/' then number = a / b
+
+               temp_numbers.unshift(number)
+       end
+       if number != 0 then random_numbers.add(number)
+end
+
+# Check if used `numbers` exist in the `random_numbers` created
+fun numbers_exists(random_numbers, numbers: Array[Int]): Bool do
+       for number in numbers do
+               if not random_numbers.count(number) >= numbers.count(number) then return false
+       end
+       return true
+end
+
+# Remove `numbers` when they are used
+fun remove_numbers(random_numbers, numbers: Array[Int]) do
+       for number in numbers do random_numbers.remove(number)
+end
+
+# Check if the mathematical `operation` is valid
+fun check(operation: String): Bool do
+       var previous_char: nullable Char = null
+       var next_char: nullable Char = null
+       var next_1_char: nullable Char = null
+
+       for i in operation.length.times do
+               var current_char = operation[i]
+
+               if i + 1 < operation.length then
+                       next_char = operation[i + 1]
+                       if i + 2 < operation.length then
+                               next_1_char = operation[i + 2]
+                       else
+                               next_1_char = null
+                       end
+               else
+                       next_char = null
+               end
+
+               if not current_char.is_op and not current_char.is_digit then return false
+               if next_char == null and current_char.is_op then return false
+
+               if previous_char == null  then
+                       if next_char == null or next_1_char == null then return false
+                       if current_char == '-' and not next_char.is_digit then return false
+                       if current_char != '-' and not current_char.is_digit then return false
+               else
+                       if next_char != null then
+                               if previous_char.is_digit and current_char.is_op and
+                               not (next_char == '-' and next_1_char != null and
+                               next_1_char.is_digit or next_char.is_digit) then
+                                       return false
+                               end
+                       end
+               end
+               previous_char = current_char
+       end
+       return true
+end
+
+var random_numbers = new Array[Int]
+var operation = ""
+
+random_numbers = random
+while not random_numbers.has(24) and random_numbers.length > 1 do
+       var numbers = new Array[Int]
+       var operands = new Array[Char]
+
+       print "numbers: " + random_numbers.join(", ")
+       operation = gets
+       if check(operation) then
+               exportation(operation, numbers, operands)
+               if numbers_exists(random_numbers, numbers) then
+                       calculation(random_numbers, numbers, operands)
+                       remove_numbers(random_numbers, numbers)
+               else
+                       print "NUMBERS ERROR!"
+               end
+       else
+               print "STRING ERROR!"
+       end
+end
+
+if random_numbers.has(24) then print "CONGRATULATIONS" else print "YOU LOSE"
index dbfc157..b68623b 100644 (file)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# Network functionnalities based on Curl_c module.
+# Curl services: `CurlHTTPRequest` and `CurlMail`
 module curl
 
-import curl_c
+import native_curl
 
-# Top level of Curl
+redef class Sys
+       # Shared Curl library handle
+       #
+       # Usually, you do not have to use this attribute, it instancied by `CurlHTTPRequest` and `CurlMail`.
+       # But in some cases you may want to finalize it to free some small resources.
+       # However, if Curl services are needed once again, this attribute must be manually set.
+       var curl: Curl = new Curl is lazy, writable
+end
+
+# Curl library handle, it is initialized and released with this class
 class Curl
-       protected var prim_curl = new CCurl.easy_init
+       super FinalizableOnce
 
-       init
-       do
-               assert curlInstance:self.prim_curl.is_init else
-                       print "Curl must be instancied to be used"
-               end
-       end
+       private var native = new NativeCurl.easy_init
 
        # Check for correct initialization
-       fun is_ok: Bool do return self.prim_curl.is_init
+       fun is_ok: Bool do return self.native.is_init
 
-       # Release Curl instance
-       fun destroy do self.prim_curl.easy_clean
+       redef fun finalize_once do if is_ok then native.easy_clean
 end
 
 # CURL Request
 class CurlRequest
 
-       var verbose: Bool = false is writable
-       private var curl: nullable Curl = null
+       private var curl: Curl = sys.curl
 
-       # Launch request method
-       fun execute: CurlResponse is abstract
+       # Shall this request be verbose?
+       var verbose: Bool = false is writable
 
        # Intern perform method, lowest level of request launching
        private fun perform: nullable CurlResponseFailed
@@ -53,10 +55,10 @@ class CurlRequest
 
                var err
 
-               err = self.curl.prim_curl.easy_setopt(new CURLOption.verbose, self.verbose)
+               err = self.curl.native.easy_setopt(new CURLOption.verbose, self.verbose)
                if not err.is_ok then return answer_failure(err.to_i, err.to_s)
 
-               err = self.curl.prim_curl.easy_perform
+               err = self.curl.native.easy_perform
                if not err.is_ok then return answer_failure(err.to_i, err.to_s)
 
                return null
@@ -72,26 +74,18 @@ end
 # CURL HTTP Request
 class CurlHTTPRequest
        super CurlRequest
-       super CCurlCallbacks
-       super CurlCallbacksRegisterIntern
+       super NativeCurlCallbacks
 
        var url: String
-       var datas: nullable HeaderMap = null is writable
-       var headers: nullable HeaderMap = null is writable
+       var datas: nullable HeaderMap is writable
+       var headers: nullable HeaderMap is writable
+       var delegate: nullable CurlCallbacks is writable
 
        # Set the user agent for all following HTTP requests
-       fun user_agent=(name: String)
-       do
-               curl.prim_curl.easy_setopt(new CURLOption.user_agent, name)
-       end
-
-       init (url: String, curl: nullable Curl) is old_style_init do
-               self.url = url
-               self.curl = curl
-       end
+       var user_agent: nullable String is writable
 
        # Execute HTTP request with settings configured through attribute
-       redef fun execute
+       fun execute: CurlResponse
        do
                if not self.curl.is_ok then return answer_failure(0, "Curl instance is not correctly initialized")
 
@@ -101,38 +95,46 @@ class CurlHTTPRequest
 
                var err
 
-               err = self.curl.prim_curl.easy_setopt(new CURLOption.follow_location, 1)
+               err = self.curl.native.easy_setopt(new CURLOption.follow_location, 1)
                if not err.is_ok then return answer_failure(err.to_i, err.to_s)
 
-               err = self.curl.prim_curl.easy_setopt(new CURLOption.url, url)
+               err = self.curl.native.easy_setopt(new CURLOption.url, url)
                if not err.is_ok then return answer_failure(err.to_i, err.to_s)
 
+               var user_agent = user_agent
+               if user_agent != null then
+                       err = curl.native.easy_setopt(new CURLOption.user_agent, user_agent)
+                       if not err.is_ok then return answer_failure(err.to_i, err.to_s)
+               end
+
                # Callbacks
-               err = self.curl.prim_curl.register_callback(callback_receiver, new CURLCallbackType.header)
+               err = self.curl.native.register_callback_header(callback_receiver)
                if not err.is_ok then return answer_failure(err.to_i, err.to_s)
 
-               err = self.curl.prim_curl.register_callback(callback_receiver, new CURLCallbackType.body)
+               err = self.curl.native.register_callback_body(callback_receiver)
                if not err.is_ok then return answer_failure(err.to_i, err.to_s)
 
                # HTTP Header
-               if self.headers != null then
-                       var headers_joined = self.headers.join_pairs(": ")
-                       err = self.curl.prim_curl.easy_setopt(new CURLOption.httpheader, headers_joined.to_curlslist)
+               var headers = self.headers
+               if headers != null then
+                       var headers_joined = headers.join_pairs(": ")
+                       err = self.curl.native.easy_setopt(new CURLOption.httpheader, headers_joined.to_curlslist)
                        if not err.is_ok then return answer_failure(err.to_i, err.to_s)
                end
 
                # Datas
-               if self.datas != null then
-                       var postdatas = self.datas.to_url_encoded(self.curl.prim_curl)
-                       err = self.curl.prim_curl.easy_setopt(new CURLOption.postfields, postdatas)
+               var datas = self.datas
+               if datas != null then
+                       var postdatas = datas.to_url_encoded(self.curl)
+                       err = self.curl.native.easy_setopt(new CURLOption.postfields, postdatas)
                        if not err.is_ok then return answer_failure(err.to_i, err.to_s)
                end
 
                var err_resp = perform
                if err_resp != null then return err_resp
 
-               var st_code = self.curl.prim_curl.easy_getinfo_long(new CURLInfoLong.response_code)
-               if not st_code == null then success_response.status_code = st_code.response
+               var st_code = self.curl.native.easy_getinfo_long(new CURLInfoLong.response_code)
+               if not st_code == null then success_response.status_code = st_code
 
                return success_response
        end
@@ -147,16 +149,16 @@ class CurlHTTPRequest
 
                var err
 
-               err = self.curl.prim_curl.easy_setopt(new CURLOption.follow_location, 1)
+               err = self.curl.native.easy_setopt(new CURLOption.follow_location, 1)
                if not err.is_ok then return answer_failure(err.to_i, err.to_s)
 
-               err = self.curl.prim_curl.easy_setopt(new CURLOption.url, url)
+               err = self.curl.native.easy_setopt(new CURLOption.url, url)
                if not err.is_ok then return answer_failure(err.to_i, err.to_s)
 
-               err = self.curl.prim_curl.register_callback(callback_receiver, new CURLCallbackType.header)
+               err = self.curl.native.register_callback_header(callback_receiver)
                if not err.is_ok then return answer_failure(err.to_i, err.to_s)
 
-               err = self.curl.prim_curl.register_callback(callback_receiver, new CURLCallbackType.stream)
+               err = self.curl.native.register_callback_stream(callback_receiver)
                if not err.is_ok then return answer_failure(err.to_i, err.to_s)
 
                var opt_name
@@ -168,71 +170,109 @@ class CurlHTTPRequest
                        return answer_failure(0, "Unable to extract file name, please specify one")
                end
 
-               success_response.i_file = new OFile.open(opt_name.to_cstring)
-               if not success_response.i_file.is_valid then
-                       success_response.i_file.close
+               success_response.file = new FileWriter.open(opt_name)
+               if not success_response.file.is_writable then
                        return answer_failure(0, "Unable to create associated file")
                end
 
                var err_resp = perform
                if err_resp != null then return err_resp
 
-               var st_code = self.curl.prim_curl.easy_getinfo_long(new CURLInfoLong.response_code)
-               if not st_code == null then success_response.status_code = st_code.response
+               var st_code = self.curl.native.easy_getinfo_long(new CURLInfoLong.response_code)
+               if not st_code == null then success_response.status_code = st_code
 
-               var speed = self.curl.prim_curl.easy_getinfo_double(new CURLInfoDouble.speed_download)
-               if not speed == null then success_response.speed_download = speed.response
+               var speed = self.curl.native.easy_getinfo_double(new CURLInfoDouble.speed_download)
+               if not speed == null then success_response.speed_download = speed
 
-               var size = self.curl.prim_curl.easy_getinfo_double(new CURLInfoDouble.size_download)
-               if not size == null then success_response.size_download = size.response
+               var size = self.curl.native.easy_getinfo_double(new CURLInfoDouble.size_download)
+               if not size == null then success_response.size_download = size
 
-               var time = self.curl.prim_curl.easy_getinfo_double(new CURLInfoDouble.total_time)
-               if not time == null then success_response.total_time = time.response
+               var time = self.curl.native.easy_getinfo_double(new CURLInfoDouble.total_time)
+               if not time == null then success_response.total_time = time
 
-               success_response.i_file.close
+               success_response.file.close
 
                return success_response
        end
 end
 
 # CURL Mail Request
-class CurlMailRequest
+#
+# ~~~
+# # Craft mail
+# var mail = new CurlMail("sender@example.org",
+#                            to=["to@example.org"], cc=["bob@example.org"])
+#
+# mail.headers_body["Content-Type:"] = """text/html; charset="UTF-8""""
+# mail.headers_body["Content-Transfer-Encoding:"] = "quoted-printable"
+#
+# mail.body = "<h1>Here you can write HTML stuff.</h1>"
+# mail.subject = "Hello From My Nit Program"
+#
+# # Set mail server
+# var error = mail.set_outgoing_server("smtps://smtp.example.org:465",
+#                                      "user@example.org", "mypassword")
+# if error != null then
+#     print "Mail Server Error: {error}"
+#     exit 0
+# end
+#
+# # Send
+# error = mail.execute
+# if error != null then
+#     print "Transfer Error: {error}"
+#     exit 0
+# end
+# ~~~
+class CurlMail
        super CurlRequest
-       super CCurlCallbacks
-
-       var headers: nullable HeaderMap = null is writable
-       var headers_body: nullable HeaderMap = null is writable
-       var from: nullable String = null is writable
-       var to: nullable Array[String] = null is writable
-       var cc: nullable Array[String] = null is writable
-       var bcc: nullable Array[String] = null is writable
-       var subject: nullable String = "" is writable
-       var body: nullable String = "" is writable
-       private var supported_outgoing_protocol: Array[String] = ["smtp", "smtps"]
-
-       init (curl: nullable Curl) is old_style_init do
-               self.curl = curl
-       end
+       super NativeCurlCallbacks
+
+       # Address of the sender
+       var from: nullable String is writable
+
+       # Main recipients
+       var to: nullable Array[String] is writable
+
+       # Subject line
+       var subject: nullable String is writable
+
+       # Text content
+       var body: nullable String is writable
+
+       # CC recipients
+       var cc: nullable Array[String] is writable
+
+       # BCC recipients (hidden from other recipients)
+       var bcc: nullable Array[String] is writable
 
-       # Helper method to add conventional space while building entire mail
-       private fun add_conventional_space(str: String):String do return "{str}\n" end
+       # HTTP header
+       var headers = new HeaderMap is lazy, writable
+
+       # Content header
+       var headers_body = new HeaderMap is lazy, writable
+
+       # Protocols supported to send mail to a server
+       #
+       # Default value at `["smtp", "smtps"]`
+       var supported_outgoing_protocol: Array[String] = ["smtp", "smtps"]
 
        # Helper method to add pair values to mail content while building it (ex: "To:", "address@mail.com")
-       private fun add_pair_to_content(str: String, att: String, val: nullable String):String
+       private fun add_pair_to_content(str: String, att: String, val: nullable String): String
        do
                if val != null then return "{str}{att}{val}\n"
                return "{str}{att}\n"
        end
 
        # Helper method to add entire list of pairs to mail content
-       private fun add_pairs_to_content(content: String, pairs: HeaderMap):String
+       private fun add_pairs_to_content(content: String, pairs: HeaderMap): String
        do
                for h_key, h_val in pairs do content = add_pair_to_content(content, h_key, h_val)
                return content
        end
 
        # Check for host and protocol availability
-       private fun is_supported_outgoing_protocol(host: String):CURLCode
+       private fun is_supported_outgoing_protocol(host: String): CURLCode
        do
                var host_reach = host.split_with("://")
                if host_reach.length > 1 and supported_outgoing_protocol.has(host_reach[0]) then return once new CURLCode.ok
@@ -250,14 +290,16 @@ class CurlMailRequest
                # Host & Protocol
                err = is_supported_outgoing_protocol(host)
                if not err.is_ok then return answer_failure(err.to_i, err.to_s)
-               err = self.curl.prim_curl.easy_setopt(new CURLOption.url, host)
+
+               err = self.curl.native.easy_setopt(new CURLOption.url, host)
                if not err.is_ok then return answer_failure(err.to_i, err.to_s)
 
                # Credentials
                if not user == null and not pwd == null then
-                       err = self.curl.prim_curl.easy_setopt(new CURLOption.username, user)
+                       err = self.curl.native.easy_setopt(new CURLOption.username, user)
                        if not err.is_ok then return answer_failure(err.to_i, err.to_s)
-                       err = self.curl.prim_curl.easy_setopt(new CURLOption.password, pwd)
+
+                       err = self.curl.native.easy_setopt(new CURLOption.password, pwd)
                        if not err.is_ok then return answer_failure(err.to_i, err.to_s)
                end
 
@@ -265,78 +307,88 @@ class CurlMailRequest
        end
 
        # Execute Mail request with settings configured through attribute
-       redef fun execute
+       fun execute: nullable CurlResponseFailed
        do
                if not self.curl.is_ok then return answer_failure(0, "Curl instance is not correctly initialized")
 
-               var success_response = new CurlMailResponseSuccess
-               var content = ""
+               var lines = new Array[String]
+
                # Headers
-               if self.headers != null then
-                       content = add_pairs_to_content(content, self.headers.as(not null))
+               var headers = self.headers
+               if not headers.is_empty then
+                       for k, v in headers do lines.add "{k}{v}"
                end
 
                # Recipients
-               var g_rec = new Array[String]
-               if self.to != null and self.to.length > 0 then
-                       content = add_pair_to_content(content, "To:", self.to.join(","))
-                       g_rec.append(self.to.as(not null))
+               var all_recipients = new Array[String]
+               var to = self.to
+               if to != null and to.length > 0 then
+                       lines.add "To:{to.join(",")}"
+                       all_recipients.append to
                end
-               if self.cc != null and self.cc.length > 0 then
-                       content = add_pair_to_content(content, "Cc:", self.cc.join(","))
-                       g_rec.append(self.cc.as(not null))
+
+               var cc = self.cc
+               if cc != null and cc.length > 0 then
+                       lines.add "Cc:{cc.join(",")}"
+                       all_recipients.append cc
                end
-               if self.bcc != null and self.bcc.length > 0 then g_rec.append(self.bcc.as(not null))
 
-               if g_rec.length < 1 then return answer_failure(0, "The mail recipients can not be empty")
+               var bcc = self.bcc
+               if bcc != null and bcc.length > 0 then all_recipients.append bcc
 
-               var err
+               if all_recipients.is_empty then return answer_failure(0, "There must be at lease one recipient")
 
-               err = self.curl.prim_curl.easy_setopt(new CURLOption.follow_location, 1)
+               var err = self.curl.native.easy_setopt(new CURLOption.follow_location, 1)
                if not err.is_ok then return answer_failure(err.to_i, err.to_s)
 
-               err = self.curl.prim_curl.easy_setopt(new CURLOption.mail_rcpt, g_rec.to_curlslist)
+               err = self.curl.native.easy_setopt(new CURLOption.mail_rcpt, all_recipients.to_curlslist)
                if not err.is_ok then return answer_failure(err.to_i, err.to_s)
 
                # From
-               if not self.from == null then
-                       content = add_pair_to_content(content, "From:", self.from)
-                       err = self.curl.prim_curl.easy_setopt(new CURLOption.mail_from, self.from.as(not null))
+               var from = self.from
+               if not from == null then
+                       lines.add "From:{from}"
+
+                       err = self.curl.native.easy_setopt(new CURLOption.mail_from, from)
                        if not err.is_ok then return answer_failure(err.to_i, err.to_s)
                end
 
                # Subject
-               content = add_pair_to_content(content, "Subject:", self.subject)
+               var subject = self.subject
+               if subject == null then subject = "" # Default
+               lines.add "Subject: {subject}"
 
                # Headers body
-               if self.headers_body != null then
-                       content = add_pairs_to_content(content, self.headers_body.as(not null))
+               var headers_body = self.headers_body
+               if not headers_body.is_empty then
+                       for k, v in headers_body do lines.add "{k}{v}"
                end
 
                # Body
-               content = add_conventional_space(content)
-               content = add_pair_to_content(content, "", self.body)
-               content = add_conventional_space(content)
-               err = self.curl.prim_curl.register_callback(self, once new CURLCallbackType.read)
+               var body = self.body
+               if body == null then body = "" # Default
+
+               lines.add ""
+               lines.add body
+               lines.add ""
+
+               err = self.curl.native.register_callback_read(self)
                if not err.is_ok then return answer_failure(err.to_i, err.to_s)
-               err = self.curl.prim_curl.register_read_datas_callback(self, content)
+
+               var content = lines.join("\n")
+               err = self.curl.native.register_read_datas_callback(self, content)
                if not err.is_ok then return answer_failure(err.to_i, err.to_s)
 
                var err_resp = perform
                if err_resp != null then return err_resp
 
-               return success_response
+               return null
        end
 end
 
 # Callbacks Interface, allow you to manage in your way the different streams
 interface CurlCallbacks
-       super CCurlCallbacks
-end
-
-# Callbacks attributes
-abstract class CurlCallbacksRegisterIntern
-       var delegate: nullable CurlCallbacks = null is writable
+       super NativeCurlCallbacks
 end
 
 # Abstract Curl request response
@@ -349,6 +401,8 @@ class CurlResponseFailed
 
        var error_code: Int
        var error_msg: String
+
+       redef fun to_s do return "{error_msg} ({error_code})"
 end
 
 # Success Abstract Response Success Class
@@ -382,64 +436,63 @@ class CurlResponseSuccess
        end
 end
 
-# Success Response Class of mail request
-class CurlMailResponseSuccess
-       super CurlResponseSuccessIntern
-end
-
 # Success Response Class of a downloaded File
 class CurlFileResponseSuccess
        super CurlResponseSuccessIntern
 
        var status_code = 0
-       var speed_download = 0
-       var size_download = 0
-       var total_time = 0
-       private var i_file: nullable OFile = null
+       var speed_download = 0.0
+       var size_download = 0.0
+       var total_time = 0.0
+       private var file: nullable FileWriter = null
 
        # Receive bytes stream from request due to stream callback registering
-       redef fun stream_callback(buffer, size, count)
+       redef fun stream_callback(buffer)
        do
-               self.i_file.write(buffer, size, count)
+               file.write buffer
        end
 end
 
-# Pseudo map associating Strings to Strings,
-# each key can have multiple associations
-# and the order of insertion is important.
+# Pseudo map associating `String` to `String` for HTTP exchanges
+#
+# This structure differs from `Map` as each key can have multiple associations
+# and the order of insertion is important to some services.
 class HeaderMap
-       private var arr = new Array[Couple[String, String]]
+       private var array = new Array[Couple[String, String]]
 
-       fun []=(k, v: String) do arr.add(new Couple[String, String](k, v))
+       # Add a `value` associated to `key`
+       fun []=(key, value: String)
+       do
+               array.add new Couple[String, String](key, value)
+       end
 
+       # Get a list of the keys associated to `key`
        fun [](k: String): Array[String]
        do
                var res = new Array[String]
-               for c in arr do if c.first == k then res.add(c.second)
+               for c in array do if c.first == k then res.add c.second
                return res
        end
 
+       # Iterate over all the associations in `self`
        fun iterator: MapIterator[String, String] do return new HeaderMapIterator(self)
 
-       # Convert Self to a single string used to post http fields
-       fun to_url_encoded(curl: CCurl): String
+       # Get `self` as a single string for HTTP POST
+       #
+       # Require: `curl.is_ok`
+       fun to_url_encoded(curl: Curl): String
        do
-               assert curlNotInitialized: curl.is_init else
-                       print "to_url_encoded required a valid instance of CCurl Object."
-               end
-               var str = ""
-               var length = self.length
-               var i = 0
+               assert curl.is_ok
+
+               var lines = new Array[String]
                for k, v in self do
-                       if k.length > 0 then
-                               k = curl.escape(k)
-                               v = curl.escape(v)
-                               str = "{str}{k}={v}"
-                               if i < length-1 then str = "{str}&"
-                       end
-                       i += 1
+                       if k.length == 0 then continue
+
+                       k = curl.native.escape(k)
+                       v = curl.native.escape(v)
+                       lines.add "{k}={v}"
                end
-               return str
+               return lines.join("&")
        end
 
        # Concatenate couple of 'key value' separated by 'sep' in Array
@@ -450,15 +503,18 @@ class HeaderMap
                return col
        end
 
-       fun length: Int do return arr.length
-       fun is_empty: Bool do return arr.is_empty
+       # Number of values in `self`
+       fun length: Int do return array.length
+
+       # Is this map empty?
+       fun is_empty: Bool do return array.is_empty
 end
 
-class HeaderMapIterator
+private class HeaderMapIterator
        super MapIterator[String, String]
 
-       private var iterator: Iterator[Couple[String, String]]
-       init(map: HeaderMap) is old_style_init do self.iterator = map.arr.iterator
+       var map: HeaderMap
+       var iterator: Iterator[Couple[String, String]] = map.array.iterator is lazy
 
        redef fun is_ok do return self.iterator.is_ok
        redef fun next do self.iterator.next
index 948ba38..d19ee96 100644 (file)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# Sample of the Curl module.
+# Example use of the Curl module
 module curl_http
 
 import curl
 
-# Small class to represent an Http Fetcher
+# Custom delegate to receive callbacks from a Curl transfer
 class MyHttpFetcher
        super CurlCallbacks
 
-       var curl: Curl
-       var our_body: String = ""
+       # Body of the downloaded file
+       var fetched_body = ""
 
-       init(curl: Curl) do self.curl = curl
-
-       # Release curl object
-       fun destroy do self.curl.destroy
-
-       # Header callback
        redef fun header_callback(line) do
                # We keep this callback silent for testing purposes
-               #if not line.has_prefix("Date:") then print "Header_callback : {line}"
+               #if not line.has_prefix("Date:") then print "Header_callback: {line}"
        end
 
-       # Body callback
-       redef fun body_callback(line) do self.our_body = "{self.our_body}{line}"
+       redef fun body_callback(line) do self.fetched_body += line
 
-       # Stream callback - Cf : No one is registered
-       redef fun stream_callback(buffer, size, count) do print "Stream_callback : {buffer} - {size} - {count}"
+       redef fun stream_callback(buffer) do print "Stream_callback: {buffer}"
 end
 
+private fun print_usage do print "Usage: curl_http [POST|GET|GET_FILE] url"
 
-# Program
 if args.length < 2 then
-       print "Usage: curl_http <method wished [POST, GET, GET_FILE]> <target url>"
-else
-       var curl = new Curl
-       var url = args[1]
-       var request = new CurlHTTPRequest(url, curl)
+       print_usage
+       exit 1
+end
+
+var url = args[1]
+var request = new CurlHTTPRequest(url)
+request.verbose = false # Set to `true` to debug
 
+if args[0] == "GET" then
        # HTTP Get Request
-       if args[0] == "GET" then
-               request.verbose = false
-               var getResponse = request.execute
-
-               if getResponse isa CurlResponseSuccess then
-                       print "Status code : {getResponse.status_code}"
-                       print "Body : {getResponse.body_str}"
-               else if getResponse isa CurlResponseFailed then
-                       print "Error code : {getResponse.error_code}"
-                       print "Error msg : {getResponse.error_msg}"
-               end
+       var response = request.execute
+
+       if response isa CurlResponseSuccess then
+               print "Status code: {response.status_code}"
+               print "Body: {response.body_str}"
+       else if response isa CurlResponseFailed then
+               print "Error code: {response.error_code}"
+               print "Error msg: {response.error_msg}"
+       end
 
+else if args[0] == "POST" then
        # HTTP Post Request
-       else if args[0] == "POST" then
-               var myHttpFetcher = new MyHttpFetcher(curl)
-               request.delegate = myHttpFetcher
-
-               var postDatas = new HeaderMap
-               postDatas["Bugs Bunny"] = "Daffy Duck"
-               postDatas["Batman"] = "Robin likes special characters @#ùà!è§'(\"é&://,;<>∞~*"
-               postDatas["Batman"] = "Yes you can set multiple identical keys, but APACHE will consider only once, the last one"
-               request.datas = postDatas
-               request.verbose = false
-               var postResponse = request.execute
-
-               print "Our body from the callback : {myHttpFetcher.our_body}"
-
-               if postResponse isa CurlResponseSuccess then
-                       print "*** Answer ***"
-                       print "Status code : {postResponse.status_code}"
-                       print "Body should be empty, because we decided to manage callbacks : {postResponse.body_str.length}"
-               else if postResponse isa CurlResponseFailed then
-                       print "Error code : {postResponse.error_code}"
-                       print "Error msg : {postResponse.error_msg}"
-               end
+       var my_http_fetcher = new MyHttpFetcher
+       request.delegate = my_http_fetcher
+
+       var post_datas = new HeaderMap
+       post_datas["Bugs Bunny"] = "Daffy Duck"
+       post_datas["Batman"] = "Robin likes special characters @#ùà!è§'(\"é&://,;<>∞~*"
+       post_datas["Batman"] = "Yes you can set multiple identical keys, but APACHE will consider only one, the last one"
+       request.datas = post_datas
+       var response = request.execute
+
+       print "Our body from the callback: {my_http_fetcher.fetched_body}"
+
+       if response isa CurlResponseSuccess then
+               print "*** Answer ***"
+               print "Status code: {response.status_code}"
+               print "Body should be empty, because we decided to manage callbacks: {response.body_str.length}"
+       else if response isa CurlResponseFailed then
+               print "Error code: {response.error_code}"
+               print "Error msg: {response.error_msg}"
+       end
 
+else if args[0] == "GET_FILE" then
        # HTTP Get to file Request
-       else if args[0] == "GET_FILE" then
-               var headers = new HeaderMap
-               headers["Accept"] = "Moo"
-               request.headers = headers
-               request.verbose = false
-               var downloadResponse = request.download_to_file(null)
-
-               if downloadResponse isa CurlFileResponseSuccess then
-                       print "*** Answer ***"
-                       print "Status code : {downloadResponse.status_code}"
-                       print "Size downloaded : {downloadResponse.size_download}"
-               else if downloadResponse isa CurlResponseFailed then
-                       print "Error code : {downloadResponse.error_code}"
-                       print "Error msg : {downloadResponse.error_msg}"
-               end
-       # Program logic
-       else
-               print "Usage : Method[POST, GET, GET_FILE]"
+       var headers = new HeaderMap
+       headers["Accept"] = "Moo"
+       request.headers = headers
+       var response = request.download_to_file(null)
+
+       if response isa CurlFileResponseSuccess then
+               print "*** Answer ***"
+               print "Status code: {response.status_code}"
+               print "Size downloaded: {response.size_download}"
+       else if response isa CurlResponseFailed then
+               print "Error code: {response.error_code}"
+               print "Error msg: {response.error_msg}"
        end
+
+else
+       print_usage
+       exit 1
 end
diff --git a/lib/curl/examples/curl_mail.nit b/lib/curl/examples/curl_mail.nit
deleted file mode 100644 (file)
index d791611..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-# This file is part of NIT ( http://www.nitlanguage.org ).
-#
-# Copyright 2013 Matthieu Lucas <lucasmatthieu@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.
-
-# Mail sender sample using the Curl module
-module curl_mail
-
-import curl
-
-var curl = new Curl
-var mail_request = new CurlMailRequest(curl)
-
-# Networks
-var response: nullable CurlResponse = mail_request.set_outgoing_server("smtps://smtp.example.org:465", "user@example.org", "mypassword")
-if response isa CurlResponseFailed then
-       print "Error code : {response.error_code}"
-       print "Error msg : {response.error_msg}"
-end
-
-# Headers
-mail_request.from = "Billy Bob"
-mail_request.to = ["user@example.org"]
-mail_request.cc = ["bob@example.org"]
-mail_request.bcc = null
-
-var headers_body = new HeaderMap
-headers_body["Content-Type:"] = "text/html; charset=\"UTF-8\""
-headers_body["Content-Transfer-Encoding:"] = "quoted-printable"
-mail_request.headers_body = headers_body
-
-# Content
-mail_request.body = "<h1>Here you can write HTML stuff.</h1>"
-mail_request.subject = "Hello From My Nit Program"
-
-# Others
-mail_request.verbose = false
-
-# Send mail
-response = mail_request.execute
-if response isa CurlResponseFailed then
-       print "Error code : {response.error_code}"
-       print "Error msg : {response.error_msg}"
-else if response isa CurlMailResponseSuccess then
-       print "Mail Sent"
-else
-       print "Unknown Curl Response type"
-end
similarity index 67%
rename from lib/curl/curl_c.nit
rename to lib/curl/native_curl.nit
index fe0a446..29ab34d 100644 (file)
 # limitations under the License.
 
 # Binding of C libCurl which allow us to interact with network.
-module curl_c is pkgconfig("libcurl")
+module native_curl is pkgconfig "libcurl"
+
+intrude import standard::file
+import standard
 
 in "C header" `{
        #include <curl/curl.h>
 
-       typedef enum {
-               CURLcallbackTypeHeader,
-               CURLcallbackTypeBody,
-               CURLcallbackTypeStream,
-               CURLcallbackTypeRead,
-       } CURLcallbackType;
-
-       typedef struct {
-               CCurlCallbacks delegate;
-               CURLcallbackType type;
-       } CURLCallbackDatas;
-
        typedef struct {
                char *data;
                int len;
@@ -44,25 +35,6 @@ in "C body" `{
        #include <stdlib.h>
        #include <string.h>
 
-       // Callbacks method for Header, Body, Stream.
-       size_t nit_curl_callback_func(void *buffer, size_t size, size_t count, CURLCallbackDatas *datas){
-               if(datas->type == CURLcallbackTypeHeader){
-                       char *line_c = (char*)buffer;
-                       String line_o = NativeString_to_s_with_copy(line_c);
-                       CCurlCallbacks_header_callback(datas->delegate, line_o);
-               }
-               else if(datas->type == CURLcallbackTypeBody){
-                       char *line_c = (char*)buffer;
-                       String line_o = NativeString_to_s_with_copy(line_c);
-                       CCurlCallbacks_body_callback(datas->delegate, line_o);
-               }
-               else if(datas->type == CURLcallbackTypeStream){
-                       char *line_c = (char*)buffer;
-                       String line_o = NativeString_to_s(line_c);
-                       CCurlCallbacks_stream_callback(datas->delegate, line_o, size, count);
-               }
-               return count;
-       }
        // Callback method to read datas from buffer.
        size_t nit_curl_callback_read_func(void *buffer, size_t size, size_t count, CURLCallbackReadDatas *datas){
                int len = datas->len - datas->pos;
@@ -73,119 +45,155 @@ in "C body" `{
        }
 `}
 
+redef extern class NativeString
+       private fun native_callback_header(size, count: Int, target: NativeCurlCallbacks): Int
+       do
+               target.header_callback to_s_with_length(size*count)
+
+               # FIXME we probably should return a value from the user
+               return count
+       end
+
+       private fun native_callback_body(size, count: Int, target: NativeCurlCallbacks): Int
+       do
+               target.body_callback to_s_with_length(size*count)
+
+               return count
+       end
+
+       private fun native_callback_stream(size, count: Int, target: NativeCurlCallbacks): Int
+       do
+               target.stream_callback to_s_with_length(size*count)
+
+               return count
+       end
+end
+
 # CURL Extern Type, reproduce CURL low level behaviors
-extern class CCurl `{ CURL * `}
+extern class NativeCurl `{ CURL * `}
        # Constructor, CURL low level initializer
        new easy_init `{ return curl_easy_init(); `}
+
        # Check for correct initialization
-       fun is_init:Bool `{ return (self != NULL); `}
+       fun is_init: Bool `{ return (self != NULL); `}
+
        # Easy Clean / Release CURL instance
        fun easy_clean `{ curl_easy_cleanup( self ); `}
+
        # Perform the transfer described by setted options
-       fun easy_perform:CURLCode `{ return curl_easy_perform( self ); `}
-       # Set options to tell CURL how to behave. Obj parameter type can be Int, Bool, String, OFile, CURLSList.
-       fun easy_setopt(opt: CURLOption, obj: Object):CURLCode
+       fun easy_perform: CURLCode `{ return curl_easy_perform( self ); `}
+
+       # Set options to tell CURL how to behave. Obj parameter type can be Int, Bool, String, FileWriter, CURLSList.
+       fun easy_setopt(opt: CURLOption, obj: Object): CURLCode
        do
-               if obj isa Int then return i_setopt_int(opt, obj)
-               if obj isa Bool and obj == true then return i_setopt_int(opt, 1)
-               if obj isa Bool and obj == false then return i_setopt_int(opt, 0)
-               if obj isa String then return i_setopt_string(opt, obj)
-               if obj isa OFile then return i_setopt_file(opt, obj)
-               if obj isa CURLSList then return i_setopt_slist(opt, obj)
+               if obj isa Int then return native_setopt_int(opt, obj)
+               if obj isa Bool and obj == true then return native_setopt_int(opt, 1)
+               if obj isa Bool and obj == false then return native_setopt_int(opt, 0)
+               if obj isa String then return native_setopt_string(opt, obj)
+               if obj isa FileWriter then return native_setopt_file(opt, obj._file.as(not null))
+               if obj isa CURLSList then return native_setopt_slist(opt, obj)
                return once new CURLCode.unknown_option
        end
-       # Internal method to set options to CURL using OFile parameter.
-       private fun i_setopt_file(opt: CURLOption, fl: OFile):CURLCode `{ return curl_easy_setopt( self, opt, fl); `}
+
+       # Internal method to set options to CURL using NativeFile parameter.
+       private fun native_setopt_file(opt: CURLOption, file: NativeFile): CURLCode `{
+               return curl_easy_setopt( self, opt, file);
+       `}
+
        # Internal method to set options to CURL using Int parameter.
-       private fun i_setopt_int(opt: CURLOption, num: Int):CURLCode `{ return curl_easy_setopt( self, opt, num); `}
+       private fun native_setopt_int(opt: CURLOption, num: Int): CURLCode `{ return curl_easy_setopt( self, opt, num); `}
+
        # Internal method to set options to CURL using CURLSList parameter.
-       private fun i_setopt_slist(opt: CURLOption, list: CURLSList):CURLCode `{ return curl_easy_setopt( self, opt, list); `}
+       private fun native_setopt_slist(opt: CURLOption, list: CURLSList): CURLCode `{ return curl_easy_setopt( self, opt, list); `}
+
        # Internal method to set options to CURL using String parameter.
-       private fun i_setopt_string(opt: CURLOption, str: String):CURLCode import String.to_cstring `{
+       private fun native_setopt_string(opt: CURLOption, str: String): CURLCode import String.to_cstring `{
                char *rStr = String_to_cstring(str);
                return curl_easy_setopt( self, opt, rStr);
        `}
+
        # Request Chars internal information from the CURL session
-       fun easy_getinfo_chars(opt: CURLInfoChars):nullable CURLInfoResponseString
+       fun easy_getinfo_chars(opt: CURLInfoChars): nullable String
        do
-                var answ = new CURLInfoResponseString
-                if not i_getinfo_chars(opt, answ).is_ok then return null
-                return answ
+                var answ = new Container[NativeString]("".to_cstring)
+                if not native_getinfo_chars(opt, answ).is_ok then return null
+                if answ.item.address_is_null then return null
+                return answ.item.to_s
        end
+
        # Internal method used to get String object information initially knowns as C Chars type
-       private fun i_getinfo_chars(opt: CURLInfoChars, res: CURLInfoResponseString):CURLCode import CURLInfoResponseString.response=, NativeString.to_s_with_copy `{
-               char *r = NULL;
+       private fun native_getinfo_chars(opt: CURLInfoChars, res: Container[NativeString]): CURLCode
+       import Container[NativeString].item= `{
+               char *r;
                CURLcode c = curl_easy_getinfo( self, opt, &r);
-               if((c == CURLE_OK) && r != NULL){
-                       String ro = NativeString_to_s_with_copy(r);
-                       CURLInfoResponseString_response__assign( res, ro);
-               }
+               if (c == CURLE_OK) Container_of_NativeString_item__assign(res, r);
                return c;
        `}
+
        # Request Long internal information from the CURL session
-       fun easy_getinfo_long(opt: CURLInfoLong):nullable CURLInfoResponseLong
+       fun easy_getinfo_long(opt: CURLInfoLong): nullable Int
        do
-                var answ = new CURLInfoResponseLong
-                if not i_getinfo_long(opt, answ).is_ok then return null
-                return answ
+                var answ = new Container[Int](0)
+                if not native_getinfo_long(opt, answ).is_ok then return null
+                return answ.item
        end
+
        # Internal method used to get Int object information initially knowns as C Long type
-       private fun i_getinfo_long(opt: CURLInfoLong, res: CURLInfoResponseLong):CURLCode import CURLInfoResponseLong.response= `{
-               long *r = NULL;
-               r = malloc(sizeof(long));
-               CURLcode c = curl_easy_getinfo( self, opt, r);
-               if((c == CURLE_OK) && r != NULL) CURLInfoResponseLong_response__assign( res, *r);
-               free(r);
+       private fun native_getinfo_long(opt: CURLInfoLong, res: Container[Int]): CURLCode
+       import Container[Int].item= `{
+               long r;
+               CURLcode c = curl_easy_getinfo( self, opt, &r);
+               if (c == CURLE_OK) Container_of_Int_item__assign(res, r);
                return c;
        `}
+
        # Request Double internal information from the CURL session
-       fun easy_getinfo_double(opt: CURLInfoDouble):nullable CURLInfoResponseDouble
+       fun easy_getinfo_double(opt: CURLInfoDouble): nullable Float
        do
-                var answ = new CURLInfoResponseDouble
-                if not i_getinfo_double(opt, answ).is_ok then return null
-                return answ
+                var answ = new Container[Float](0.0)
+                if not native_getinfo_double(opt, answ).is_ok then return null
+                return answ.item
        end
+
        # Internal method used to get Int object information initially knowns as C Double type
-       private fun i_getinfo_double(opt: CURLInfoDouble, res: CURLInfoResponseDouble):CURLCode import CURLInfoResponseDouble.response= `{
-               double *r = NULL;
-               r = malloc(sizeof(double));
-               CURLcode c = curl_easy_getinfo( self, opt, r);
-               if((c == CURLE_OK) && r != NULL) CURLInfoResponseDouble_response__assign( res, *r);
-               free(r);
+       private fun native_getinfo_double(opt: CURLInfoDouble, res: Container[Float]): CURLCode
+       import Container[Float].item= `{
+               double r;
+               CURLcode c = curl_easy_getinfo(self, opt, &r);
+               if (c == CURLE_OK) Container_of_Float_item__assign(res, r);
                return c;
        `}
+
        # Request SList internal information from the CURL session
-       fun easy_getinfo_slist(opt: CURLInfoSList):nullable CURLInfoResponseArray
+       fun easy_getinfo_slist(opt: CURLInfoSList): nullable Array[String]
        do
-               var answ = new CURLInfoResponseArray
-               if not i_getinfo_slist(opt, answ).is_ok then return null
-               answ.response = answ.prim_response.to_a
-               answ.prim_response.destroy
-               return answ
+               var answ = new Container[CURLSList](new CURLSList)
+               if not native_getinfo_slist(opt, answ).is_ok then return null
+
+               var native = answ.item
+               var nity = native.to_a
+               native.destroy
+               return nity
        end
+
        # Internal method used to get Array[String] object information initially knowns as C SList type
-       private fun i_getinfo_slist(opt: CURLInfoSList, res: CURLInfoResponseArray):CURLCode import CURLInfoResponseArray.prim_response=`{
-               struct curl_slist* csl = NULL;
-               CURLcode ce = curl_easy_getinfo( self, opt, &csl);
-               CURLInfoResponseArray_prim_response__assign(res, csl);
-               return ce;
+       private fun native_getinfo_slist(opt: CURLInfoSList, res: Container[CURLSList]): CURLCode
+       import Container[CURLSList].item= `{
+               struct curl_slist* csl;
+               CURLcode c = curl_easy_getinfo(self, opt, &csl);
+               if (c == CURLE_OK) Container_of_CURLSList_item__assign(res, csl);
+               return c;
        `}
-       # Register delegate to get callbacks about the CURL transfer performed
-       fun register_callback(delegate: CCurlCallbacks, cbtype: CURLCallbackType):CURLCode
-       do
-               if once [new CURLCallbackType.header, new CURLCallbackType.body, new CURLCallbackType.stream, new CURLCallbackType.read].has(cbtype) then
-                       return i_register_callback(delegate, cbtype)
-               end
-               return once new CURLCode.unknown_option
-       end
+
        # Register delegate to read datas from given buffer
-       fun register_read_datas_callback(delegate: CCurlCallbacks, datas: String):CURLCode
+       fun register_read_datas_callback(delegate: NativeCurlCallbacks, datas: String): CURLCode
        do
-               if datas.length > 0 then return i_register_read_datas_callback(delegate, datas, datas.length)
+               if datas.length > 0 then return native_register_read_datas_callback(delegate, datas, datas.length)
                return once new CURLCode.unknown_option
        end
+
        # Internal method used to configure read callback
-       private fun i_register_read_datas_callback(delegate: CCurlCallbacks, datas: String, size: Int):CURLCode import String.to_cstring `{
+       private fun native_register_read_datas_callback(delegate: NativeCurlCallbacks, datas: String, size: Int): CURLCode import String.to_cstring `{
                CURLCallbackReadDatas *d = NULL;
                d = malloc(sizeof(CURLCallbackReadDatas));
                d->data = (char*)String_to_cstring(datas);
@@ -193,34 +201,56 @@ extern class CCurl `{ CURL * `}
                d->pos = 0;
                return curl_easy_setopt( self, CURLOPT_READDATA, d);
        `}
-       # Internal method used to configure callbacks in terms of given type
-       private fun i_register_callback(delegate: CCurlCallbacks, cbtype: CURLCallbackType):CURLCode is extern import CCurlCallbacks.header_callback, CCurlCallbacks.body_callback, CCurlCallbacks.stream_callback, NativeString.to_s_with_copy, NativeString.to_s `{
-               CURLCallbackDatas *d = malloc(sizeof(CURLCallbackDatas));
-               CCurlCallbacks_incr_ref(delegate);
-               d->type = cbtype;
-               d->delegate = delegate;
+
+       # Register `delegate` to get callbacks about the CURL transfer
+       fun register_callback_header(delegate: NativeCurlCallbacks): CURLCode
+       import NativeString.native_callback_header `{
                CURLcode e;
-               switch(cbtype){
-                       case CURLcallbackTypeHeader:
-                               e = curl_easy_setopt( self, CURLOPT_HEADERFUNCTION, (curl_write_callback)&nit_curl_callback_func);
-                               if(e != CURLE_OK) return e;
-                               e = curl_easy_setopt( self, CURLOPT_WRITEHEADER, d);
-                       break;
-                       case CURLcallbackTypeBody:
-                       case CURLcallbackTypeStream:
-                               e = curl_easy_setopt( self, CURLOPT_WRITEFUNCTION, (curl_write_callback)&nit_curl_callback_func);
-                               if(e != CURLE_OK) return e;
-                               e = curl_easy_setopt( self, CURLOPT_WRITEDATA, d);
-                       break;
-                       case CURLcallbackTypeRead:
-                               e = curl_easy_setopt( self, CURLOPT_READFUNCTION, (curl_write_callback)&nit_curl_callback_read_func);
-                       default:
-                       break;
-               }
+               NativeCurlCallbacks_incr_ref(delegate); // FIXME deallocated these when download completes?
+
+               e = curl_easy_setopt(self, CURLOPT_HEADERFUNCTION, (curl_write_callback)&NativeString_native_callback_header);
+               if(e != CURLE_OK) return e;
+
+               e = curl_easy_setopt(self, CURLOPT_WRITEHEADER, delegate);
                return e;
        `}
+
+       # Register `delegate` to get callbacks about the CURL transfer
+       fun register_callback_body(delegate: NativeCurlCallbacks): CURLCode
+       import NativeString.native_callback_body `{
+               CURLcode e;
+               NativeCurlCallbacks_incr_ref(delegate);
+
+               e = curl_easy_setopt(self, CURLOPT_WRITEFUNCTION, (curl_write_callback)&NativeString_native_callback_body);
+               if(e != CURLE_OK) return e;
+
+               e = curl_easy_setopt(self, CURLOPT_WRITEDATA, delegate);
+               return e;
+       `}
+
+       # Register `delegate` to get callbacks about the CURL transfer
+       fun register_callback_stream(delegate: NativeCurlCallbacks): CURLCode
+       import NativeString.native_callback_stream `{
+               CURLcode e;
+               NativeCurlCallbacks_incr_ref(delegate);
+
+               e = curl_easy_setopt(self, CURLOPT_WRITEFUNCTION, (curl_write_callback)&NativeString_native_callback_stream);
+               if(e != CURLE_OK) return e;
+
+               e = curl_easy_setopt(self, CURLOPT_WRITEDATA, delegate);
+               return e;
+       `}
+
+       # Register `delegate` to get callbacks about the CURL transfer
+       fun register_callback_read(delegate: NativeCurlCallbacks): CURLCode
+       import NativeString.native_callback_stream `{
+               NativeCurlCallbacks_incr_ref(delegate);
+
+               return curl_easy_setopt(self, CURLOPT_READFUNCTION, (curl_write_callback)&nit_curl_callback_read_func);
+       `}
+
        # Convert given string to URL encoded string
-       fun escape(url: String):String import String.to_cstring, NativeString.to_s_with_copy `{
+       fun escape(url: String): String import String.to_cstring, NativeString.to_s_with_copy `{
                char *orig_url, *encoded_url = NULL;
                orig_url = String_to_cstring(url);
                encoded_url = curl_easy_escape( self, orig_url, strlen(orig_url));
@@ -230,44 +260,11 @@ extern class CCurl `{ CURL * `}
        `}
 end
 
-# FILE Extern type, reproduce basic FILE I/O
-extern class OFile `{ FILE* `}
-       # Open / Create a file from given name
-       new open(str: NativeString) `{ return fopen(str, "wb"); `}
-       # Check for File validity
-       fun is_valid:Bool `{ return self != NULL; `}
-       # Internal method to write to the current file
-       private fun n_write(buffer: NativeString, size: Int, count: Int):Int `{ return fwrite(buffer, size, count, self); `}
-       # Write datas to the current file
-       fun write(buffer: String, size: Int, count: Int):Int
-       do
-               if is_valid == true then return n_write(buffer.to_cstring, size, count)
-               return 0
-       end
-       # Internal method to close the current file
-       private fun n_close:Int `{ return fclose(self); `}
-       # Close the current file
-       fun close:Bool
-       do
-               if is_valid == true then return n_close == 0
-               return false
-       end
-end
-
 # Interface for internal information callbacks methods
-interface CCurlCallbacks
-       fun header_callback(line: String) is abstract
-       fun body_callback(line: String) is abstract
-       fun stream_callback(buffer: String, size: Int, count: Int) is abstract
-end
-
-# Extern Type to reproduce Enum of available Callback type
-extern class CURLCallbackType `{ CURLcallbackType `}
-       new header `{ return CURLcallbackTypeHeader; `}
-       new body `{ return CURLcallbackTypeBody; `}
-       new stream `{ return CURLcallbackTypeStream; `}
-       new read `{ return CURLcallbackTypeRead; `}
-       fun to_i:Int `{ return self; `}
+interface NativeCurlCallbacks
+       fun header_callback(buffer: String) do end
+       fun body_callback(buffer: String) do end
+       fun stream_callback(buffer: String) do end
 end
 
 # CURL Code binding and helpers
@@ -276,11 +273,12 @@ extern class CURLCode `{ CURLcode `}
        new unsupported_protocol `{ return CURLE_UNSUPPORTED_PROTOCOL; `}
        new ok `{ return CURLE_OK; `}
        new failed_init `{ return CURLE_FAILED_INIT; `}
-       fun code:Int `{ return self; `}
-       fun is_ok:Bool `{ return self == CURLE_OK; `}
-       fun is_valid_protocol:Bool `{ return self == CURLE_UNSUPPORTED_PROTOCOL; `}
-       fun is_valid_init:Bool `{ return self == CURLE_FAILED_INIT; `}
-       fun to_i:Int do return code end
+
+       fun code: Int `{ return self; `}
+       fun is_ok: Bool `{ return self == CURLE_OK; `}
+       fun is_valid_protocol: Bool `{ return self == CURLE_UNSUPPORTED_PROTOCOL; `}
+       fun is_valid_init: Bool `{ return self == CURLE_FAILED_INIT; `}
+       fun to_i: Int do return code end
        redef fun to_s import NativeString.to_s_with_copy `{
                char *c = (char*)curl_easy_strerror(self);
                return NativeString_to_s_with_copy(c);
@@ -291,39 +289,48 @@ end
 extern class CURLSList `{ struct curl_slist * `}
        # Empty constructor which allow us to avoid the use of Nit NULLABLE type
        private new `{ return NULL; `}
+
        # Constructor allow us to get list instancied by appending an element inside.
        new with_str(s: String) import String.to_cstring `{
                struct curl_slist *l = NULL;
                l = curl_slist_append(l, String_to_cstring(s));
                return l;
        `}
+
        # Check for initialization
-       fun is_init:Bool `{ return (self != NULL); `}
+       fun is_init: Bool `{ return (self != NULL); `}
+
        # Append an element in the linked list
        fun append(key: String) import String.to_cstring `{
                 char *k = String_to_cstring(key);
                 curl_slist_append(self, (char*)k);
        `}
+
        # Internal method to check for reachability of current data
-       private fun i_data_reachable(c: CURLSList):Bool `{ return (c != NULL && c->data != NULL); `}
+       private fun native_data_reachable(c: CURLSList): Bool `{ return (c != NULL && c->data != NULL); `}
+
        # Internal method to check for reachability of next element
-       private fun i_next_reachable(c: CURLSList):Bool `{ return (c != NULL && c->next != NULL); `}
+       private fun native_next_reachable(c: CURLSList): Bool `{ return (c != NULL && c->next != NULL); `}
+
        # Internal method to get current data
-       private fun i_data(c: CURLSList):String import NativeString.to_s `{ return NativeString_to_s(c->data); `}
+       private fun native_data(c: CURLSList): String import NativeString.to_s `{ return NativeString_to_s(c->data); `}
+
        # Internal method to get next element
-       private fun i_next(c: CURLSList):CURLSList `{ return c->next; `}
+       private fun native_next(c: CURLSList): CURLSList `{ return c->next; `}
+
        # Convert current low level List to an Array[String] object
-       fun to_a:Array[String]
+       fun to_a: Array[String]
        do
                var r = new Array[String]
                var cursor = self
                loop
-                       if i_data_reachable(cursor) != true then break
-                       r.add(i_data(cursor))
-                       cursor = i_next(cursor)
+                       if native_data_reachable(cursor) != true then break
+                       r.add(native_data(cursor))
+                       cursor = native_next(cursor)
                end
                return r
        end
+
        # Release allocated memory
        fun destroy `{ curl_slist_free_all(self); `}
 end
@@ -345,34 +352,13 @@ redef class Collection[E]
        end
 end
 
-# Array Response type of CCurl.easy_getinfo method
-class CURLInfoResponseArray
-       var response:Array[String] = new Array[String]
-       private var prim_response:CURLSList = new CURLSList
-end
-
-# Long Response type of CCurl.easy_getinfo method
-class CURLInfoResponseLong
-       var response:Int=0
-end
-
-# Double Response type of CCurl.easy_getinfo method
-class CURLInfoResponseDouble
-       var response:Int=0
-end
-
-# String Response type of CCurl:easy_getinfo method
-class CURLInfoResponseString
-       var response:String = ""
-end
-
-# Reproduce Enum of available CURL SList information, used for CCurl.easy_getinfo
+# Reproduce Enum of available CURL SList information, used for NativeCurl.easy_getinfo
 extern class CURLInfoSList `{ CURLINFO `}
        new ssl_engines `{ return CURLINFO_SSL_ENGINES; `}
        new cookielist `{ return CURLINFO_COOKIELIST; `}
 end
 
-# Reproduce Enum of available CURL Long information, used for CCurl.easy_getinfo
+# Reproduce Enum of available CURL Long information, used for NativeCurl.easy_getinfo
 extern class CURLInfoLong `{ CURLINFO `}
        new response_code `{ return CURLINFO_RESPONSE_CODE; `}
        new header_size `{ return CURLINFO_HEADER_SIZE; `}
@@ -394,7 +380,7 @@ extern class CURLInfoLong `{ CURLINFO `}
        new rtsp_cseq_self `{ return CURLINFO_RTSP_CSEQ_RECV; `}
 end
 
-# Reproduce Enum of available CURL Double information, used for CCurl.easy_getinfo
+# Reproduce Enum of available CURL Double information, used for NativeCurl.easy_getinfo
 extern class CURLInfoDouble `{ CURLINFO `}
        new total_time `{ return CURLINFO_TOTAL_TIME; `}
        new namelookup_time `{ return CURLINFO_NAMELOOKUP_TIME; `}
@@ -411,7 +397,7 @@ extern class CURLInfoDouble `{ CURLINFO `}
        new content_length_upload `{ return CURLINFO_CONTENT_LENGTH_UPLOAD; `}
 end
 
-# Reproduce Enum of available CURL Chars information, used for CCurl.easy_getinfo
+# Reproduce Enum of available CURL Chars information, used for NativeCurl.easy_getinfo
 extern class CURLInfoChars `{ CURLINFO `}
        new content_type `{ return CURLINFO_CONTENT_TYPE; `}
        new effective_url `{ return CURLINFO_EFFECTIVE_URL; `}
@@ -462,22 +448,26 @@ extern class CURLStatusCode `{ int `}
        new service_unavailable `{ return 503; `}
        new gateway_timeout `{ return 504; `}
        new http_version_not_supported `{ return 505; `}
-       fun to_i:Int `{ return self; `}
+       fun to_i: Int `{ return self; `}
 end
 
-# Reproduce Enum of CURL Options usable, used for CCurl.easy_setopt
+# Reproduce Enum of CURL Options usable, used for NativeCurl.easy_setopt
 extern class CURLOption `{ CURLoption `}
 
        # Behavior options
 
        # Display verbose information.
        new verbose `{ return CURLOPT_VERBOSE; `}
+
        # Include the header in the body output.
        new header `{ return CURLOPT_HEADER; `}
+
        # Shut off the progress meter.
        new no_progress `{ return CURLOPT_NOPROGRESS; `}
+
        # Do not install signal handlers.
        new     no_signal `{ return CURLOPT_NOSIGNAL; `}
+
        # Transfer multiple files according to a file name pattern.
        new     wild_card_match `{ return CURLOPT_WILDCARDMATCH; `}
 
@@ -485,6 +475,7 @@ extern class CURLOption `{ CURLoption `}
 
        # Callback for writing data.
        new write_function `{ return CURLOPT_WRITEFUNCTION; `}
+
        # Data pointer to pass to the write callback.
        new write_data `{ return CURLOPT_WRITEDATA; `}
 
@@ -576,8 +567,10 @@ extern class CURLOption `{ CURLoption `}
 
        # Accept-Encoding and automatic decompressing data.
        new     accept_encoding `{ return CURLOPT_ACCEPT_ENCODING; `}
+
        # Request Transfer-Encoding.
        new     transfert_encoding `{ return CURLOPT_TRANSFER_ENCODING; `}
+
        # Follow HTTP redirects.
        new follow_location `{ return CURLOPT_FOLLOWLOCATION; `}
 
@@ -587,8 +580,10 @@ extern class CURLOption `{ CURLoption `}
 
        # Issue a HTTP PUT request.
        new put `{ return CURLOPT_PUT; `}
+
        # Issue a HTTP POS request.
        new post `{ return CURLOPT_POST; `}
+
        # Send a POST with this data.
        new postfields `{ return CURLOPT_POSTFIELDS; `}
 
@@ -600,6 +595,7 @@ extern class CURLOption `{ CURLoption `}
 
        # User-Agent: header.
        new user_agent  `{ return CURLOPT_USERAGENT; `}
+
        # Custom HTTP headers.
        new httpheader `{ return CURLOPT_HTTPHEADER; `}
 
@@ -624,6 +620,7 @@ extern class CURLOption `{ CURLoption `}
 
        # Address of the sender.
        new     mail_from `{ return CURLOPT_MAIL_FROM; `}
+
        # Address of the recipients.
        new     mail_rcpt `{ return CURLOPT_MAIL_RCPT; `}
 
@@ -642,6 +639,7 @@ extern class CURLOption `{ CURLoption `}
 
        # List only.
        new dir_list_only `{ return CURLOPT_DIRLISTONLY; `}
+
        # Append to remote file.
        new append `{ return CURLOPT_APPEND; `}
 
diff --git a/lib/date.nit b/lib/date.nit
new file mode 100755 (executable)
index 0000000..19e8ceb
--- /dev/null
@@ -0,0 +1,180 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# 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 manipulate `Date`, `Time` and `DateTime`
+#
+# The services are split in 2 classes:
+#
+# * `Date` handles the year, month and day parts of the date.
+# * `Time` handles the time in hours, minutes and seconds.
+#
+# These are united in `DateTime` for a precise time in a precise day.
+#
+# ~~~
+# var now = new Time.now
+# var midnight = new Time(0, 0, 0)
+# assert now > midnight
+#
+# var nine_thirty = new Time(9, 30, 0)
+# var eleven_twenty = new Time(11, 20, 0)
+# assert eleven_twenty > nine_thirty
+#
+# var pi_day = new Date(2015, 03, 14)
+# var may_the_fourth = new Date(2015, 5, 4)
+# assert pi_day < may_the_fourth
+#
+# var now_t = new DateTime.now
+# var epoch = new DateTime(1970, 1, 1, 0, 0, 0)
+# assert now_t > epoch
+# ~~~
+#
+module date
+
+# A time of the day, composed of an `hour`, a `minute` and a `second` count
+class Time
+       super Comparable
+       redef type OTHER: Time
+
+       # The hour part of this time, between 0 and 23
+       var hour: Int
+
+       # The minute within the hour, between 0 and 59
+       var minute: Int
+
+       # The second within the minute, between 0 and 59
+       var second: Int
+
+       # Get the current time of the day
+       init now do
+               var tm = new Tm.localtime
+               hour = tm.hour
+               minute = tm.min
+               second = tm.sec
+       end
+
+       # Get the difference between two times in second
+       fun diff_time(other: Time): Int do
+               return (hour * 3600 + minute * 60 + second) -
+                       (other.hour * 3600 + other.minute * 60 + other.second)
+       end
+
+       redef fun ==(d) do return d isa Time and time_eq(d)
+
+       redef fun <(d) do return self.diff_time(d) < 0
+
+       redef fun hash do return hour * 1024 + minute * 64 + second
+
+       private fun time_eq(other: Time): Bool
+       do
+               return hour * 3600 + minute * 60 + second ==
+                       other.hour * 3600 + other.minute * 60 + other.second
+       end
+end
+
+# A date, composed by a `year`, a `month` and a `day`
+class Date
+       super Comparable
+       redef type OTHER: Date
+
+       # Year, ex: 1989
+       var year: Int
+
+       # Month as an integer, `1` for January, `2` for February, etc.
+       var month: Int
+
+       # Day of the month
+       var day: Int
+
+       # UTC time zone
+       #
+       # FIXME this value is not yet applied
+       var time_zone = "Z"
+
+       # The date of this day
+       init today do
+               var tm = new Tm.localtime
+               year = 1900 + tm.year
+               month = tm.mon + 1
+               day = tm.mday
+       end
+
+       # `self` formatted according to ISO 8601
+       redef fun to_s do return "{year}-{month}-{day}"
+
+       # Difference in days between `self` and `other`
+       fun diff_days(other: Date): Int
+       do
+               var y_out = year - other.year
+               y_out = y_out * 365
+               var m_out = month - other.month
+               m_out = m_out * 30 # FIXME
+               return day - other.day + m_out + y_out
+       end
+
+       # Difference in months between `self` and `other`
+       fun diff_months(other: Date): Int
+       do
+               var y_out = year - other.year
+               y_out = y_out * 12
+               return month - other.month + y_out
+       end
+
+       # Difference in years between `self` and `other`
+       fun diff_years(other: Date): Int do return year - other.year
+
+       redef fun ==(d) do return d isa Date and self.diff_days(d) == 0
+
+       redef fun hash do return year + month * 1024 + day * 2048
+
+       redef fun <(d) do return self.diff_days(d) < 0
+
+       # Is `self` is between the years of `a` and `b`?
+       private fun is_between_years(a, b: Date): Bool
+       do
+               return (a.year > year and b.year < year) or (b.year > year and a.year < year) or (a.year == year or b.year == year)
+       end
+
+       # Is `self` is between the months of `a` and `b`?
+       private fun is_between_months(a, b: Date) : Bool
+       do
+               if not self.is_between_years(a,b) then return false
+               return (a.month > month and b.month < month) or (b.month > month and a.month < month) or (a.month == month or b.month == month)
+       end
+
+       # Is `self` between `a` and `b`?
+       redef fun is_between(a, b)
+       do
+               if not self.is_between_months(a, b) then return false
+               return (a.day > day and b.day < day) or (b.day > day and a.day < day) or (a.day == day or b.day == day)
+       end
+end
+
+# A `Time` in a `Date`
+class DateTime
+       super Date
+       super Time
+       redef type OTHER: DateTime
+       autoinit year, month, day, hour, minute, second
+
+       # Get the current `DateTime`
+       init now
+       do
+               super
+               today
+       end
+
+       redef fun ==(other) do return other isa DateTime and diff_days(other) == 0 and time_eq(other)
+
+       redef fun to_s do return "{super} {hour}:{minute}:{second}{time_zone}"
+end
index 8e70600..62776e6 100644 (file)
@@ -21,7 +21,6 @@ import json::static
 
 # Specific Curl that know hot to talk to the github API
 class GithubCurl
-       super Curl
 
        # Headers to use on all requests
        var header: HeaderMap is noinit
@@ -42,7 +41,7 @@ class GithubCurl
        # and check for Github errors.
        fun get_and_check(uri: String): nullable Jsonable
        do
-               var request = new CurlHTTPRequest(uri, self)
+               var request = new CurlHTTPRequest(uri)
                request.user_agent = user_agent
                request.headers = header
                var response = request.execute
@@ -73,7 +72,7 @@ class GithubCurl
        # are reported as `GithubError`.
        fun get_and_parse(uri: String): nullable Jsonable
        do
-               var request = new CurlHTTPRequest(uri, self)
+               var request = new CurlHTTPRequest(uri)
                request.user_agent = user_agent
                request.headers = header
                var response = request.execute
index 37f822e..0c24718 100644 (file)
@@ -46,6 +46,48 @@ extern class AbstractJavaArray[E: Object]
        redef fun reverse_iterator do return new JavaArrayReverseIterator[E](self)
 end
 
+# Java primitive array `int[]`
+extern class JavaIntArray in "Java" `{ int[] `}
+       super AbstractJavaArray[Int]
+
+       # Get a new array of the given `size`
+       new (size: Int) in "Java" `{ return new int[(int)size]; `}
+
+       redef fun [](i) in "Java" `{ return self[(int)i]; `}
+
+       redef fun []=(i, e) in "Java" `{ self[(int)i] = (int)e; `}
+
+       redef fun length in "Java" `{ return self.length; `}
+end
+
+# Java primitive array `short[]`
+extern class JavaShortArray in "Java" `{ short[] `}
+       super AbstractJavaArray[Int]
+
+       # Get a new array of the given `size`
+       new (size: Int) in "Java" `{ return new short[(int)size]; `}
+
+       redef fun [](i) in "Java" `{ return (short)self[(int)i]; `}
+
+       redef fun []=(i, e) in "Java" `{ self[(int)i] = (short)e; `}
+
+       redef fun length in "Java" `{ return self.length; `}
+end
+
+# Java primitive array `long[]`
+extern class JavaLongArray in "Java" `{ long[] `}
+       super AbstractJavaArray[Int]
+
+       # Get a new array of the given `size`
+       new (size: Int) in "Java" `{ return new long[(int)size]; `}
+
+       redef fun [](i) in "Java" `{ return self[(int)i]; `}
+
+       redef fun []=(i, e) in "Java" `{ self[(int)i] = (long)e; `}
+
+       redef fun length in "Java" `{ return self.length; `}
+end
+
 # Java primitive array `float[]`
 #
 # Note that Nit `Float` is the size of a double, so storing them in a
@@ -91,13 +133,47 @@ extern class JavaArray in "Java" `{ java.lang.Object[] `}
        redef fun length in "Java" `{ return self.length; `}
 end
 
-# TODO other primitive arrays:
-# * Java primitive array `byte[]`
-# * Java primitive array `short[]`
-# * Java primitive array `int[]`
-# * Java primitive array `long[]`
-# * Java primitive array `boolean[]`
-# * Java primitive array `char[]`
+# Java primitive array `boolean[]`
+extern class JavaBoolArray in "Java" `{ boolean[] `}
+       super AbstractJavaArray[Bool]
+
+       # Get a new array of the given `size`
+       new (size: Int) in "Java" `{ return new boolean[(int)size]; `}
+
+       redef fun [](i) in "Java" `{ return self[(int)i]; `}
+
+       redef fun []=(i, e) in "Java" `{self[(int)i] = (boolean)e; `}
+
+       redef fun length in "Java" `{ return self.length; `}
+end
+
+# Java primitive array `byte[]`
+extern class JavaByteArray in "Java" `{ byte[] `}
+       super AbstractJavaArray[Int]
+
+       # Get a new array of the given `size`
+       new (size: Int) in "Java" `{ return new byte[(int)size]; `}
+
+       redef fun [](i) in "Java" `{ return (byte)self[(int)i]; `}
+
+       redef fun []=(i, e) in "Java" `{ self[(int)i] = (byte)e; `}
+
+       redef fun length in "Java" `{ return self.length; `}
+end
+
+# Java primitive array `char[]`
+extern class JavaCharArray in "Java" `{ char[] `}
+       super AbstractJavaArray[Char]
+
+       # Get a new array of the given `size`
+       new (size: Int) in "Java" `{ return new char[(int)size]; `}
+
+       redef fun [](i) in "Java" `{ return (char)self[(int)i]; `}
+
+       redef fun []=(i, e) in "Java" `{ self[(int)i] = (char)e; `}
+
+       redef fun length in "Java" `{ return self.length; `}
+end
 
 # An `Iterator` on Java primitive arrays
 private class JavaArrayIterator[E: Object]
index e458eb1..17df2fc 100644 (file)
@@ -20,31 +20,11 @@ intrude import curl
 
 # An abstract request that defines most of the standard options for Neo4j REST API
 abstract class JsonCurlRequest
-       super CurlRequest
-       super CCurlCallbacks
-       super CurlCallbacksRegisterIntern
-
-       # REST API service URL
-       var url: String
-
-       init (url: String, curl: nullable Curl) do
-               self.url = url
-               self.curl = curl
-
-               init_headers
-       end
+       super CurlHTTPRequest
 
        # OAuth token
        var auth: nullable String is writable
 
-       # User agent (is used by github to contact devs in case of problems)
-       # Eg. "Awesome-Octocat-App"
-       var user_agent: nullable String is writable
-
-       # HTTP headers to send
-       var headers: nullable HeaderMap = null is writable
-
-
        # init HTTP headers for Neo4j REST API
        protected fun init_headers do
                headers = new HeaderMap
@@ -54,6 +34,8 @@ abstract class JsonCurlRequest
                if auth != null then
                        headers["Authorization"] = "token {auth.to_s}"
                end
+
+               # User agent (is used by github to contact devs in case of problems)
                if user_agent != null then
                        headers["User-Agent"] = user_agent.to_s
                end
@@ -61,6 +43,7 @@ abstract class JsonCurlRequest
 
        redef fun execute do
                init_headers
+
                if not self.curl.is_ok then
                        return answer_failure(0, "Curl instance is not correctly initialized")
                end
@@ -69,28 +52,25 @@ abstract class JsonCurlRequest
                var callback_receiver: CurlCallbacks = success_response
                if self.delegate != null then callback_receiver = self.delegate.as(not null)
 
-               var err
-
-               err = self.curl.prim_curl.easy_setopt(new CURLOption.follow_location, 1)
+               var err = self.curl.native.easy_setopt(new CURLOption.follow_location, 1)
                if not err.is_ok then return answer_failure(err.to_i, err.to_s)
 
-               err = self.curl.prim_curl.easy_setopt(new CURLOption.http_version, 1)
+               err = self.curl.native.easy_setopt(new CURLOption.http_version, 1)
                if not err.is_ok then return answer_failure(err.to_i, err.to_s)
 
-
-               err = self.curl.prim_curl.easy_setopt(new CURLOption.url, url)
+               err = self.curl.native.easy_setopt(new CURLOption.url, url)
                if not err.is_ok then return answer_failure(err.to_i, err.to_s)
 
-               err = self.curl.prim_curl.register_callback(callback_receiver, new CURLCallbackType.header)
+               err = self.curl.native.register_callback_header(callback_receiver)
                if not err.is_ok then return answer_failure(err.to_i, err.to_s)
 
-               err = self.curl.prim_curl.register_callback(callback_receiver, new CURLCallbackType.body)
+               err = self.curl.native.register_callback_body(callback_receiver)
                if not err.is_ok then return answer_failure(err.to_i, err.to_s)
 
                # HTTP Header
                if self.headers != null then
                        var headers_joined = self.headers.join_pairs(": ")
-                       err = self.curl.prim_curl.easy_setopt(
+                       err = self.curl.native.easy_setopt(
                                new CURLOption.httpheader, headers_joined.to_curlslist)
                        if not err.is_ok then return answer_failure(err.to_i, err.to_s)
                end
@@ -101,8 +81,8 @@ abstract class JsonCurlRequest
                var err_resp = perform
                if err_resp != null then return err_resp
 
-               var st_code = self.curl.prim_curl.easy_getinfo_long(new CURLInfoLong.response_code)
-               if not st_code == null then success_response.status_code = st_code.response
+               var st_code = self.curl.native.easy_getinfo_long(new CURLInfoLong.response_code)
+               if not st_code == null then success_response.status_code = st_code
 
                return success_response
        end
@@ -116,7 +96,7 @@ class JsonGET
        super JsonCurlRequest
 
        redef fun execute_hook do
-               var err = self.curl.prim_curl.easy_setopt(new CURLOption.get, true)
+               var err = self.curl.native.easy_setopt(new CURLOption.get, true)
                if not err.is_ok then return answer_failure(err.to_i, err.to_s)
                return null
        end
@@ -134,12 +114,12 @@ class JsonPOST
        end
 
        redef fun execute_hook do
-               var err = self.curl.prim_curl.easy_setopt(new CURLOption.post, true)
+               var err = self.curl.native.easy_setopt(new CURLOption.post, true)
                if not err.is_ok then return answer_failure(err.to_i, err.to_s)
 
                if self.data != null then
                        var postdatas = self.data.to_json
-                       err = self.curl.prim_curl.easy_setopt(new CURLOption.postfields, postdatas)
+                       err = self.curl.native.easy_setopt(new CURLOption.postfields, postdatas)
                        if not err.is_ok then return answer_failure(err.to_i, err.to_s)
                end
                return null
@@ -151,7 +131,7 @@ class JsonDELETE
        super JsonCurlRequest
 
        redef fun execute_hook do
-               var err = self.curl.prim_curl.easy_setopt(new CURLOption.custom_request, "DELETE")
+               var err = self.curl.native.easy_setopt(new CURLOption.custom_request, "DELETE")
                if not err.is_ok then return answer_failure(err.to_i, err.to_s)
                return null
        end
@@ -169,12 +149,12 @@ class JsonPUT
        end
 
        redef fun execute_hook do
-               var err = self.curl.prim_curl.easy_setopt(new CURLOption.custom_request, "PUT")
+               var err = self.curl.native.easy_setopt(new CURLOption.custom_request, "PUT")
                if not err.is_ok then return answer_failure(err.to_i, err.to_s)
 
                if self.data != null then
                        var postdatas = self.data.to_json
-                       err = self.curl.prim_curl.easy_setopt(new CURLOption.postfields, postdatas)
+                       err = self.curl.native.easy_setopt(new CURLOption.postfields, postdatas)
                        if not err.is_ok then return answer_failure(err.to_i, err.to_s)
                end
                return null
index 4694f8d..88c151a 100644 (file)
@@ -320,14 +320,14 @@ class Neo4jClient
 
        # GET JSON data from `url`
        fun get(url: String): Jsonable do
-               var request = new JsonGET(url, curl)
+               var request = new JsonGET(url)
                var response = request.execute
                return parse_response(response)
        end
 
        # POST `params` to `url`
        fun post(url: String, params: Jsonable): Jsonable do
-               var request = new JsonPOST(url, curl)
+               var request = new JsonPOST(url)
                request.data = params
                var response = request.execute
                return parse_response(response)
@@ -335,7 +335,7 @@ class Neo4jClient
 
        # PUT `params` at `url`
        fun put(url: String, params: Jsonable): Jsonable do
-               var request = new JsonPUT(url, curl)
+               var request = new JsonPUT(url)
                request.data = params
                var response = request.execute
                return parse_response(response)
@@ -343,7 +343,7 @@ class Neo4jClient
 
        # DELETE `url`
        fun delete(url: String): Jsonable do
-               var request = new JsonDELETE(url, curl)
+               var request = new JsonDELETE(url)
                var response = request.execute
                return parse_response(response)
        end
@@ -912,7 +912,7 @@ class NeoBatch
 
        # Execute the batch and update local nodes
        fun execute: List[NeoError] do
-               var request = new JsonPOST(client.batch_url, client.curl)
+               var request = new JsonPOST(client.batch_url)
                # request.headers["X-Stream"] = "true"
                var json_jobs = new JsonArray
                for job in jobs.values do json_jobs.add job.to_rest
index 22e2b09..b081e84 100644 (file)
@@ -767,11 +767,12 @@ redef class String
                return res
        end
 
-       # Simplify a file path by remove useless ".", removing "//", and resolving ".."
+       # Simplify a file path by remove useless `.`, removing `//`, and resolving `..`
        #
-       # * ".." are not resolved if they start the path
-       # * starting "/" is not removed
-       # * trailing "/" is removed
+       # * `..` are not resolved if they start the path
+       # * starting `.` is simplified unless the path is empty
+       # * starting `/` is not removed
+       # * trailing `/` is removed
        #
        # Note that the method only work on the string:
        #
@@ -785,17 +786,29 @@ redef class String
        # assert "dir/..".simplify_path            ==  "."
        # assert "//absolute//path/".simplify_path ==  "/absolute/path"
        # assert "//absolute//../".simplify_path   ==  "/"
+       # assert "/".simplify_path                 == "/"
+       # assert "../".simplify_path               == ".."
+       # assert "./".simplify_path                == "."
+       # assert "././././././".simplify_path      == "."
+       # assert "./../dir".simplify_path                  == "../dir"
+       # assert "./dir".simplify_path                     == "dir"
        # ~~~
        fun simplify_path: String
        do
                var a = self.split_with("/")
                var a2 = new Array[String]
                for x in a do
-                       if x == "." then continue
-                       if x == "" and not a2.is_empty then continue
+                       if x == "." and not a2.is_empty then continue # skip `././`
+                       if x == "" and not a2.is_empty then continue # skip `//`
                        if x == ".." and not a2.is_empty and a2.last != ".." then
-                               a2.pop
-                               continue
+                               if a2.last == "." then # do not skip `./../`
+                                       a2.pop # reduce `./../` in `../`
+                               else # reduce `dir/../` in `/`
+                                       a2.pop
+                                       continue
+                               end
+                       else if not a2.is_empty and a2.last == "." then
+                               a2.pop # reduce `./dir` in `dir`
                        end
                        a2.push(x)
                end
index 9d3b0f3..c48aab9 100644 (file)
@@ -2457,7 +2457,7 @@ redef class AAttrPropdef
                        var res
                        if is_lazy then
                                var set
-                               var ret = self.mpropdef.static_mtype
+                               var ret = self.mtype
                                var useiset = not ret.is_c_primitive and not ret isa MNullableType
                                var guard = self.mlazypropdef.mproperty
                                if useiset then
@@ -2485,7 +2485,7 @@ redef class AAttrPropdef
                        assert arguments.length == 2
                        v.write_attribute(self.mpropdef.mproperty, arguments.first, arguments[1])
                        if is_lazy then
-                               var ret = self.mpropdef.static_mtype
+                               var ret = self.mtype
                                var useiset = not ret.is_c_primitive and not ret isa MNullableType
                                if not useiset then
                                        v.write_attribute(self.mlazypropdef.mproperty, arguments.first, v.bool_instance(true))
@@ -2507,11 +2507,11 @@ redef class AAttrPropdef
                var oldnode = v.current_node
                v.current_node = self
                var old_frame = v.frame
-               var frame = new StaticFrame(v, self.mpropdef.as(not null), recv.mcasttype.undecorate.as(MClassType), [recv])
+               var frame = new StaticFrame(v, self.mreadpropdef.as(not null), recv.mcasttype.undecorate.as(MClassType), [recv])
                v.frame = frame
 
                var value
-               var mtype = self.mpropdef.static_mtype
+               var mtype = self.mtype
                assert mtype != null
 
                var nexpr = self.n_expr
index 16e0b48..53f2f41 100644 (file)
@@ -1245,13 +1245,13 @@ redef class AAttrPropdef
        do
                if is_lazy then return
                if has_value then
-                       var f = v.new_frame(self, mpropdef.as(not null), [recv])
+                       var f = v.new_frame(self, mreadpropdef.as(not null), [recv])
                        evaluate_expr(v, recv, f)
                        return
                end
                var mpropdef = self.mpropdef
                if mpropdef == null then return
-               var mtype = mpropdef.static_mtype.as(not null)
+               var mtype = self.mtype.as(not null)
                mtype = mtype.anchor_to(v.mainmodule, recv.mtype.as(MClassType))
                if mtype isa MNullableType then
                        v.write_attribute(self.mpropdef.mproperty, recv, v.null_instance)
index 91c552f..1afce19 100644 (file)
@@ -158,9 +158,6 @@ redef class ModelBuilder
                        return
                end
 
-               # Is the class forbid constructors?
-               if not mclassdef.mclass.kind.need_init then return
-
                # Is there already a constructor defined?
                var defined_init: nullable MMethodDef = null
                for mpropdef in mclassdef.mpropdefs do
@@ -182,18 +179,11 @@ redef class ModelBuilder
                var initializers = new Array[MProperty]
                for npropdef in nclassdef.n_propdefs do
                        if npropdef isa AMethPropdef then
+                               if not npropdef.is_autoinit then continue # Skip non tagged autoinit
                                if npropdef.mpropdef == null then return # Skip broken method
-                               var at = npropdef.get_single_annotation("autoinit", self)
-                               if at == null then continue # Skip non tagged init
-
                                var sig = npropdef.mpropdef.msignature
                                if sig == null then continue # Skip broken method
 
-                               if not npropdef.mpropdef.is_intro then
-                                       self.error(at, "Error: `autoinit` cannot be set on redefinitions.")
-                                       continue
-                               end
-
                                for param in sig.mparameters do
                                        var ret_type = param.mtype
                                        var mparameter = new MParameter(param.name, ret_type, false, ret_type isa MNullableType)
@@ -743,6 +733,8 @@ end
 redef class AMethPropdef
        redef type MPROPDEF: MMethodDef
 
+       # Is the method annotated `autoinit`?
+       var is_autoinit = false
 
        # Can self be used as a root init?
        private fun look_like_a_root_init(modelbuilder: ModelBuilder, mclassdef: MClassDef): Bool
@@ -988,6 +980,17 @@ redef class AMethPropdef
                # Check annotations
                var at = self.get_single_annotation("lazy", modelbuilder)
                if at != null then modelbuilder.error(at, "Syntax Error: `lazy` must be used on attributes.")
+
+               var atautoinit = self.get_single_annotation("autoinit", modelbuilder)
+               if atautoinit != null then
+                       if not mpropdef.is_intro then
+                               modelbuilder.error(atautoinit, "Error: `autoinit` cannot be set on redefinitions.")
+                       else if not mclassdef.is_intro then
+                               modelbuilder.error(atautoinit, "Error: `autoinit` cannot be used in class refinements.")
+                       else
+                               self.is_autoinit = true
+                       end
+               end
        end
 
        redef fun check_signature(modelbuilder)
@@ -1135,6 +1138,10 @@ end
 redef class AAttrPropdef
        redef type MPROPDEF: MAttributeDef
 
+       # The static type of the property (declared, inferred or inherited)
+       # This attribute is also used to check if the property was analyzed and is valid.
+       var mtype: nullable MType
+
        # Is the node tagged `noinit`?
        var noinit = false
 
@@ -1209,8 +1216,7 @@ redef class AAttrPropdef
                                return
                        end
                        if atabstract != null then
-                               modelbuilder.error(atnoinit, "Error: `noautoinit` attributes cannot be abstract.")
-                               return
+                               modelbuilder.warning(atnoinit, "useless-noautoinit", "Warning: superfluous `noautoinit` on abstract attribute.")
                        end
                end
 
@@ -1282,6 +1288,22 @@ redef class AAttrPropdef
                modelbuilder.mpropdef2npropdef[mwritepropdef] = self
                mwritepropdef.mdoc = mreadpropdef.mdoc
                if atabstract != null then mwritepropdef.is_abstract = true
+
+               var atautoinit = self.get_single_annotation("autoinit", modelbuilder)
+               if atautoinit != null then
+                       if has_value then
+                               modelbuilder.error(atautoinit, "Error: `autoinit` attributes cannot have an initial value.")
+                       else if not mwritepropdef.is_intro then
+                               modelbuilder.error(atautoinit, "Error: `autoinit` attributes cannot be set on redefinitions.")
+                       else if not mclassdef.is_intro then
+                               modelbuilder.error(atautoinit, "Error: `autoinit` attributes cannot be used in class refinements.")
+                       else if atabstract == null then
+                               modelbuilder.warning(atautoinit, "useless-autoinit", "Warning: superfluous `autoinit` on attribute.")
+                       end
+               else if atabstract != null then
+                       # By default, abstract attribute are not autoinit
+                       noinit = true
+               end
        end
 
        redef fun build_signature(modelbuilder)
@@ -1359,6 +1381,8 @@ redef class AAttrPropdef
                        return
                end
 
+               self.mtype = mtype
+
                if mpropdef != null then
                        mpropdef.static_mtype = mtype
                end
@@ -1389,7 +1413,7 @@ redef class AAttrPropdef
                var mpropdef = self.mpropdef
                if mpropdef == null then return # Error thus skipped
                var ntype = self.n_type
-               var mtype = self.mpropdef.static_mtype
+               var mtype = self.mtype
                if mtype == null then return # Error thus skipped
 
                var mclassdef = mpropdef.mclassdef
index d81d1c7..9010dde 100644 (file)
@@ -359,7 +359,7 @@ class RapidTypeAnalysis
                        for npropdef in modelbuilder.collect_attr_propdef(cd) do
                                if not npropdef.has_value then continue
 
-                               var mpropdef = npropdef.mpropdef.as(not null)
+                               var mpropdef = npropdef.mreadpropdef.as(not null)
                                var v = new RapidTypeVisitor(self, bound_mtype, mpropdef)
                                v.enter_visit(npropdef.n_expr)
                                v.enter_visit(npropdef.n_block)
index a69c57a..4106660 100644 (file)
@@ -33,13 +33,13 @@ end
 # A local variable (including parameters, automatic variables and self)
 class Variable
        # The name of the variable (as used in the program)
-       var name: String
+       var name: String is writable
 
        # Alias of `name`
        redef fun to_s do return self.name
 
        # The declaration of the variable, if any
-       var location: nullable Location = null
+       var location: nullable Location = null is writable
 
        # Is the local variable not read and need a warning?
        var warn_unread = false is writable
@@ -439,7 +439,7 @@ end
 
 redef class AVarFormExpr
        # The associated variable
-       var variable: nullable Variable
+       var variable: nullable Variable is writable
 end
 
 redef class ACallFormExpr
index 4aad2d2..b37e4a4 100644 (file)
@@ -648,7 +648,7 @@ end
 
 redef class Variable
        # The declared type of the variable
-       var declared_type: nullable MType
+       var declared_type: nullable MType is writable
 
        # Was the variable type-adapted?
        # This is used to speedup type retrieval while it remains `false`
@@ -760,15 +760,15 @@ redef class AAttrPropdef
        do
                if not has_value then return
 
-               var mpropdef = self.mpropdef
-               if mpropdef == null then return # skip error
+               var mpropdef = self.mreadpropdef
+               if mpropdef == null or mpropdef.msignature == null then return # skip error
 
                var v = new TypeVisitor(modelbuilder, mpropdef.mclassdef.mmodule, mpropdef)
                self.selfvariable = v.selfvariable
 
                var nexpr = self.n_expr
                if nexpr != null then
-                       var mtype = self.mpropdef.static_mtype
+                       var mtype = self.mtype
                        v.visit_expr_subtype(nexpr, mtype)
                end
                var nblock = self.n_block
diff --git a/src/ssa.nit b/src/ssa.nit
new file mode 100644 (file)
index 0000000..634dfa3
--- /dev/null
@@ -0,0 +1,1138 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2015 Julien Pagès <julien.pages@lirmm.fr>
+#
+# 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.
+
+# Single-Static Assignment algorithm from an AST
+module ssa
+
+import semantize
+import astbuilder
+
+# Represent a sequence of the program
+# A basic block is composed of several instructions without a jump
+class BasicBlock
+       # First instruction of the basic block
+       var first: ANode is noinit
+
+       # Last instruction of the basic block
+       var last: ANode is noinit
+
+       # Direct successors
+       var successors = new Array[BasicBlock]
+
+       # Direct predecessors
+       var predecessors = new Array[BasicBlock]
+
+       # Parts of AST that contain a read to a variable
+       var read_sites = new Array[AVarFormExpr]
+
+       # Parts of AST that contain a write to a variable
+       var write_sites = new Array[AVarFormExpr]
+
+       # Parts of AST that contain a variable access (read or write)
+       var variables_sites = new Array[AExpr]
+
+       # The iterated dominance frontier of this block
+       # i.e. the set of blocks this block dominate directly or indirectly
+       var dominance_frontier: Array[BasicBlock] = new Array[BasicBlock] is lazy
+
+       # Self is the old block to link to the new,
+       # The two blocks are not linked if the current ends with a `AReturnExpr` or `ABreakExpr`
+       # i.e. self is the predecessor of `successor`
+       # `successor` The successor block
+       fun link(successor: BasicBlock)
+       do
+               # Do not link the two blocks if the current block end with a return, break or continue
+               if last isa AReturnExpr or last isa ABreakExpr or last isa AContinueExpr then return
+
+               successors.add(successor)
+               successor.predecessors.add(self)
+       end
+
+       # Self is the old block to link to the new
+       # i.e. self is the predecessor of `successor`
+       # `successor` The successor block
+       fun link_special(successor: BasicBlock)
+       do
+               # Link the two blocks even if the current block ends with a return or a break
+               successors.add(successor)
+               successor.predecessors.add(self)
+       end
+
+       # Add the `block` to the dominance frontier of this block
+       fun add_df(block: BasicBlock)
+       do
+               dominance_frontier.add(block)
+
+               # Add this block recursively in super-blocks to compute the iterated
+               # dominance frontier
+               for successor in block.successors do
+                       # If this successor has not already been add to the dominance frontier
+                       if not dominance_frontier.has(successor) then
+                               add_df(successor)
+                       end
+               end
+       end
+
+       # Compute recursively the dominance frontier of self block and its successors
+       private fun compute_df
+       do
+               # Treat each block only one time
+               df_computed = true
+
+               for s in successors do
+                       add_df(s)
+
+                       if not s.df_computed then s.compute_df
+               end
+       end
+
+       # Used to handle recursions by treating only one time each block
+       var treated: Bool = false
+
+       # Used to dump the BasicBlock to dot
+       var treated_debug: Bool = false
+
+       # If true, the iterated dominance frontier of this block has been computed
+       var df_computed: Bool = false
+
+       # Indicate the BasicBlock is newly created and needs to be updated
+       var need_update: Bool = false
+
+       # Indicate if the variables renaming step has been made for this block
+       var is_renaming: Bool = false
+
+       # The variables that are accessed in this block
+       var variables = new Array[Variable] is lazy
+
+       # The PhiFunction this block contains at the beginning
+       var phi_functions = new Array[PhiFunction] is lazy
+end
+
+# Contain the currently analyzed propdef
+class SSA
+       # The currently analyzed APropdef
+       var propdef: APropdef
+
+       # The PhiFunction `current_propdef` contains
+       var phi_functions = new Array[PhiFunction]
+
+       # Recursively generate the basic blocks for this propdef
+       fun generate_basic_blocks
+       do
+               propdef.generate_basic_blocks(self)
+       end
+end
+
+redef class Variable
+       # The expressions of AST of this variable depends
+       var dep_exprs = new Array[AExpr]
+
+       # The blocks in which this variable is assigned
+       var assignment_blocks: Array[BasicBlock] = new Array[BasicBlock] is lazy
+
+       # Part of the program where this variable is read
+       var read_blocks: Array[BasicBlock] = new Array[BasicBlock] is lazy
+
+       # The stack of this variable, used for SSA renaming
+       var stack = new Array[Variable] is lazy
+
+       # The original Variable in case of renaming
+       var original_variable: nullable Variable = self
+
+       # If true, this variable is a parameter of a method
+       var parameter: Bool = false
+end
+
+# A PhiFunction is a kind of Variable used in SSA-construction,
+# it is placed at the beginning of a BasicBlock with many incoming blocks
+class PhiFunction
+       super Variable
+
+       # The dependences of this variable for SSA-Algorithm
+       var dependences = new Array[Couple[Variable, BasicBlock]]
+
+       # The position in the AST of the phi-function
+       var block: BasicBlock
+
+       # Set the dependences for the phi-function
+       # *`block` BasicBlock in which we go through the dominance-frontier
+       # *`v` The variable to looking for
+       fun add_dependences(block: BasicBlock, v: Variable)
+       do
+               # Look in which blocks of DF(block) `v` has been assigned
+               for b in block.predecessors do
+                       if v.assignment_blocks.has(b) then
+                               var dep = new Couple[Variable, BasicBlock](v, b)
+                               dependences.add(dep)
+                       end
+               end
+       end
+
+       # Print the PhiFunction with all its dependences
+       redef fun to_s: String
+       do
+               var s = ""
+               s += " dependences = [ "
+               for d in dependences do
+                       s += d.first.to_s + " "
+               end
+               s += "]"
+
+               return s
+       end
+end
+
+redef class APropdef
+       # The variables contained in the body on this propdef
+       var variables: HashSet[Variable] = new HashSet[Variable] is lazy
+
+       # The first basic block of the code
+       var basic_block: nullable BasicBlock
+
+       # If true, the basic blocks where generated
+       var is_generated: Bool = false
+
+       # Generate all basic blocks for this code
+       fun generate_basic_blocks(ssa: SSA) is abstract
+
+       # Contain all AST-parts related to object mechanisms the propdef has:
+       # instantiation, method dispatch, attribute access, subtyping-test
+       var object_sites: Array[AExpr] = new Array[AExpr]
+
+       # Compute the three steps of SSA-algorithm
+       # `ssa` A new instance of SSA class initialized with `self`
+       fun compute_ssa(ssa: SSA)
+       do
+               if is_generated then return
+
+               # The first step is to generate the basic blocks
+               generate_basic_blocks(ssa)
+
+               # The propdef has no body (abstract)
+               if not is_generated then return
+
+               # Once basic blocks were generated, compute SSA algorithm
+               compute_phi(ssa)
+               rename_variables(ssa)
+               ssa_destruction(ssa)
+       end
+
+       # Compute the first phase of SSA algorithm: placing phi-functions
+       fun compute_phi(ssa: SSA)
+       do
+               var root_block = basic_block.as(not null)
+
+               # Compute the iterated dominance frontier of the graph of basic blocks
+               root_block.compute_df
+
+               # Places where a phi-function is added per variable
+               var phi_blocks = new HashMap[Variable, Array[BasicBlock]]
+
+               # For each variables in the propdef
+               for v in variables do
+                       var phi_variables = new Array[BasicBlock]
+
+                       var read_blocks = new Array[BasicBlock]
+                       read_blocks.add_all(v.read_blocks)
+                       read_blocks.add_all(v.assignment_blocks)
+
+                       # While we have not treated each part accessing `v`
+                       while not read_blocks.is_empty do
+                               # Remove a block from the array
+                               var block = read_blocks.shift
+
+                               # For each block in the dominance frontier of `block`
+                               for df in block.dominance_frontier do
+                                       # If we have not yet put a phi-function at the beginning of this block
+                                       if not phi_variables.has(df) then
+                                               phi_variables.add(df)
+
+                                               # Create a new phi-function and set its dependences
+                                               var phi = new PhiFunction("phi", df)
+                                               phi.add_dependences(df, v)
+                                               phi.block = df
+                                               phi.original_variable = phi
+                                               phi.declared_type = v.declared_type
+
+                                               # Indicate this phi-function is assigned in this block
+                                               phi.assignment_blocks.add(block)
+                                               ssa.phi_functions.add(phi)
+
+                                               # Add a phi-function at the beginning of df for variable v
+                                               df.phi_functions.add(phi)
+
+                                               if not v.read_blocks.has(df) or not v.assignment_blocks.has(df) then read_blocks.add(df)
+                                       end
+                               end
+                       end
+
+                       # Add `phi-variables` to the global map
+                       phi_blocks[v] = phi_variables
+               end
+       end
+
+       # Compute the second phase of SSA algorithm: renaming variables
+       # NOTE: `compute_phi` must has been called before
+       fun rename_variables(ssa: SSA)
+       do
+               # A counter for each variable
+               # The key is the variable, the value the number of assignment into the variable
+               var counter = new HashMap[Variable, Int]
+
+               for v in variables do
+                       counter[v] = 0
+                       v.stack.push(v)
+               end
+
+               for phi in ssa.phi_functions do counter[phi] = 0
+
+               # Launch the recursive renaming from the root block
+               rename(basic_block.as(not null), counter, ssa)
+       end
+
+       # Recursively rename each variable from `block`
+       # *`block` The starting basic block
+       # *`counter` The key is the variable, the value the number of assignment into the variable
+       fun rename(block: BasicBlock, counter: HashMap[Variable, Int], ssa: SSA)
+       do
+               if block.is_renaming then return
+
+               block.is_renaming = true
+
+               # For each phi-function of this block
+               for phi in block.phi_functions do
+                       generate_name(phi, counter, block.first, ssa)
+
+                       # Replace the phi into the block
+                       block.phi_functions[block.phi_functions.index_of(phi)] = phi.original_variable.stack.last.as(PhiFunction)
+               end
+
+               # For each variable read in `block`
+               for vread in block.read_sites do
+                       # Replace the old variable in AST
+                       vread.variable = vread.variable.original_variable.stack.last
+               end
+
+               # For each variable write
+               for vwrite in block.write_sites do
+                       generate_name(vwrite.variable.as(not null), counter, vwrite, ssa)
+
+                       var new_version = vwrite.variable.original_variable.stack.last
+
+                       # Set dependence of the new variable
+                       if vwrite isa AVarReassignExpr then
+                               new_version.dep_exprs.add(vwrite.n_value)
+                       else if vwrite isa AVarAssignExpr then
+                               new_version.dep_exprs.add(vwrite.n_value)
+                       end
+
+                       # Replace the old variable by the last created
+                       vwrite.variable = new_version
+               end
+
+               # Rename occurrence of old names in phi-function
+               for successor in block.dominance_frontier do
+                       for sphi in successor.phi_functions do
+                               # Go over the couples in the phi dependences to rename variables
+                               for couple in sphi.dependences do
+                                       if couple.second == block then
+                                               # Rename this variable
+                                               couple.first = couple.first.original_variable.stack.last
+                                       end
+                               end
+                       end
+               end
+
+               # Recurse in successor blocks
+               for successor in block.successors do
+                       rename(successor, counter, ssa)
+               end
+
+               # Pop old names off the stack for each phi-function
+               for phi in block.phi_functions do
+                       if not phi.stack.is_empty then phi.stack.pop
+               end
+       end
+
+       # Generate a new version of the variable `v` and return it
+       # *`v` The variable for which we generate a name
+       # *`counter` The key is the variable, the value the number of assignment into the variable
+       # *`expr` The AST node in which the assignment of v is made
+       # *`ssa` The instance of SSA
+       fun generate_name(v: Variable, counter: HashMap[Variable, Int], expr: ANode, ssa: SSA): Variable
+       do
+               var original_variable = v.original_variable.as(not null)
+
+               var i = counter[original_variable]
+
+               var new_version: Variable
+
+               # Create a new version of Variable
+               if original_variable isa PhiFunction then
+                       var block = original_variable.block
+                       new_version = new PhiFunction(original_variable.name + i.to_s, block)
+                       new_version.dependences.add_all(original_variable.dependences)
+                       ssa.phi_functions.add(new_version)
+               else
+                       new_version = new Variable(original_variable.name + i.to_s)
+                       new_version.declared_type = expr.as(AVarFormExpr).variable.declared_type
+                       variables.add(new_version)
+               end
+
+               # Recopy the fields into the new version
+               new_version.location = expr.location
+               new_version.original_variable = original_variable
+
+               # Push a new version on the stack
+               original_variable.stack.add(new_version)
+               counter[v] = i + 1
+
+               return new_version
+       end
+
+       # Transform SSA-representation into an executable code (delete phi-functions)
+       # `ssa` Current instance of SSA
+       fun ssa_destruction(ssa: SSA)
+       do
+               var builder = new ASTBuilder(mpropdef.mclassdef.mmodule, mpropdef.mclassdef.bound_mtype)
+
+               # Iterate over all phi-functions
+               for phi in ssa.phi_functions do
+                       for dep in phi.dependences do
+                               # dep.second is the block where we need to create a varassign
+                               var var_read = builder.make_var_read(dep.first, dep.first.declared_type.as(not null))
+                               var nvar = builder.make_var_assign(dep.first, var_read)
+
+                               var block = dep.second.last.parent
+
+                               # This variable read must be add to a ABlockExpr
+                               if block isa ABlockExpr then
+                                       block.add(nvar)
+                               end
+
+                               propagate_dependences(phi, phi.block)
+                               ssa.propdef.variables.add(dep.first)
+                       end
+               end
+       end
+
+       # Propagate the dependences of the phi-functions into following variables
+       # `phi` The PhiFunction
+       # `block` Current block where we propagate dependences
+       fun propagate_dependences(phi: PhiFunction, block: BasicBlock)
+       do
+               # Treat each block once
+               if block.treated then return
+
+               # For each variable access site in the block
+               for site in block.variables_sites do
+                       if site isa AVarExpr then
+                               # Propagate the dependences of the phi-function in variables after the phi
+                               for dep in phi.dependences do
+                                       for expr in dep.first.dep_exprs do
+                                               if site.variable.dep_exprs.has(expr) then break
+
+                                               if dep.first.original_variable == site.variable.original_variable then
+                                                       site.variable.dep_exprs.add(expr)
+                                               end
+                                       end
+                               end
+                       else
+                               # The site is a variable write, we stop the propagation
+                               return
+                       end
+               end
+
+               block.treated = true
+
+               # If we do not meet a variable write, continue the propagation
+               for b in block.successors do propagate_dependences(phi, b)
+       end
+end
+
+redef class AAttrPropdef
+       redef fun generate_basic_blocks(ssa: SSA)
+       do
+               basic_block = new BasicBlock
+               basic_block.first = self
+               basic_block.last = self
+
+               # Add the self variable
+               if self.selfvariable != null then variables.add(selfvariable.as(not null))
+
+               # Recursively goes into the nodes
+               if n_block != null then
+                       n_block.generate_basic_blocks(ssa, basic_block.as(not null))
+                       is_generated = true
+               end
+       end
+end
+
+redef class AMethPropdef
+
+       # The return variable of the propdef
+       # Create an empty variable for the return of the method
+       # and treat returns like variable assignments
+       var returnvar: Variable = new Variable("returnvar")
+
+       redef fun generate_basic_blocks(ssa: SSA)
+       do
+               basic_block = new BasicBlock
+               basic_block.first = self
+               basic_block.last = self
+
+               # If the method has a signature
+               if n_signature != null then
+                       for p in n_signature.n_params do
+                               # Add parameters to the local variables
+                               variables.add(p.variable.as(not null))
+                               p.variable.parameter = true
+                       end
+               end
+
+               # Add the return variable
+               variables.add(returnvar)
+
+               # Add the self variable
+               if self.selfvariable != null then variables.add(selfvariable.as(not null))
+
+               # Recursively goes into the nodes
+               if n_block != null then
+                       n_block.generate_basic_blocks(ssa, basic_block.as(not null))
+                       is_generated = true
+               end
+       end
+end
+
+# Utility class for dump basic block and SSA output to dot files
+class BlockDebug
+       # The output file
+       var file: FileWriter
+
+       # Dump all the hierarchy of BasicBlock from `block` to the leaves
+       fun dump(block: BasicBlock)
+       do
+               # Write the basic blocks hierarchy in output file
+               file.write("digraph basic_blocks\n\{\n")
+               var i = 0
+               file.write(print_block(block, i))
+               file.write("\n\}")
+
+               file.close
+       end
+
+       # Print all the block recursively from `block` to the leaves
+       # *`block` The root BasicBlock
+       # *`i` Used for the recursion
+       private fun print_block(block: BasicBlock, i: Int): String
+       do
+               # Precise the type and location of the begin and end of current block
+               var s = "block{block.hash.to_s} [shape=record, label="+"\"\{"
+               s += "block" + block.to_s.escape_to_dot
+               s += "|\{" + block.first.location.file.filename.to_s + block.first.location.line_start.to_s
+               s += " | " + block.first.to_s.escape_to_dot
+
+               # Print phi-functions if any
+               for phi in block.phi_functions do
+                       s += " | " + phi.to_s.escape_to_dot + " "
+               end
+
+               s += "}|\{" + block.last.location.file.filename.to_s + block.last.location.line_start.to_s
+               s += " | " + block.last.to_s.escape_to_dot + "}}\"];"+ "\n"
+
+               i += 1
+               block.treated_debug = true
+
+               for b in block.successors do
+                       # Print edges to successors
+                       s += "block{block.hash.to_s} -> " + " block{b.hash.to_s};\n"
+
+                       # Recursively print child blocks
+                       if not b.treated_debug then s += print_block(b, i)
+               end
+
+               return s
+       end
+end
+
+redef class AExpr
+       # Generate recursively basic block for this expression
+       # *`ssa` An instance of the SSA class initialized with the enclosing `APropdef`
+       # *`old_block` A basic block not completely filled
+       # Return the last created block (the last block can be nested)
+       fun generate_basic_blocks(ssa: SSA, old_block: BasicBlock): BasicBlock
+       do
+               return old_block
+       end
+end
+
+redef class AVarFormExpr
+       # The original variable
+       var original_variable: nullable Variable = variable
+end
+
+redef class AVarExpr
+       redef fun generate_basic_blocks(ssa, old_block)
+       do
+               self.variable.as(not null).read_blocks.add(old_block)
+               old_block.variables.add(self.variable.as(not null))
+
+               self.variable.as(not null).original_variable = self.variable.as(not null)
+               # Save this read site in the block
+               old_block.read_sites.add(self)
+               old_block.variables_sites.add(self)
+
+               return old_block
+       end
+end
+
+redef class AVardeclExpr
+       redef fun generate_basic_blocks(ssa, old_block)
+       do
+               var decl = self.variable.as(not null)
+
+               # Add the corresponding variable to the enclosing mpropdef
+               ssa.propdef.variables.add(decl)
+
+               decl.original_variable = decl
+               decl.assignment_blocks.add(old_block)
+               old_block.variables.add(decl)
+
+               if self.n_expr != null then
+                       self.variable.dep_exprs.add(self.n_expr.as(not null))
+                       old_block = self.n_expr.generate_basic_blocks(ssa, old_block)
+               end
+
+               return old_block
+       end
+end
+
+redef class AVarAssignExpr
+       redef fun generate_basic_blocks(ssa, old_block)
+       do
+               self.variable.as(not null).assignment_blocks.add(old_block)
+               old_block.variables.add(self.variable.as(not null))
+               self.variable.as(not null).original_variable = self.variable.as(not null)
+
+               # Save this write site in the block
+               old_block.write_sites.add(self)
+               old_block.variables_sites.add(self)
+
+               ssa.propdef.variables.add(self.variable.as(not null))
+
+               return self.n_value.generate_basic_blocks(ssa, old_block)
+       end
+end
+
+redef class AVarReassignExpr
+       redef fun generate_basic_blocks(ssa, old_block)
+       do
+               self.variable.as(not null).assignment_blocks.add(old_block)
+               old_block.variables.add(self.variable.as(not null))
+               self.variable.as(not null).original_variable = self.variable.as(not null)
+
+               # Save this write site in the block
+               old_block.write_sites.add(self)
+               old_block.variables_sites.add(self)
+
+               ssa.propdef.variables.add(self.variable.as(not null))
+               return self.n_value.generate_basic_blocks(ssa, old_block)
+       end
+end
+
+redef class ABreakExpr
+       redef fun generate_basic_blocks(ssa, old_block)
+       do
+               # Finish the old block
+               old_block.last = self
+
+               return old_block
+       end
+end
+
+redef class AContinueExpr
+       redef fun generate_basic_blocks(ssa, old_block)
+       do
+               return old_block
+       end
+end
+
+redef class AReturnExpr
+       redef fun generate_basic_blocks(ssa, old_block)
+       do
+               # The return just set the current block and stop the recursion
+               if self.n_expr != null then
+                       old_block = self.n_expr.generate_basic_blocks(ssa, old_block)
+
+                       # Store the return expression in the dependences of the dedicated returnvar
+                       if ssa.propdef isa AMethPropdef then
+                               ssa.propdef.as(AMethPropdef).returnvar.dep_exprs.add(n_expr.as(not null))
+                       end
+               end
+
+               old_block.last = self
+
+               return old_block
+       end
+end
+
+redef class AAssertExpr
+       redef fun generate_basic_blocks(ssa, old_block)
+       do
+               self.n_expr.generate_basic_blocks(ssa, old_block)
+
+               # The condition of the assert is the last expression of the previous block
+               old_block.last = self.n_expr
+
+               # The block if the assert fail
+               var block_false = new BasicBlock
+
+               if self.n_else != null then
+                       block_false.first = self.n_else.as(not null)
+                       block_false.last = self.n_else.as(not null)
+                       self.n_else.generate_basic_blocks(ssa, block_false)
+               else
+                       block_false.first = self
+                       block_false.first = self
+               end
+
+               old_block.link(block_false)
+
+               # The block if the assert is true: the execution continue
+               var block_true = new BasicBlock
+               block_true.first = self
+               block_true.last = self
+
+               old_block.link(block_true)
+
+               return block_true
+       end
+end
+
+redef class AOrExpr
+       redef fun generate_basic_blocks(ssa, old_block)
+       do
+               self.n_expr.generate_basic_blocks(ssa, old_block)
+               return self.n_expr2.generate_basic_blocks(ssa, old_block)
+       end
+end
+
+redef class AImpliesExpr
+       redef fun generate_basic_blocks(ssa, old_block)
+       do
+               self.n_expr.generate_basic_blocks(ssa, old_block)
+               return self.n_expr2.generate_basic_blocks(ssa, old_block)
+       end
+end
+
+redef class AAndExpr
+       redef fun generate_basic_blocks(ssa, old_block)
+       do
+               self.n_expr.generate_basic_blocks(ssa, old_block)
+               return self.n_expr2.generate_basic_blocks(ssa, old_block)
+       end
+end
+
+redef class ANotExpr
+       redef fun generate_basic_blocks(ssa, old_block)
+       do
+               return self.n_expr.generate_basic_blocks(ssa, old_block)
+       end
+end
+
+redef class AOrElseExpr
+       redef fun generate_basic_blocks(ssa, old_block)
+       do
+               self.n_expr.generate_basic_blocks(ssa, old_block)
+               return self.n_expr2.generate_basic_blocks(ssa, old_block)
+       end
+end
+
+redef class AArrayExpr
+       redef fun generate_basic_blocks(ssa, old_block)
+       do
+               for nexpr in self.n_exprs do
+                       old_block = nexpr.generate_basic_blocks(ssa, old_block)
+               end
+
+               return old_block
+       end
+end
+
+redef class ASuperstringExpr
+       redef fun generate_basic_blocks(ssa, old_block)
+       do
+               for nexpr in self.n_exprs do old_block = nexpr.generate_basic_blocks(ssa, old_block)
+
+               return old_block
+       end
+end
+
+redef class ACrangeExpr
+       redef fun generate_basic_blocks(ssa, old_block)
+       do
+               self.n_expr.generate_basic_blocks(ssa, old_block)
+               return self.n_expr2.generate_basic_blocks(ssa, old_block)
+       end
+end
+
+redef class AOrangeExpr
+       redef fun generate_basic_blocks(ssa, old_block)
+       do
+               self.n_expr.generate_basic_blocks(ssa, old_block)
+               return self.n_expr2.generate_basic_blocks(ssa, old_block)
+       end
+end
+
+redef class AIsaExpr
+       redef fun generate_basic_blocks(ssa, old_block)
+       do
+               ssa.propdef.object_sites.add(self)
+
+               return self.n_expr.generate_basic_blocks(ssa, old_block)
+       end
+end
+
+redef class AAsCastExpr
+       redef fun generate_basic_blocks(ssa, old_block)
+       do
+               ssa.propdef.object_sites.add(self)
+
+               return self.n_expr.generate_basic_blocks(ssa, old_block)
+       end
+end
+
+redef class AAsNotnullExpr
+       redef fun generate_basic_blocks(ssa, old_block)
+       do
+               return self.n_expr.generate_basic_blocks(ssa, old_block)
+       end
+end
+
+redef class AParExpr
+       redef fun generate_basic_blocks(ssa, old_block)
+       do
+               return self.n_expr.generate_basic_blocks(ssa, old_block)
+       end
+end
+
+redef class AOnceExpr
+       redef fun generate_basic_blocks(ssa, old_block)
+       do
+               return self.n_expr.generate_basic_blocks(ssa, old_block)
+       end
+end
+
+redef class ASendExpr
+       redef fun generate_basic_blocks(ssa, old_block)
+       do
+               # A call does not finish the current block,
+               # because we create intra-procedural basic blocks here
+
+               ssa.propdef.object_sites.add(self)
+
+               # Recursively goes into arguments to find variables if any
+               for e in self.raw_arguments do e.generate_basic_blocks(ssa, old_block)
+
+               return self.n_expr.generate_basic_blocks(ssa, old_block)
+       end
+end
+
+redef class ASendReassignFormExpr
+       redef fun generate_basic_blocks(ssa, old_block)
+       do
+               self.n_expr.generate_basic_blocks(ssa, old_block)
+
+               ssa.propdef.object_sites.add(self)
+
+               # Recursively goes into arguments to find variables if any
+               for e in self.raw_arguments do e.generate_basic_blocks(ssa, old_block)
+
+               return self.n_value.generate_basic_blocks(ssa, old_block)
+       end
+end
+
+redef class ASuperExpr
+       redef fun generate_basic_blocks(ssa, old_block)
+       do
+               # Recursively goes into arguments to find variables if any
+               for arg in self.n_args.n_exprs do arg.generate_basic_blocks(ssa, old_block)
+
+               return old_block
+       end
+end
+
+redef class ANewExpr
+       redef fun generate_basic_blocks(ssa, old_block)
+       do
+               for e in self.n_args.n_exprs do e.generate_basic_blocks(ssa, old_block)
+
+               ssa.propdef.object_sites.add(self)
+
+               return old_block
+       end
+end
+
+redef class AAttrExpr
+       redef fun generate_basic_blocks(ssa, old_block)
+       do
+               ssa.propdef.object_sites.add(self)
+
+               return self.n_expr.generate_basic_blocks(ssa, old_block)
+       end
+end
+
+redef class AAttrAssignExpr
+       redef fun generate_basic_blocks(ssa, old_block)
+       do
+               ssa.propdef.object_sites.add(self)
+
+               return self.n_expr.generate_basic_blocks(ssa, old_block)
+       end
+end
+
+redef class AAttrReassignExpr
+       redef fun generate_basic_blocks(ssa, old_block)
+       do
+               ssa.propdef.object_sites.add(self)
+
+               return self.n_expr.generate_basic_blocks(ssa, old_block)
+       end
+end
+
+redef class AIssetAttrExpr
+       redef fun generate_basic_blocks(ssa, old_block)
+       do
+               return self.n_expr.generate_basic_blocks(ssa, old_block)
+       end
+end
+
+redef class ABlockExpr
+       # The block needs to know if a new block is created
+       redef fun generate_basic_blocks(ssa, old_block)
+       do
+               var last_block = old_block
+               var current_block: BasicBlock
+
+               # Recursively continue in the body of the block
+               for i in [0..self.n_expr.length[ do
+                       current_block = self.n_expr[i].generate_basic_blocks(ssa, last_block)
+
+                       if current_block.need_update then
+                               if i < (self.n_expr.length-1) then
+                                       # Current_block must be filled
+                                       current_block.first = self.n_expr[i+1]
+                                       current_block.last = self.n_expr[i+1]
+                                       current_block.need_update = false
+                               else
+                                       # Put the current block at the end of the block
+                                       current_block.first = last_block.last
+                                       current_block.last = last_block.last
+                               end
+                       end
+
+                       if not current_block.last isa AEscapeExpr or current_block.last isa AReturnExpr then
+                               # Re-affected the last block
+                               current_block.last = self.n_expr[i]
+                       end
+
+                       last_block = current_block
+               end
+
+               return last_block
+       end
+end
+
+redef class AIfExpr
+       redef fun generate_basic_blocks(ssa, old_block)
+       do
+               # Terminate the previous block
+               old_block.last = self
+
+               # We start two new blocks if the if has two branches
+               var block_then = new BasicBlock
+
+               # Visit the test of the if
+               self.n_expr.generate_basic_blocks(ssa, old_block)
+
+               # Launch the recursion in two successors if they exist
+               if self.n_then != null then
+                       old_block.link(block_then)
+
+                       block_then.first = self.n_then.as(not null)
+                       block_then.last = self.n_then.as(not null)
+                       self.n_then.generate_basic_blocks(ssa, block_then)
+               end
+
+               var block_else = new BasicBlock
+
+               if self.n_else != null then
+                       old_block.link(block_else)
+
+                       block_else.first = self.n_else.as(not null)
+                       block_else.last = self.n_else.as(not null)
+                       self.n_else.generate_basic_blocks(ssa, block_else)
+               end
+
+               # Create a new BasicBlock to represent the two successor
+               # branches of the if
+               var new_block = new BasicBlock
+               new_block.first = self
+               new_block.last = self
+
+               if self.n_then != null then block_then.link(new_block)
+
+               # The new block needs to be filled by the caller
+               new_block.need_update = true
+
+               if block_else.predecessors.length != 0 then block_else.link(new_block)
+
+               return new_block
+       end
+end
+
+redef class AIfexprExpr
+       redef fun generate_basic_blocks(ssa, old_block)
+       do
+               # Terminate the previous block
+               old_block.last = self
+
+               # We start two new blocks if the if has two branches
+               var block_then = new BasicBlock
+
+               # Visit the test of the if
+               self.n_expr.generate_basic_blocks(ssa, old_block)
+
+               # Launch the recursion in two successors if they exist
+               old_block.link(block_then)
+
+               block_then.first = self.n_then
+               block_then.last = self.n_then
+               self.n_then.generate_basic_blocks(ssa, block_then)
+
+               var block_else = new BasicBlock
+
+               old_block.link(block_else)
+
+               block_else.first = self.n_else
+               block_else.last = self.n_else
+               self.n_else.generate_basic_blocks(ssa, block_else)
+
+               # Create a new BasicBlock to represent the two successor
+               # branches of the if
+               var new_block = new BasicBlock
+               new_block.first = self
+               new_block.last = self
+
+               block_then.link(new_block)
+
+               # The new block needs to be filled by the caller
+               new_block.need_update = true
+
+               block_else.link(new_block)
+
+               return new_block
+       end
+end
+
+redef class ADoExpr
+       redef fun generate_basic_blocks(ssa, old_block)
+       do
+               old_block.last = self
+
+               # The beginning of the block is the first instruction
+               var block = new BasicBlock
+               block.first = self.n_block.as(not null)
+               block.last = self.n_block.as(not null)
+
+               old_block.link(block)
+               return self.n_block.generate_basic_blocks(ssa, block)
+       end
+end
+
+redef class AWhileExpr
+       redef fun generate_basic_blocks(ssa, old_block)
+       do
+               old_block.last = self
+
+               # The beginning of the block is the test of the while
+               var block = new BasicBlock
+               block.first = self.n_expr
+               block.last = self.n_block.as(not null)
+
+               old_block.link(block)
+
+               self.n_expr.generate_basic_blocks(ssa, old_block)
+               var inside_block = self.n_block.generate_basic_blocks(ssa, block)
+
+               # Link the inside of the block to the previous block
+               block.link_special(old_block)
+
+               # Create a new Block after the while
+               var new_block = new BasicBlock
+               new_block.need_update = true
+
+               old_block.link_special(new_block)
+
+               return new_block
+       end
+end
+
+redef class ALoopExpr
+       redef fun generate_basic_blocks(ssa, old_block)
+       do
+               old_block.last = self
+
+               # The beginning of the block is the first instruction
+               var block = new BasicBlock
+               block.first = self.n_block.as(not null)
+               block.last = self.n_block.as(not null)
+
+               old_block.link(block)
+               self.n_block.generate_basic_blocks(ssa, block)
+
+               return block
+       end
+end
+
+redef class AForExpr
+       redef fun generate_basic_blocks(ssa, old_block)
+       do
+               old_block.last = self
+
+               # The beginning of the block is the first instruction
+               var block = new BasicBlock
+               block.first = self.n_expr
+               block.last = self.n_block.as(not null)
+
+               # Visit the test of the if
+               self.n_expr.generate_basic_blocks(ssa, block)
+
+               # Collect the variables declared in the for
+               for v in variables do
+                       ssa.propdef.variables.add(v)
+               end
+
+               old_block.link(block)
+
+               block.link(old_block)
+
+               var new_block = new BasicBlock
+               new_block.need_update = true
+
+               return new_block
+       end
+end
diff --git a/src/vm/compilation.nit b/src/vm/compilation.nit
new file mode 100644 (file)
index 0000000..5dca966
--- /dev/null
@@ -0,0 +1,60 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2015 Julien Pagès <julien.pages@lirmm.fr>
+#
+# 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.
+
+# The compilation module of the VirtualMachine
+module compilation
+
+import variables_numbering
+import ssa
+
+redef class VirtualMachine
+
+       # The currently analyzed APropdef
+       var current_propdef: APropdef
+
+       redef fun new_frame(node, mpropdef, args)
+       do
+               # Save the current propdef
+               if node isa APropdef then self.current_propdef = node
+
+               return super
+       end
+end
+
+redef class APropdef
+
+       redef fun compile(vm)
+       do
+               super
+
+               # A new instance of SSA to analyze the self propdef
+               var ssa = new SSA(self)
+
+               # Generate basic_blocks and compute SSA-algorithm for this propdef
+               compute_ssa(ssa)
+       end
+
+       # Redef to add the same position to a new version of a Variable than the original variable
+       redef fun generate_name(v, counter, expr, ssa)
+       do
+               var new_version = super
+
+               # All versions of a variable have the same position in the environment
+               new_version.position = v.original_variable.position
+
+               return new_version
+       end
+end
index 4de0eb4..d01b390 100644 (file)
@@ -39,19 +39,10 @@ redef class VirtualMachine
        do
                var f = new VmFrame(node, mpropdef, args)
 
-               # If this Frame is for a method then number variables into the body of the method
-               if node isa AMethPropdef then
-                       # Number the variables
-                       if not node.is_numbering then node.numbering_variables(self, mpropdef.as(MMethodDef))
-
-                       # Create an empty environment
-                       f.variables = new Array[Instance].filled_with(initialization_value, node.environment_size)
-               end
-
-               # If this Frame is for an attribute with a block then number the block
-               if node isa AAttrPropdef then
-                       # Number the variables
-                       if not node.is_numbering then node.numbering_variables(self)
+               # If this Frame is for a method or an attribute block then number variables into the body of the method
+               if node isa APropdef then
+                       # Compile the code (number its local variables)
+                       if not node.is_compiled then node.compile(self)
 
                        # Create an empty environment
                        f.variables = new Array[Instance].filled_with(initialization_value, node.environment_size)
@@ -77,7 +68,7 @@ end
 
 redef class Variable
        # The position in the environment
-       var position: Int
+       var position: Int is writable
 end
 
 # Implementation of a Frame with numbered variables
@@ -102,18 +93,33 @@ redef class AExpr
 end
 
 redef class APropdef
+       # Indicite if this propdef was compile
+       var is_compiled: Bool = false
+
        # Indicate if the variables numbering has been done
        private var is_numbering: Bool = false
 
        # The size of the environment to create to call this method
        private var environment_size: Int = 0
+
+       # Compile this propdef
+       # *`vm` The running instance of `VirtualMachine`
+       fun compile(vm: VirtualMachine)
+       do
+               # Number the variables
+               if not is_numbering then numbering_variables(vm)
+
+               is_compiled = true
+       end
+
+       # Numbering the variable inside the propdef
+       fun numbering_variables(vm: VirtualMachine) is abstract
 end
 
 redef class AMethPropdef
-       # Assign a position in the environment to each local variable of `mpropdef`
-       # *`v` The current VirtualMachine
-       # *`mpropdef` The method to number
-       private fun numbering_variables(v: VirtualMachine, mpropdef: MMethodDef)
+       # Assign a position in the environment to each local variable
+       # *`vm` The current VirtualMachine
+       redef fun numbering_variables(vm: VirtualMachine)
        do
                # The position in the environment
                var position = 0
@@ -133,7 +139,7 @@ redef class AMethPropdef
 
                # Recursively go into the AST nodes to number all local variables
                if n_block != null then
-                       position = v.numbering(self.n_block, position)
+                       position = vm.numbering(self.n_block, position)
                end
 
                is_numbering = true
@@ -144,9 +150,9 @@ redef class AMethPropdef
 end
 
 redef class AAttrPropdef
-       # Assign a position in the environment to each local variable of `mpropdef`
-       # *`v` The current VirtualMachine
-       private fun numbering_variables(v: VirtualMachine)
+       # Assign a position in the environment to each local variable
+       # *`vm` The current VirtualMachine
+       redef fun numbering_variables(vm: VirtualMachine)
        do
                # The position in the environment
                var position = 0
@@ -159,7 +165,7 @@ redef class AAttrPropdef
 
                # Recursively go into the AST nodes to number all local variables
                if n_block != null then
-                       position = v.numbering(self.n_block, position)
+                       position = vm.numbering(self.n_block, position)
                end
 
                is_numbering = true
index 4027a15..e98d2da 100644 (file)
@@ -20,3 +20,4 @@ module vm
 import virtual_machine
 import vm_optimizations
 import variables_numbering
+import compilation
diff --git a/tests/24_game.inputs b/tests/24_game.inputs
new file mode 100644 (file)
index 0000000..7b80b80
--- /dev/null
@@ -0,0 +1,3 @@
+8/4
+8*2
+16+8
index b8f02dc..1b88711 100644 (file)
@@ -31,9 +31,15 @@ end
 class C
        super B
        redef fun foo: Int do return 100
-       redef fun bar=(i: Int) do i.output
+       redef fun bar=(i: Int) do
+               super
+               i.output
+       end
        redef fun baz: Int do return 400
-       redef fun baz=(i: Int) do i.output
+       redef fun baz=(i: Int) do
+               super
+               i.output
+       end
 end
 
 var a = new A
index 34c1e4c..d4b07a7 100644 (file)
 
 import kernel
 
-interface Foo
+class Foo
        var a: Object is abstract
-       #alt1#var b = 1 is abstract
-       #alt2#var b is abstract, noautoinit
+       var b: Object = 10 is abstract
+       #alt1#var b is abstract, noautoinit
+       #alt1#var c = 1 is abstract, lazy
+       #alt1#var d = 1 is abstract, autoinit
+       #alt1#var e = 1 is abstract, readonly
 end
 
 class Bar
        super Foo
        redef var a
+       redef var b is noinit
 end
 
 class Baz
        super Foo
-       redef fun a do return 100
-       redef fun a=(x) do (101).output
-end
-
-class FooBar
-       super Foo
+       redef fun a do return 100 #alt2#
+       redef fun a=(x) do (101).output #alt3#
+       redef fun b do return 200 #alt4#
+       redef fun b=(x) do (201).output #alt5#
 end
 
 var f: Foo = new Bar(1)
@@ -40,11 +42,21 @@ f.a.output
 f.a = 2
 f.a.output
 
+'\n'.output
+
+f.b.output
+f.b = 20
+f.b.output
+
+'\n'.output
+
 f = new Baz
 f.a.output
 f.a = 3
 f.a.output
 
-f = new FooBar
-#alt3#f.a.output
-#alt4#f.a = 4
+'\n'.output
+
+f.b.output
+f.b = 30
+f.b.output
index 931f334..0a5b8e9 100644 (file)
@@ -16,7 +16,7 @@ import standard::kernel
 
 abstract class A
        var x: Int
-       var y: Int is abstract
+       var y: Int is abstract, autoinit
 end
 
 class B
diff --git a/tests/base_attr_abstract3.nit b/tests/base_attr_abstract3.nit
new file mode 100644 (file)
index 0000000..d67a45f
--- /dev/null
@@ -0,0 +1,76 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# 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.
+
+import standard::kernel
+
+interface A
+       var i: Int is abstract, autoinit
+       fun j: Int is abstract, autoinit
+       fun j=(o: Int) is abstract, autoinit
+end
+
+class B
+       super A
+       var k: Int is abstract, autoinit
+       fun l: Int is abstract, autoinit
+       fun l=(o: Int) is abstract, autoinit
+end
+
+class C
+       super B
+       redef fun i do
+               'i'.output
+               return 1
+       end
+       redef fun i=(o) do
+               'i'.output
+               '='.output
+               o.output
+       end
+       redef fun j do
+               'j'.output
+               return 2
+       end
+       redef fun j=(o) do
+               'j'.output
+               '='.output
+               o.output
+       end
+       redef fun k do
+               'k'.output
+               return 3
+       end
+       redef fun k=(o)
+       do
+               'k'.output
+               '='.output
+               o.output
+       end
+       redef fun l do
+               'l'.output
+               return 4
+       end
+       redef fun l=(o) do
+               'l'.output
+               '='.output
+               o.output
+       end
+end
+
+var c = new C(10,20,30,40)
+'\n'.output
+c.i.output
+c.j.output
+c.k.output
+c.l.output
diff --git a/tests/base_attr_abstract4.nit b/tests/base_attr_abstract4.nit
new file mode 100644 (file)
index 0000000..876b85a
--- /dev/null
@@ -0,0 +1,75 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# 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.
+
+import standard::kernel
+
+interface A
+       var i: Int is abstract
+       fun j: Int is abstract
+       fun j=(o: Int) is abstract
+end
+
+class B
+       super A
+       var k: Int is abstract
+       fun l: Int is abstract
+       fun l=(o: Int) is abstract
+end
+
+class C
+       super B
+       redef fun i do
+               'i'.output
+               return 1
+       end
+       redef fun i=(o) do
+               'i'.output
+               '='.output
+               o.output
+       end
+       redef fun j do
+               'j'.output
+               return 2
+       end
+       redef fun j=(o) do
+               'j'.output
+               '='.output
+               o.output
+       end
+       redef fun k do
+               'k'.output
+               return 3
+       end
+       redef fun k=(o)
+       do
+               'k'.output
+               '='.output
+               o.output
+       end
+       redef fun l do
+               'l'.output
+               return 4
+       end
+       redef fun l=(o) do
+               'l'.output
+               '='.output
+               o.output
+       end
+end
+
+var c = new C
+c.i.output
+c.j.output
+c.k.output
+c.l.output
diff --git a/tests/base_attr_annot.nit b/tests/base_attr_annot.nit
new file mode 100644 (file)
index 0000000..17f7076
--- /dev/null
@@ -0,0 +1,34 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# 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.
+
+import standard::kernel
+
+class A
+       var a: Object is
+               #alt2# noautoinit
+               #alt3# autoinit
+               #alt4# lazy
+               #alt5# readonly
+               #alt6# abstract
+               #alt7# lateinit
+               writable
+       end #1alt1# do return 1
+end
+
+class B
+       super A
+end
+
+var b = new B(1) #alt1,2,4,5,6,7# var b = new B
+b.a.output
diff --git a/tests/base_init_setter.nit b/tests/base_init_setter.nit
new file mode 100644 (file)
index 0000000..52a4c94
--- /dev/null
@@ -0,0 +1,37 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# 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.
+
+import standard::kernel
+
+class A
+       var i: Int = 1
+end
+
+class B
+       super A
+       redef fun i=(v)
+       do
+               super
+               'i'.output
+               v.output
+       end
+end
+
+var a = new A
+a.i.output
+
+'\n'.output
+
+var b = new B
+b.i.output
diff --git a/tests/sav/24_game.res b/tests/sav/24_game.res
new file mode 100644 (file)
index 0000000..bcbdec9
--- /dev/null
@@ -0,0 +1,4 @@
+numbers: 8, 4, 8, 8
+numbers: 8, 8, 2
+numbers: 8, 16
+CONGRATULATIONS
index 635a8c2..3278c31 100644 (file)
@@ -9,6 +9,6 @@
 
 100
 200
-30
+200
 300
 400
index 5d77e90..2fa9ce5 100644 (file)
@@ -1 +1 @@
-alt/base_attr4_alt1.nit:40,3--5: Error: method `foo=` does not exists in `A`.
+alt/base_attr4_alt1.nit:46,3--5: Error: method `foo=` does not exists in `A`.
index 30b0f43..2f0440d 100644 (file)
@@ -1 +1 @@
-alt/base_attr4_alt2.nit:43,3--5: Error: method `bar` does not exists in `A`.
+alt/base_attr4_alt2.nit:49,3--5: Error: method `bar` does not exists in `A`.
index 36f0f1a..fa5258d 100644 (file)
@@ -1,5 +1,3 @@
-1
-2
-100
-101
-100
+base_attr_abstract.nit:19,24--31: Error: `abstract` attributes cannot have an initial value.
+base_attr_abstract.nit:37,12--13: Error: no property `Baz::b=` is inherited. Remove the `redef` keyword to define a new property.
+base_attr_abstract.nit:37,15: Error: untyped parameter `x'.
diff --git a/tests/sav/base_attr_abstract3.res b/tests/sav/base_attr_abstract3.res
new file mode 100644 (file)
index 0000000..d328d13
--- /dev/null
@@ -0,0 +1,9 @@
+i=10
+jj=20
+k=30
+ll=40
+
+i1
+j2
+k3
+l4
diff --git a/tests/sav/base_attr_abstract4.res b/tests/sav/base_attr_abstract4.res
new file mode 100644 (file)
index 0000000..4d4bee4
--- /dev/null
@@ -0,0 +1,4 @@
+i1
+j2
+k3
+l4
index 4b97e69..e3a1ef5 100644 (file)
@@ -1 +1,7 @@
-alt/base_attr_abstract_alt1.nit:19,15--22: Error: `abstract` attributes cannot have an initial value.
+alt/base_attr_abstract_alt1.nit:19,24--31: Error: `abstract` attributes cannot have an initial value.
+alt/base_attr_abstract_alt1.nit:20,6: Error: a property `b` is already defined in class `Foo` at line 19.
+alt/base_attr_abstract_alt1.nit:21,15--22: Error: `abstract` attributes cannot have an initial value.
+alt/base_attr_abstract_alt1.nit:22,15--22: Error: `abstract` attributes cannot have an initial value.
+alt/base_attr_abstract_alt1.nit:23,15--22: Error: `abstract` attributes cannot have an initial value.
+alt/base_attr_abstract_alt1.nit:37,12--13: Error: no property `Baz::b=` is inherited. Remove the `redef` keyword to define a new property.
+alt/base_attr_abstract_alt1.nit:37,15: Error: untyped parameter `x'.
index af3a672..f79bebd 100644 (file)
@@ -1,2 +1,3 @@
-alt/base_attr_abstract_alt2.nit:20,6: Error: untyped attribute `base_attr_abstract_alt2#Foo#b`.
-alt/base_attr_abstract_alt2.nit:20,21--30: Error: `noautoinit` attributes cannot be abstract.
+alt/base_attr_abstract_alt2.nit:19,24--31: Error: `abstract` attributes cannot have an initial value.
+alt/base_attr_abstract_alt2.nit:37,12--13: Error: no property `Baz::b=` is inherited. Remove the `redef` keyword to define a new property.
+alt/base_attr_abstract_alt2.nit:37,15: Error: untyped parameter `x'.
index 4052598..b112e42 100644 (file)
@@ -1,6 +1,3 @@
-Runtime error: Abstract method `a` called on `FooBar` (alt/base_attr_abstract_alt3.nit:18)
-1
-2
-100
-101
-100
+alt/base_attr_abstract_alt3.nit:19,24--31: Error: `abstract` attributes cannot have an initial value.
+alt/base_attr_abstract_alt3.nit:37,12--13: Error: no property `Baz::b=` is inherited. Remove the `redef` keyword to define a new property.
+alt/base_attr_abstract_alt3.nit:37,15: Error: untyped parameter `x'.
index 09d65f9..0d349af 100644 (file)
@@ -1,6 +1,3 @@
-Runtime error: Abstract method `a=` called on `FooBar` (alt/base_attr_abstract_alt4.nit:18)
-1
-2
-100
-101
-100
+alt/base_attr_abstract_alt4.nit:19,24--31: Error: `abstract` attributes cannot have an initial value.
+alt/base_attr_abstract_alt4.nit:37,12--13: Error: no property `Baz::b=` is inherited. Remove the `redef` keyword to define a new property.
+alt/base_attr_abstract_alt4.nit:37,15: Error: untyped parameter `x'.
diff --git a/tests/sav/base_attr_abstract_alt5.res b/tests/sav/base_attr_abstract_alt5.res
new file mode 100644 (file)
index 0000000..431493f
--- /dev/null
@@ -0,0 +1 @@
+alt/base_attr_abstract_alt5.nit:19,24--31: Error: `abstract` attributes cannot have an initial value.
diff --git a/tests/sav/base_attr_annot.res b/tests/sav/base_attr_annot.res
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/tests/sav/base_attr_annot_1alt1.res b/tests/sav/base_attr_annot_1alt1.res
new file mode 100644 (file)
index 0000000..4cd5256
--- /dev/null
@@ -0,0 +1 @@
+alt/base_attr_annot_1alt1.nit:33,9--11: Error: expected 0 argument(s) for `init`; got 1. See introduction at `standard::Object::init`.
diff --git a/tests/sav/base_attr_annot_1alt1_alt1.res b/tests/sav/base_attr_annot_1alt1_alt1.res
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/tests/sav/base_attr_annot_1alt1_alt2.res b/tests/sav/base_attr_annot_1alt1_alt2.res
new file mode 100644 (file)
index 0000000..225f15c
--- /dev/null
@@ -0,0 +1 @@
+alt/base_attr_annot_1alt1_alt2.nit:19,3--12: Error: `noautoinit` attributes cannot have an initial value.
diff --git a/tests/sav/base_attr_annot_1alt1_alt3.res b/tests/sav/base_attr_annot_1alt1_alt3.res
new file mode 100644 (file)
index 0000000..dac6bc0
--- /dev/null
@@ -0,0 +1 @@
+alt/base_attr_annot_1alt1_alt3.nit:19,3--20,10: Error: `autoinit` attributes cannot have an initial value.
diff --git a/tests/sav/base_attr_annot_1alt1_alt4.res b/tests/sav/base_attr_annot_1alt1_alt4.res
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/tests/sav/base_attr_annot_1alt1_alt5.res b/tests/sav/base_attr_annot_1alt1_alt5.res
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/tests/sav/base_attr_annot_1alt1_alt6.res b/tests/sav/base_attr_annot_1alt1_alt6.res
new file mode 100644 (file)
index 0000000..0bd4036
--- /dev/null
@@ -0,0 +1 @@
+alt/base_attr_annot_1alt1_alt6.nit:19,3--23,10: Error: `abstract` attributes cannot have an initial value.
diff --git a/tests/sav/base_attr_annot_1alt1_alt7.res b/tests/sav/base_attr_annot_1alt1_alt7.res
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/tests/sav/base_attr_annot_alt1.res b/tests/sav/base_attr_annot_alt1.res
new file mode 100644 (file)
index 0000000..0b649c6
--- /dev/null
@@ -0,0 +1 @@
+alt/base_attr_annot_alt1.nit:33,9--11: Error: expected 1 argument(s) for `init(a: Object)`; got 0. See introduction at `standard::Object::init`.
diff --git a/tests/sav/base_attr_annot_alt2.res b/tests/sav/base_attr_annot_alt2.res
new file mode 100644 (file)
index 0000000..1211ed7
--- /dev/null
@@ -0,0 +1 @@
+Runtime error: Uninitialized attribute _a (alt/base_attr_annot_alt2.nit:18)
diff --git a/tests/sav/base_attr_annot_alt3.res b/tests/sav/base_attr_annot_alt3.res
new file mode 100644 (file)
index 0000000..fdf9917
--- /dev/null
@@ -0,0 +1,2 @@
+alt/base_attr_annot_alt3.nit:19,3--20,10: Warning: superfluous `autoinit` on attribute.
+1
diff --git a/tests/sav/base_attr_annot_alt4.res b/tests/sav/base_attr_annot_alt4.res
new file mode 100644 (file)
index 0000000..c1a929e
--- /dev/null
@@ -0,0 +1 @@
+alt/base_attr_annot_alt4.nit:19,3--21,6: Error: `lazy` attributes need a value.
diff --git a/tests/sav/base_attr_annot_alt5.res b/tests/sav/base_attr_annot_alt5.res
new file mode 100644 (file)
index 0000000..21b6b60
--- /dev/null
@@ -0,0 +1 @@
+alt/base_attr_annot_alt5.nit:19,3--22,10: Error: `readonly` attributes need a value.
diff --git a/tests/sav/base_attr_annot_alt6.res b/tests/sav/base_attr_annot_alt6.res
new file mode 100644 (file)
index 0000000..a594cce
--- /dev/null
@@ -0,0 +1 @@
+Runtime error: Abstract method `a` called on `B` (alt/base_attr_annot_alt6.nit:18)
diff --git a/tests/sav/base_attr_annot_alt7.res b/tests/sav/base_attr_annot_alt7.res
new file mode 100644 (file)
index 0000000..75208d1
--- /dev/null
@@ -0,0 +1 @@
+alt/base_attr_annot_alt7.nit:19,3--24,10: Error: `lateinit` attributes need a value.
diff --git a/tests/sav/base_init_setter.res b/tests/sav/base_init_setter.res
new file mode 100644 (file)
index 0000000..a594e14
--- /dev/null
@@ -0,0 +1,3 @@
+1
+
+1
index e4d9464..5118616 100644 (file)
@@ -1 +1 @@
-Usage: curl_http <method wished [POST, GET, GET_FILE]> <target url>
+Usage: curl_http [POST|GET|GET_FILE] url
index c47c136..587f274 100644 (file)
@@ -1,5 +1,5 @@
-Status code : 200
-Body : <!doctype html>
+Status code: 200
+Body: <!doctype html>
 <html>
 <head>
     <title>Example Domain</title>
index a7b3f76..7fa85c5 100644 (file)
@@ -1,4 +1,4 @@
-Our body from the callback : <!doctype html>
+Our body from the callback: <!doctype html>
 <html>
 <head>
     <title>Example Domain</title>
@@ -50,5 +50,5 @@ Our body from the callback : <!doctype html>
 </html>
 
 *** Answer ***
-Status code : 200
-Body should be empty, because we decided to manage callbacks : 0
+Status code: 200
+Body should be empty, because we decided to manage callbacks: 0
index 0c72a82..bf03427 100644 (file)
@@ -1,3 +1,3 @@
 *** Answer ***
-Status code : 200
-Size downloaded : 1270
+Status code: 200
+Size downloaded: 1270.0
diff --git a/tests/sav/curl_mail.res b/tests/sav/curl_mail.res
deleted file mode 100644 (file)
index 5e63d7f..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-Error code : 6
-Error msg : Couldn't resolve host name
index 38a9af9..2fd90b2 100644 (file)
@@ -1 +1,12 @@
+../lib/standard/kernel.nit:24,1--95,3: Error: `kernel#Object` does not specialize `module_0#Object`. Possible duplication of the root class `Object`?
 ../lib/standard/kernel.nit:97,1--111,3: Error: `kernel#Sys` does not specialize `module_0#Object`. Possible duplication of the root class `Object`?
+../lib/standard/kernel.nit:124,1--182,3: Error: `kernel#Comparable` does not specialize `module_0#Object`. Possible duplication of the root class `Object`?
+../lib/standard/kernel.nit:184,1--221,3: Error: `kernel#Discrete` does not specialize `module_0#Object`. Possible duplication of the root class `Object`?
+../lib/standard/kernel.nit:223,1--240,3: Error: `kernel#Cloneable` does not specialize `module_0#Object`. Possible duplication of the root class `Object`?
+../lib/standard/kernel.nit:242,1--297,3: Error: `kernel#Numeric` does not specialize `module_0#Object`. Possible duplication of the root class `Object`?
+../lib/standard/kernel.nit:303,1--326,3: Error: `kernel#Bool` does not specialize `module_0#Object`. Possible duplication of the root class `Object`?
+../lib/standard/kernel.nit:328,1--410,3: Error: `kernel#Float` does not specialize `module_0#Object`. Possible duplication of the root class `Object`?
+../lib/standard/kernel.nit:412,1--514,3: Error: `kernel#Byte` does not specialize `module_0#Object`. Possible duplication of the root class `Object`?
+../lib/standard/kernel.nit:516,1--707,3: Error: `kernel#Int` does not specialize `module_0#Object`. Possible duplication of the root class `Object`?
+../lib/standard/kernel.nit:709,1--849,3: Error: `kernel#Char` does not specialize `module_0#Object`. Possible duplication of the root class `Object`?
+../lib/standard/kernel.nit:851,1--858,3: Error: `kernel#Pointer` does not specialize `module_0#Object`. Possible duplication of the root class `Object`?
diff --git a/tests/sav/niti/base_attr_annot_alt2.res b/tests/sav/niti/base_attr_annot_alt2.res
new file mode 100644 (file)
index 0000000..f51ab75
--- /dev/null
@@ -0,0 +1 @@
+Runtime error: Uninitialized attribute _a (alt/base_attr_annot_alt2.nit:34)
index 1b8bc03..757c963 100644 (file)
@@ -14,7 +14,6 @@
 # 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.
-module test_curl
 
 import curl
 
@@ -28,7 +27,7 @@ fun error_manager(err: CURLCode) do if not err.is_ok then print err
 
 var url = "http://example.org/"
 
-var curl = new CCurl.easy_init
+var curl = new NativeCurl.easy_init
 if not curl.is_init then print "failed init"
 
 var error:CURLCode
@@ -40,15 +39,14 @@ error_manager(error)
 #error_manager(error)
 
 var cbManager = new CallbackManager
-error = curl.register_callback(cbManager, new CURLCallbackType.body)
+error = curl.register_callback_body(cbManager)
 error_manager(error)
 
 error = curl.easy_perform
 error_manager(error)
 
 # Long set
-var info:nullable CURLInfoResponseLong
-info = curl.easy_getinfo_long(new CURLInfoLong.header_size)
+var info = curl.easy_getinfo_long(new CURLInfoLong.header_size)
 assert infoResp:info != null
 
 info = curl.easy_getinfo_long(new CURLInfoLong.response_code)
@@ -103,8 +101,7 @@ info = curl.easy_getinfo_long(new CURLInfoLong.rtsp_cseq_self)
 assert infoResp:info != null
 
 # Double
-var infoDouble: nullable CURLInfoResponseDouble
-infoDouble = curl.easy_getinfo_double(new CURLInfoDouble.total_time)
+var infoDouble = curl.easy_getinfo_double(new CURLInfoDouble.total_time)
 assert infoResp:infoDouble != null
 
 infoDouble = curl.easy_getinfo_double(new CURLInfoDouble.namelookup_time)
@@ -144,15 +141,15 @@ infoDouble = curl.easy_getinfo_double(new CURLInfoDouble.content_length_upload)
 assert infoResp:infoDouble != null
 
 # String set
-var infoStr:nullable CURLInfoResponseString
-infoStr = curl.easy_getinfo_chars(new CURLInfoChars.content_type)
+var infoStr = curl.easy_getinfo_chars(new CURLInfoChars.content_type)
 assert infoResp:infoStr != null
 
 infoStr = curl.easy_getinfo_chars(new CURLInfoChars.effective_url)
 assert infoResp:infoStr != null
 
+# follow_location not set, so returns null
 infoStr = curl.easy_getinfo_chars(new CURLInfoChars.redirect_url)
-assert infoResp:infoStr != null
+assert infoStr == null
 
 infoStr = curl.easy_getinfo_chars(new CURLInfoChars.primary_ip)
 assert infoResp:infoStr != null
@@ -160,18 +157,20 @@ assert infoResp:infoStr != null
 infoStr = curl.easy_getinfo_chars(new CURLInfoChars.local_ip)
 assert infoResp:infoStr != null
 
+# Not connecting to FTP so `null`
 infoStr = curl.easy_getinfo_chars(new CURLInfoChars.ftp_entry_path)
-assert infoResp:infoStr != null
+assert infoStr == null
 
+# opt private not set nor implemented, so returns null
 infoStr = curl.easy_getinfo_chars(new CURLInfoChars.private_data)
-assert infoResp:infoStr != null
+assert infoStr == null
 
+# Not an RTSP connection so `null`
 infoStr = curl.easy_getinfo_chars(new CURLInfoChars.rtsp_session_id)
-assert infoResp:infoStr != null
+assert infoStr == null
 
 # CURLSList set
-var infoList:nullable CURLInfoResponseArray
-infoList = curl.easy_getinfo_slist(new CURLInfoSList.ssl_engines)
+var infoList = curl.easy_getinfo_slist(new CURLInfoSList.ssl_engines)
 assert infoResp:infoList != null
 
 infoList = curl.easy_getinfo_slist(new CURLInfoSList.cookielist)
@@ -211,4 +210,4 @@ var hashMapRefined = new HeaderMap
 hashMapRefined["hello"] = "toto"
 hashMapRefined["hello"] = "tata"
 hashMapRefined["allo"] = "foo"
-print hashMapRefined.to_url_encoded(new CCurl.easy_init)
+print hashMapRefined.to_url_encoded(sys.curl)