Merge: Attribute and autoinit annotations
authorJean Privat <jean@pryen.org>
Wed, 10 Jun 2015 01:46:42 +0000 (21:46 -0400)
committerJean Privat <jean@pryen.org>
Wed, 10 Jun 2015 01:46:42 +0000 (21:46 -0400)
A big set of loosely coupled but related changed on the annotations on attributes and methods.
Here is a summary of the changes on the user-side:

* No more special case for the kind of classes, so you can use `autoinit` in interfaces.
* Explicit annotation `autoinit` is understood on attributes and is the default on value-less concrete attribute.
* Abstract attributes are `noautoinit` by default, if `autoinit` is given, it is applied on the setter. This way abstract attributes are basically just a couple of getter-setter. close #1311

This way there is less special cases and behaviors. Still more work is required to finish #1322.

Pull-Request: #1433
Reviewed-by: Lucas Bajolet <r4pass@hotmail.com>
Reviewed-by: Romain Chanoir <chanoir.romain@courrier.uqam.ca>
Reviewed-by: Alexandre Terrasa <alexandre@moz-code.org>

54 files changed:
contrib/opportunity/src/templates/meetup.nit
examples/rosettacode/24_game.nit [new file with mode: 0644]
lib/android/bundle/bundle.nit
lib/android/intent/intent_api10.nit
lib/binary/binary.nit
lib/cpp.nit
lib/date.nit [new file with mode: 0755]
lib/mnit_android/android_assets.nit
lib/socket/socket.nit
lib/socket/socket_c.nit
lib/standard/file.nit
share/man/nitc.md
src/c_tools.nit
src/compiler/abstract_compiler.nit
src/compiler/compiler_ffi/light.nit
src/compiler/separate_compiler.nit
src/ffi/java.nit
src/ffi/light_ffi_base.nit
src/frontend/simple_misc_analysis.nit
src/loader.nit
src/mkcsrc
src/nitni/nitni_base.nit
src/parser/nit.sablecc3xx
src/parser/parser_nodes.nit
src/parser/parser_work.nit
src/parser/tables_nit.c
src/phase.nit
src/rapid_type_analysis.nit
src/semantize/scope.nit
src/semantize/typing.nit
src/ssa.nit [new file with mode: 0644]
src/transform.nit
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_adaptive_loop3.nit
tests/base_adaptive_loop_null.nit
tests/base_do_block.nit [new file with mode: 0644]
tests/sav/24_game.res [new file with mode: 0644]
tests/sav/base_do_block.res [new file with mode: 0644]
tests/sav/base_import_alt3.res
tests/sav/error_mod_unk.res
tests/sav/neo_doxygen_dump_args4.res
tests/sav/neo_doxygen_dump_args5.res
tests/sav/test_ffi_c_primitives.res
tests/sav/test_float.res
tests/sav/test_keep_going.res [new file with mode: 0644]
tests/sav/xymus_net.res
tests/test_ffi_c_primitives.nit
tests/test_ffi_cpp_duplicated_callback_a.nit
tests/test_ffi_cpp_duplicated_callback_b.nit
tests/test_float.nit
tests/test_keep_going.nit [new file with mode: 0755]

index 6eca566..07a5f66 100644 (file)
@@ -356,7 +356,7 @@ redef class Meetup
                end
                t.add """
 <tr id="total">
-       <th>Total</th>
+       <th>Total ({{{participants(db).length}}})</th>
                """
                for i in answers(db) do
                        t.add """<th id="total{{{i.id}}}"><center>{{{i.count(db)}}}"""
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 edb0c88..76babb4 100644 (file)
@@ -63,7 +63,7 @@ extern class NativeBundle in "Java" `{ android.os.Bundle `}
        `}
        # FIXME: Java's `char` are encoded on 16-bits whereas Nit's are on 8-bits.
        fun put_char(key: JavaString, value: Char) in "Java" `{
-               self.putChar(key, value);
+               self.putChar(key, (char)value);
        `}
        fun put_short(key: JavaString, value: Int) in "Java" `{
                self.putShort(key, (short) value);
@@ -148,7 +148,7 @@ extern class NativeBundle in "Java" `{ android.os.Bundle `}
                char[] java_array = new char[(int)Array_of_Char_length(value)];
 
                for(int i=0; i < java_array.length; ++i)
-                       java_array[i] = Array_of_Char__index(value, i);
+                       java_array[i] = (char)Array_of_Char__index(value, i);
 
                self.putCharArray(key, java_array);
        `}
@@ -218,10 +218,10 @@ extern class NativeBundle in "Java" `{ android.os.Bundle `}
                return self.getByte(key, (byte) def_value);
        `}
        # FIXME: Java's `char` are encoded on 16-bits whereas Nit's are on 8-bits.
-       fun get_char(key: JavaString): Char in "Java" `{ return self.getChar(key); `}
+       fun get_char(key: JavaString): Char in "Java" `{ return (int)self.getChar(key); `}
        # FIXME: Java's `char` are encoded on 16-bits whereas Nit's are on 8-bits.
        fun get_char_with_def_value(key: JavaString, def_value: Char): Char in "Java" `{
-               return self.getChar(key, def_value);
+               return (int)self.getChar(key, (char)def_value);
        `}
        fun get_short(key: JavaString): Int in "Java" `{ return (short) self.getShort(key); `}
        fun get_short_with_def_value(key: JavaString, def_value: Int): Int in "Java" `{
@@ -335,7 +335,7 @@ extern class NativeBundle in "Java" `{ android.os.Bundle `}
                if (java_array == null) return nit_array;
 
                for(int i=0; i < java_array.length; ++i)
-                       Array_of_Char_add(nit_array, java_array[i]);
+                       Array_of_Char_add(nit_array, (int)java_array[i]);
 
                return nit_array;
        `}
index 2d536fd..8c6a928 100644 (file)
@@ -81,7 +81,7 @@ extern class NativeIntent in "Java" `{ android.content.Intent `}
        `}
        # FIXME: Java's `char` are encoded on 16-bits whereas Nit's are on 8-bits.
        fun char_extra(name: JavaString, def_value: Char): Char in "Java" `{
-               return self.getCharExtra(name, def_value);
+               return (int)self.getCharExtra(name, (char)def_value);
        `}
        fun char_sequence_array_extra(name: JavaString): Array[String]
          import StringCopyArray, StringCopyArray.add, StringCopyArray.collection in "Java" `{
@@ -244,7 +244,7 @@ extern class NativeIntent in "Java" `{ android.content.Intent `}
                char[] java_array = new char[(int)Array_of_Char_length(value)];
 
                for (int i=0; i < java_array.length; ++i)
-                       java_array[i] = Array_of_Char__index(value, i);
+                       java_array[i] = (char)Array_of_Char__index(value, i);
 
                return self.putExtra(name, java_array);
        `}
index 59ec88d..f4be1eb 100644 (file)
@@ -45,10 +45,13 @@ in "C" `{
        #include <endian.h>
 
        // Android compatibility
+       #ifndef be32toh
+               #define be32toh(val) betoh32(val)
+               #define le32toh(val) letoh32(val)
+       #endif
+
        #ifndef be64toh
                #define be64toh(val) betoh64(val)
-       #endif
-       #ifndef le64toh
                #define le64toh(val) letoh64(val)
        #endif
 `}
@@ -148,11 +151,15 @@ redef abstract class Reader
        super BinaryStream
 
        # Read a single byte and return `true` if its value is different than 0
+       #
+       # Returns `false` when an error is pending (`last_error != null`).
        fun read_bool: Bool do return read_byte != 0
 
        # Get an `Array` of 8 `Bool` by reading a single byte
        #
        # To be used with `BinaryWriter::write_bits`.
+       #
+       # Returns an array of `false` when an error is pending (`last_error != null`).
        fun read_bits: Array[Bool]
        do
                var int = read_byte
@@ -163,12 +170,14 @@ redef abstract class Reader
        # Read a null terminated string
        #
        # To be used with `Writer::write_string`.
+       #
+       # Returns a truncated string when an error is pending (`last_error != null`).
        fun read_string: String
        do
                var buf = new FlatBuffer
                loop
                        var byte = read_byte
-                       if byte == 0x00 then return buf.to_s
+                       if byte == null or byte == 0x00 then return buf.to_s
                        buf.chars.add byte.ascii
                end
        end
@@ -176,6 +185,8 @@ redef abstract class Reader
        # Read the length as a 64 bits integer, then the content of the block
        #
        # To be used with `Writer::write_block`.
+       #
+       # Returns a truncated string when an error is pending (`last_error != null`).
        fun read_block: String
        do
                var length = read_int64
@@ -187,6 +198,8 @@ redef abstract class Reader
        #
        # Using this format may result in a loss of precision as it uses less bits
        # than Nit `Float`.
+       #
+       # Returns `0.0` when an error is pending (`last_error != null`).
        fun read_float: Float
        do
                if last_error != null then return 0.0
@@ -223,6 +236,8 @@ redef abstract class Reader
        `}
 
        # Read a floating point on 64 bits and return it as a `Float`
+       #
+       # Returns `0.0` when an error is pending (`last_error != null`).
        fun read_double: Float
        do
                if last_error != null then return 0.0
@@ -271,6 +286,8 @@ redef abstract class Reader
        #
        # Using this format may result in a loss of precision as the length of a
        # Nit `Int` may be less than 64 bits on some platforms.
+       #
+       # Returns `0` when an error is pending (`last_error != null`).
        fun read_int64: Int
        do
                if last_error != null then return 0
index a2896d3..c64ae33 100644 (file)
@@ -31,6 +31,6 @@ end
 redef class NativeString
        # Get `self` as a `CppString`
        fun to_cpp_string(length: Int): CppString in "C++" `{
-               return new std::string(self, length);
+               return new std::string(reinterpret_cast<char*>(self), length);
        `}
 end
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 51e1ec8..6531035 100644 (file)
@@ -231,7 +231,7 @@ redef universal Int
        # The first power of `exp` greater or equal to `self`
        private fun next_pow(exp: Int): Int
        do
-               var p = 0
+               var p = 1
                while p < self do p = p*exp
                return p
        end
index 4885805..a40cc5d 100644 (file)
@@ -71,14 +71,29 @@ class TCPStream
                        closed = true
                        return
                end
-               var hostname = socket.gethostbyname(host)
-               addrin = new NativeSocketAddrIn.with_hostent(hostname, port)
 
+               var hostname = sys.gethostbyname(host.to_cstring)
+               if hostname.address_is_null then
+                       # Error in name lookup
+                       var err = sys.h_errno
+                       last_error = new IOError(err.to_s)
+
+                       closed = true
+                       end_reached = true
+
+                       return
+               end
+
+               addrin = new NativeSocketAddrIn.with_hostent(hostname, port)
                address = addrin.address
                init(addrin.port, hostname.h_name)
 
                closed = not internal_connect
                end_reached = closed
+               if closed then
+                       # Connection failed
+                       last_error = new IOError(errno.strerror)
+               end
        end
 
        # Creates a client socket, this is meant to be used by accept only
index d9056d6..94eecd7 100644 (file)
@@ -121,8 +121,6 @@ extern class NativeSocket `{ int* `}
 
        fun descriptor: Int `{ return *self; `}
 
-       fun gethostbyname(n: String): NativeSocketHostent import String.to_cstring `{ return gethostbyname(String_to_cstring(n)); `}
-
        fun connect(addrIn: NativeSocketAddrIn): Int `{
                return connect(*self, (struct sockaddr*)addrIn, sizeof(*addrIn));
        `}
@@ -482,3 +480,52 @@ extern class NativeSocketPollValues `{ int `}
                return self | other;
        `}
 end
+
+redef class Sys
+       # Get network host entry
+       fun gethostbyname(name: NativeString): NativeSocketHostent `{
+               return gethostbyname(name);
+       `}
+
+       # Last error raised by `gethostbyname`
+       fun h_errno: HErrno `{ return h_errno; `}
+end
+
+# Error code of `Sys::h_errno`
+extern class HErrno `{ int `}
+       # The specified host is unknown
+       fun host_not_found: Bool `{ return self == HOST_NOT_FOUND; `}
+
+       # The requested name is valid but does not have an IP address
+       #
+       # Same as `no_data`.
+       fun no_address: Bool `{ return self == NO_ADDRESS; `}
+
+       # The requested name is valid byt does not have an IP address
+       #
+       # Same as `no_address`.
+       fun no_data: Bool `{ return self == NO_DATA; `}
+
+       # A nonrecoverable name server error occurred
+       fun no_recovery: Bool `{ return self == NO_RECOVERY; `}
+
+       # A temporary error occurred on an authoritative name server, try again later
+       fun try_again: Bool `{ return self == TRY_AGAIN; `}
+
+       redef fun to_s
+       do
+               if host_not_found then
+                       return "The specified host is unknown"
+               else if no_address then
+                       return "The requested name is valid but does not have an IP address"
+               else if no_recovery then
+                       return "A nonrecoverable name server error occurred"
+               else if try_again then
+                       return "A temporary error occurred on an authoritative name server, try again later"
+               else
+                       # This may happen if another call was made to `gethostbyname`
+                       # before we fetch the error code.
+                       return "Unknown error on `gethostbyname`"
+               end
+       end
+end
index 46c52ec..9687b0c 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 91e8d8c..9e0fbf5 100644 (file)
@@ -404,8 +404,18 @@ They are useless for a normal user.
 `--no-main`
 :   Do not generate main entry point.
 
-`--stacktrace`
-:   Control the generation of stack traces.
+`--no-stacktrace`
+:   The compiled program will not display stack traces on runtime errors.
+
+    Because stack traces rely on libunwind, this option might be useful in order to generate more portable binaries
+    since libunwind might be non available on the runtime system (or available with an ABI incompatible version).
+
+    The generated C is API-portable and can be reused, distributed and compiled on any supported system.
+    If the option `--no-stacktrace` is not used but the development files of the library `libunwind` are not available, then a warning will be displayed
+    and stack trace will be disabled.
+
+    Note that the `--no-stacktrace` option (or this absence) can be toggled manually in the generated Makefile (search `NO_STACKTRACE` in the Makefile).
+    Moreover, the environment variable `NIT_NO_STACK` (see bellow) can also be used at runtime to disable stack traces.
 
 `--max-c-lines`
 :   Maximum number of lines in generated C files. Use 0 for unlimited.
@@ -481,6 +491,20 @@ This option is used to test the robustness of the tools by allowing phases to pr
     * large: disable the GC and just allocate a large memory area to use for all instantiation.
     * help: show the list of available options.
 
+`NIT_NO_STACK`
+:   Runtime control of stack traces.
+
+    By default, stack traces are printed when a runtime errors occurs during the execution of a compiled program.
+    When setting this environment variable to a non empty value, such stack traces are disabled.
+
+    The environment variable is used when programs are executed, not when they are compiled.
+    Thus, you do not need to recompile programs in order to disable generated stack traces.
+
+    Note that stack traces require that, during the compilation, development files of the library `libunwind` are available.
+    If they are not available, then programs are compiled without any stack trace support.
+
+    To completely disable stack traces, see the option `--no-stacktrace`.
+
 # SEE ALSO
 
 The Nit language documentation and the source code of its tools and libraries may be downloaded from <http://nitlanguage.org>
index df2ddd8..0b80817 100644 (file)
@@ -47,7 +47,7 @@ class CCompilationUnit
        # files to compile TODO check is appropriate
        var files = new Array[String]
 
-       # Add `c_function` as a `static` function local to this unit
+       # Add a `static` `c_function` to be strictly local to this unit
        fun add_local_function(c_function: CFunction)
        do
                body_decl.add "static {c_function.signature};\n"
@@ -55,10 +55,10 @@ class CCompilationUnit
                body_impl.add c_function.to_writer
        end
 
-       # Add `c_function` as a public function to this unit
+       # Add a public `c_function` accessible from outside this compilation unit
        fun add_exported_function(c_function: CFunction)
        do
-               header_decl.add "{c_function.signature};\n"
+               body_decl.add "{c_function.signature};\n"
                body_impl.add "\n"
                body_impl.add c_function.to_writer
        end
index 61b59a9..c48aab9 100644 (file)
@@ -63,8 +63,8 @@ redef class ToolContext
        var opt_invocation_metrics = new OptionBool("Enable static and dynamic count of all method invocations", "--invocation-metrics")
        # --isset-checks-metrics
        var opt_isset_checks_metrics = new OptionBool("Enable static and dynamic count of isset checks before attributes access", "--isset-checks-metrics")
-       # --stacktrace
-       var opt_stacktrace = new OptionString("Control the generation of stack traces", "--stacktrace")
+       # --no-stacktrace
+       var opt_no_stacktrace = new OptionBool("Disable the generation of stack traces", "--no-stacktrace")
        # --no-gcc-directives
        var opt_no_gcc_directive = new OptionArray("Disable a advanced gcc directives for optimization", "--no-gcc-directive")
        # --release
@@ -76,7 +76,7 @@ redef class ToolContext
                self.option_context.add_option(self.opt_output, self.opt_dir, self.opt_no_cc, self.opt_no_main, self.opt_make_flags, self.opt_compile_dir, self.opt_hardening)
                self.option_context.add_option(self.opt_no_check_covariance, self.opt_no_check_attr_isset, self.opt_no_check_assert, self.opt_no_check_autocast, self.opt_no_check_null, self.opt_no_check_all)
                self.option_context.add_option(self.opt_typing_test_metrics, self.opt_invocation_metrics, self.opt_isset_checks_metrics)
-               self.option_context.add_option(self.opt_stacktrace)
+               self.option_context.add_option(self.opt_no_stacktrace)
                self.option_context.add_option(self.opt_no_gcc_directive)
                self.option_context.add_option(self.opt_release)
                self.option_context.add_option(self.opt_max_c_lines, self.opt_group_c_files)
@@ -88,17 +88,6 @@ redef class ToolContext
        do
                super
 
-               var st = opt_stacktrace.value
-               if st == "none" or st == "libunwind" or st == "nitstack" then
-                       # Fine, do nothing
-               else if st == "auto" or st == null then
-                       # Default is nitstack
-                       opt_stacktrace.value = "nitstack"
-               else
-                       print "Option Error: unknown value `{st}` for --stacktrace. Use `none`, `libunwind`, `nitstack` or `auto`."
-                       exit(1)
-               end
-
                if opt_output.value != null and opt_dir.value != null then
                        print "Option Error: cannot use both --dir and --output"
                        exit(1)
@@ -212,7 +201,7 @@ class MakefileToolchain
        fun write_files(compile_dir: String, cfiles: Array[String])
        do
                var platform = compiler.target_platform
-               if self.toolcontext.opt_stacktrace.value == "nitstack" and platform.supports_libunwind then compiler.build_c_to_nit_bindings
+               if platform.supports_libunwind then compiler.build_c_to_nit_bindings
                var cc_opt_with_libgc = "-DWITH_LIBGC"
                if not platform.supports_libgc then cc_opt_with_libgc = ""
 
@@ -355,25 +344,50 @@ class MakefileToolchain
 
                makefile.write("CC = ccache cc\nCXX = ccache c++\nCFLAGS = -g -O2 -Wno-unused-value -Wno-switch -Wno-attributes\nCINCL =\nLDFLAGS ?= \nLDLIBS  ?= -lm {linker_options.join(" ")}\n\n")
 
-               var ost = toolcontext.opt_stacktrace.value
-               if (ost == "libunwind" or ost == "nitstack") and platform.supports_libunwind then makefile.write("NEED_LIBUNWIND := YesPlease\n")
+               makefile.write "\n# SPECIAL CONFIGURATION FLAGS\n"
+               if platform.supports_libunwind then
+                       if toolcontext.opt_no_stacktrace.value then
+                               makefile.write "NO_STACKTRACE=True"
+                       else
+                               makefile.write "NO_STACKTRACE= # Set to `True` to enable"
+                       end
+               end
 
                # Dynamic adaptations
                # While `platform` enable complex toolchains, they are statically applied
                # For a dynamic adaptsation of the compilation, the generated Makefile should check and adapt things itself
+               makefile.write "\n\n"
 
                # Check and adapt the targeted system
                makefile.write("uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not')\n")
-               makefile.write("ifeq ($(uname_S),Darwin)\n")
-               # remove -lunwind since it is already included on macosx
-               makefile.write("\tNEED_LIBUNWIND :=\n")
-               makefile.write("endif\n\n")
 
                # Check and adapt for the compiler used
                # clang need an additionnal `-Qunused-arguments`
                makefile.write("clang_check := $(shell sh -c '$(CC) -v 2>&1 | grep -q clang; echo $$?')\nifeq ($(clang_check), 0)\n\tCFLAGS += -Qunused-arguments\nendif\n")
 
-               makefile.write("ifdef NEED_LIBUNWIND\n\tLDLIBS += -lunwind\nendif\n")
+               if platform.supports_libunwind then
+                       makefile.write """
+ifneq ($(NO_STACKTRACE), True)
+  # Check and include lib-unwind in a portable way
+  ifneq ($(uname_S),Darwin)
+    # already included on macosx, but need to get the correct flags in other supported platforms.
+    ifeq ($(shell pkg-config --exists 'libunwind'; echo $$?), 0)
+      LDLIBS += `pkg-config --libs libunwind`
+      CFLAGS += `pkg-config --cflags libunwind`
+    else
+      $(warning "[_] stack-traces disabled. Please install libunwind-dev.")
+      CFLAGS += -D NO_STACKTRACE
+    endif
+  endif
+else
+  # Stacktraces disabled
+  CFLAGS += -D NO_STACKTRACE
+endif
+
+"""
+               else
+                       makefile.write("CFLAGS += -D NO_STACKTRACE\n\n")
+               end
 
                makefile.write("all: {outpath}\n")
                if outpath != real_outpath then
@@ -623,6 +637,7 @@ abstract class AbstractCompiler
                self.header.add_decl("#include <string.h>")
                self.header.add_decl("#include <sys/types.h>\n")
                self.header.add_decl("#include <unistd.h>\n")
+               self.header.add_decl("#include <stdint.h>\n")
                self.header.add_decl("#include \"gc_chooser.h\"")
                self.header.add_decl("#ifdef ANDROID")
                self.header.add_decl("  #include <android/log.h>")
@@ -730,19 +745,16 @@ extern void nitni_global_ref_decr( struct nitni_ref *ref );
        do
                var v = self.new_visitor
                v.add_decl("#include <signal.h>")
-               var ost = modelbuilder.toolcontext.opt_stacktrace.value
                var platform = target_platform
 
-               if not platform.supports_libunwind then ost = "none"
-
                var no_main = platform.no_main or modelbuilder.toolcontext.opt_no_main.value
 
-               if ost == "nitstack" or ost == "libunwind" then
+               if platform.supports_libunwind then
+                       v.add_decl("#ifndef NO_STACKTRACE")
                        v.add_decl("#define UNW_LOCAL_ONLY")
                        v.add_decl("#include <libunwind.h>")
-                       if ost == "nitstack" then
-                               v.add_decl("#include \"c_functions_hash.h\"")
-                       end
+                       v.add_decl("#include \"c_functions_hash.h\"")
+                       v.add_decl("#endif")
                end
                v.add_decl("int glob_argc;")
                v.add_decl("char **glob_argv;")
@@ -776,7 +788,8 @@ extern void nitni_global_ref_decr( struct nitni_ref *ref );
                end
 
                v.add_decl("static void show_backtrace(void) \{")
-               if ost == "nitstack" or ost == "libunwind" then
+               if platform.supports_libunwind then
+                       v.add_decl("#ifndef NO_STACKTRACE")
                        v.add_decl("char* opt = getenv(\"NIT_NO_STACK\");")
                        v.add_decl("unw_cursor_t cursor;")
                        v.add_decl("if(opt==NULL)\{")
@@ -790,20 +803,17 @@ extern void nitni_global_ref_decr( struct nitni_ref *ref );
                        v.add_decl("PRINT_ERROR(\"-------------------------------------------------\\n\");")
                        v.add_decl("while (unw_step(&cursor) > 0) \{")
                        v.add_decl("    unw_get_proc_name(&cursor, procname, 100, &ip);")
-                       if ost == "nitstack" then
                        v.add_decl("    const char* recv = get_nit_name(procname, strlen(procname));")
                        v.add_decl("    if (recv != NULL)\{")
                        v.add_decl("            PRINT_ERROR(\"` %s\\n\", recv);")
                        v.add_decl("    \}else\{")
                        v.add_decl("            PRINT_ERROR(\"` %s\\n\", procname);")
                        v.add_decl("    \}")
-                       else
-                       v.add_decl("    PRINT_ERROR(\"` %s \\n\",procname);")
-                       end
                        v.add_decl("\}")
                        v.add_decl("PRINT_ERROR(\"-------------------------------------------------\\n\");")
                        v.add_decl("free(procname);")
                        v.add_decl("\}")
+                       v.add_decl("#endif /* NO_STACKTRACE */")
                end
                v.add_decl("\}")
 
@@ -1662,8 +1672,9 @@ abstract class AbstractCompilerVisitor
                if nexpr == null then return
                if nexpr.mtype == null and not nexpr.is_typed then
                        # Untyped expression.
-                       # Might mean dead code
-                       # So just return
+                       # Might mean dead code or invalid code
+                       # so aborts
+                       add_abort("FATAL: bad statement executed.")
                        return
                end
 
@@ -1687,8 +1698,10 @@ abstract class AbstractCompilerVisitor
        do
                if nexpr.mtype == null then
                        # Untyped expression.
-                       # Might mean dead code
-                       # so return a placebo result
+                       # Might mean dead code or invalid code.
+                       # so aborts
+                       add_abort("FATAL: bad expression executed.")
+                       # and return a placebo result to please the C compiler
                        if mtype == null then mtype = compiler.mainmodule.object_type
                        return new_var(mtype)
                end
@@ -1860,13 +1873,13 @@ redef class MClassType
                else if mclass.name == "Bool" then
                        return "short int"
                else if mclass.name == "Char" then
-                       return "char"
+                       return "uint32_t"
                else if mclass.name == "Float" then
                        return "double"
                else if mclass.name == "Byte" then
                        return "unsigned char"
                else if mclass.name == "NativeString" then
-                       return "char*"
+                       return "unsigned char*"
                else if mclass.name == "NativeArray" then
                        return "val*"
                else
@@ -2131,12 +2144,12 @@ redef class AMethPropdef
                                v.ret(v.new_expr("(unsigned char){arguments[0]}", ret.as(not null)))
                                return true
                        else if pname == "ascii" then
-                               v.ret(v.new_expr("{arguments[0]}", ret.as(not null)))
+                               v.ret(v.new_expr("(uint32_t){arguments[0]}", ret.as(not null)))
                                return true
                        end
                else if cname == "Char" then
                        if pname == "output" then
-                               v.add("printf(\"%c\", {arguments.first});")
+                               v.add("printf(\"%c\", ((unsigned char){arguments.first}));")
                                return true
                        else if pname == "object_id" then
                                v.ret(v.new_expr("(long){arguments.first}", ret.as(not null)))
@@ -2170,7 +2183,7 @@ redef class AMethPropdef
                                v.ret(v.new_expr("{arguments[0]}-'0'", ret.as(not null)))
                                return true
                        else if pname == "ascii" then
-                               v.ret(v.new_expr("(unsigned char){arguments[0]}", ret.as(not null)))
+                               v.ret(v.new_expr("(long){arguments[0]}", ret.as(not null)))
                                return true
                        end
                else if cname == "Byte" then
@@ -2310,10 +2323,10 @@ redef class AMethPropdef
                        end
                else if cname == "NativeString" then
                        if pname == "[]" then
-                               v.ret(v.new_expr("{arguments[0]}[{arguments[1]}]", ret.as(not null)))
+                               v.ret(v.new_expr("(uint32_t){arguments[0]}[{arguments[1]}]", ret.as(not null)))
                                return true
                        else if pname == "[]=" then
-                               v.add("{arguments[0]}[{arguments[1]}]={arguments[2]};")
+                               v.add("{arguments[0]}[{arguments[1]}]=(unsigned char){arguments[2]};")
                                return true
                        else if pname == "copy_to" then
                                v.add("memmove({arguments[1]}+{arguments[4]},{arguments[0]}+{arguments[3]},{arguments[2]});")
@@ -2325,7 +2338,7 @@ redef class AMethPropdef
                                v.ret(v.new_expr("{arguments[0]} + {arguments[1]}", ret.as(not null)))
                                return true
                        else if pname == "new" then
-                               v.ret(v.new_expr("(char*)nit_alloc({arguments[1]})", ret.as(not null)))
+                               v.ret(v.new_expr("(unsigned char*)nit_alloc({arguments[1]})", ret.as(not null)))
                                return true
                        end
                else if cname == "NativeArray" then
@@ -2339,7 +2352,7 @@ redef class AMethPropdef
                        v.ret(v.new_expr("glob_sys", ret.as(not null)))
                        return true
                else if pname == "calloc_string" then
-                       v.ret(v.new_expr("(char*)nit_alloc({arguments[1]})", ret.as(not null)))
+                       v.ret(v.new_expr("(unsigned char*)nit_alloc({arguments[1]})", ret.as(not null)))
                        return true
                else if pname == "calloc_array" then
                        v.calloc_array(ret.as(not null), arguments)
index 01579b0..1f59771 100644 (file)
@@ -43,6 +43,7 @@ redef class MModule
                ensure_compile_nitni_base(v)
 
                nitni_ccu.header_c_types.add("#include \"{c_name}._ffi.h\"\n")
+               nitni_ccu.header_c_types.add("#include <stdint.h>\n")
                nitni_ccu.header_c_types.add """
 extern void nitni_global_ref_incr(void*);
 extern void nitni_global_ref_decr(void*);
index 31a4f20..e07f125 100644 (file)
@@ -625,6 +625,7 @@ class SeparateCompiler
                for cd in mmodule.mclassdefs do
                        for pd in cd.mpropdefs do
                                if not pd isa MMethodDef then continue
+                               if pd.msignature == null then continue # Skip broken method
                                var rta = runtime_type_analysis
                                if modelbuilder.toolcontext.opt_skip_dead_methods.value and rta != null and not rta.live_methoddefs.has(pd) then continue
                                #print "compile {pd} @ {cd} @ {mmodule}"
@@ -1193,7 +1194,7 @@ class SeparateCompilerVisitor
                                if mtype.name == "Int" then
                                        return self.new_expr("(long)({value})>>2", mtype)
                                else if mtype.name == "Char" then
-                                       return self.new_expr("(char)((long)({value})>>2)", mtype)
+                                       return self.new_expr("(uint32_t)((long)({value})>>2)", mtype)
                                else if mtype.name == "Bool" then
                                        return self.new_expr("(short int)((long)({value})>>2)", mtype)
                                else
index 3f2a21e..c26fea2 100644 (file)
@@ -243,7 +243,6 @@ redef class MModule
        private fun insert_compiler_options
        do
                cflags.add_one("", "-I $(JAVA_HOME)/include/ -I $(JAVA_HOME)/include/linux/")
-               ldflags.add_one("", "-L $(JNI_LIB_PATH) -ljvm")
        end
 
        # Name of the generated Java class where to store all implementation methods of this module
@@ -480,7 +479,7 @@ redef class MClassType
                if ftype isa ForeignJavaType then return ftype.java_type.
                        replace('/', ".").replace('$', ".").replace(' ', "").replace('\n',"")
                if mclass.name == "Bool" then return "boolean"
-               if mclass.name == "Char" then return "char"
+               if mclass.name == "Char" then return "int"
                if mclass.name == "Int" then return "long"
                if mclass.name == "Float" then return "double"
                if mclass.name == "Byte" then return "byte"
@@ -492,7 +491,7 @@ redef class MClassType
                var ftype = mclass.ftype
                if ftype isa ForeignJavaType then return "jobject"
                if mclass.name == "Bool" then return "jboolean"
-               if mclass.name == "Char" then return "jchar"
+               if mclass.name == "Char" then return "jint"
                if mclass.name == "Int" then return "jlong"
                if mclass.name == "Float" then return "jdouble"
                if mclass.name == "Byte" then return "jbyte"
@@ -552,7 +551,7 @@ redef class MClassType
                        return "L{jni_type};"
                end
                if mclass.name == "Bool" then return "Z"
-               if mclass.name == "Char" then return "C"
+               if mclass.name == "Char" then return "I"
                if mclass.name == "Int" then return "J"
                if mclass.name == "Float" then return "D"
                if mclass.name == "Byte" then return "B"
@@ -565,7 +564,7 @@ redef class MClassType
 
                if ftype isa ForeignJavaType then return "Object"
                if mclass.name == "Bool" then return "Boolean"
-               if mclass.name == "Char" then return "Char"
+               if mclass.name == "Char" then return "Int"
                if mclass.name == "Int" then return "Long"
                if mclass.name == "Float" then return "Double"
                if mclass.name == "Byte" then return "Byte"
index 6791e5c..3385301 100644 (file)
@@ -161,10 +161,10 @@ redef class CCompilationUnit
 
                var h_file = "{base_name}.h"
                var guard = "{mmodule.c_name.to_upper}_NIT_H"
-               write_header_to_file(mmodule, "{compdir}/{h_file}", new Array[String], guard)
+               write_header_to_file(mmodule, "{compdir}/{h_file}", ["<stdint.h>"], guard)
 
                var c_file = "{base_name}.c"
-               write_body_to_file(mmodule, "{compdir}/{c_file}", ["<stdlib.h>", "<stdio.h>", "\"{h_file}\""])
+               write_body_to_file(mmodule, "{compdir}/{c_file}", ["<stdlib.h>", "<stdio.h>", "<stdint.h>", "\"{h_file}\""])
 
                files.add( "{compdir}/{c_file}" )
        end
index 885d794..f61b10a 100644 (file)
@@ -65,6 +65,14 @@ private class SimpleMiscVisitor
        do
                toolcontext.warning(node.hot_location, tag, msg)
        end
+
+       # Issue a warning if `sub` is a standalone `do` block.
+       fun check_do_expr(sub: nullable AExpr)
+       do
+               if sub isa ADoExpr then
+                       warning(sub, "useless-do", "Warning: superfluous `do` block.")
+               end
+       end
 end
 
 
@@ -143,6 +151,21 @@ redef class AWhileExpr
                else
                        n_expr.warn_parentheses(v)
                end
+               v.check_do_expr(n_block)
+       end
+end
+
+redef class ADoExpr
+       redef fun after_simple_misc(v)
+       do
+               v.check_do_expr(n_block)
+       end
+end
+
+redef class ALoopExpr
+       redef fun after_simple_misc(v)
+       do
+               v.check_do_expr(n_block)
        end
 end
 
@@ -150,6 +173,14 @@ redef class AForExpr
        redef fun after_simple_misc(v)
        do
                n_expr.warn_parentheses(v)
+               v.check_do_expr(n_block)
+       end
+end
+
+redef class AWithExpr
+       redef fun after_simple_misc(v)
+       do
+               v.check_do_expr(n_block)
        end
 end
 
index 0e6878b..d78ac71 100644 (file)
@@ -50,7 +50,9 @@ redef class ModelBuilder
                end
 
                var nit_dir = toolcontext.nit_dir
-               var libname = "{nit_dir}/lib"
+               var libname = nit_dir/"lib"
+               if libname.file_exists then paths.add(libname)
+               libname = nit_dir/"contrib"
                if libname.file_exists then paths.add(libname)
        end
 
@@ -222,6 +224,14 @@ redef class ModelBuilder
                                return res
                        end
 
+                       # Fourth, try if the requested module is itself a group with a src
+                       try_file = dirname + "/" + name + "/src/" + name + ".nit"
+                       if try_file.file_exists then
+                               var res = self.identify_file(try_file.simplify_path)
+                               assert res != null
+                               return res
+                       end
+
                        c = c.parent
                end
 
@@ -301,6 +311,19 @@ redef class ModelBuilder
                                        end
                                end
                        end
+                       try_file = (dirname + "/" + name + "/src/" + name + ".nit").simplify_path
+                       if try_file.file_exists then
+                               if candidate == null then
+                                       candidate = try_file
+                               else if candidate != try_file then
+                                       # try to disambiguate conflicting modules
+                                       var abs_candidate = module_absolute_path(candidate)
+                                       var abs_try_file = module_absolute_path(try_file)
+                                       if abs_candidate != abs_try_file then
+                                               toolcontext.error(location, "Error: conflicting module file for `{name}`: `{candidate}` `{try_file}`")
+                                       end
+                               end
+                       end
                end
                if candidate == null then return null
                return identify_file(candidate)
index e1f43cc..de71f37 100755 (executable)
@@ -3,7 +3,7 @@
 # Regeneration of c_src from the current nitc
 
 rm -r ../c_src
-./nitc nith.nit --stacktrace none --semi-global --compile-dir ../c_src --output ../c_src/nitg --no-cc
+./nitc nith.nit --semi-global --compile-dir ../c_src --output ../c_src/nitg --no-cc
 
 # Remove old compilation flags
 sed -i -e 's/OLDNITCOPT=.*/OLDNITCOPT=/' Makefile
index 7cf6bbc..f5cccc0 100644 (file)
@@ -71,14 +71,15 @@ redef class MType
 
        # Representation of this type in C for the internal of the system
        # Hides extern types.
-       fun cname_blind: String is abstract
+       fun cname_blind: String do return "struct nitni_instance *"
 
        # Representation of this type in mangled C
        #   Object -> Object
        #   Pointer -> Pointer
        fun mangled_cname: String is abstract
 
-       # Does this types has a primitive reprensentation
+       # Does this type have a primitive representation?
+       #
        #   type Object is_primitive? false
        #   type Pointer is_primitive? true
        fun is_cprimitive: Bool is abstract
@@ -89,11 +90,11 @@ redef class MClassType
        do
                var name = mclass.name
                if name == "Bool" then return "int"
-               if name == "Char" then return "char"
+               if name == "Char" then return "uint32_t"
                if name == "Float" then return "double"
                if name == "Int" then return "long"
                if name == "Byte" then return "unsigned char"
-               if name == "NativeString" then return "char*"
+               if name == "NativeString" then return "unsigned char*"
                if mclass.kind == extern_kind then
                        var ctype = mclass.ctype
                        assert ctype != null
@@ -105,13 +106,13 @@ redef class MClassType
        redef fun cname_blind do
                var name = mclass.name
                if name == "Bool" then return "int"
-               if name == "Char" then return "char"
+               if name == "Char" then return "uint32_t"
                if name == "Float" then return "double"
                if name == "Int" then return "long"
                if name == "Byte" then return "unsigned char"
-               if name == "NativeString" then return "char*"
+               if name == "NativeString" then return "unsigned char*"
                if mclass.kind == extern_kind then return "void*"
-               return "struct nitni_instance *"
+               return super
        end
 
        # Name of this type in C for normal classes (not extern and not primitive)
@@ -120,18 +121,17 @@ redef class MClassType
        redef fun mangled_cname do return mclass.name
 
        redef fun is_cprimitive do return mclass.kind == extern_kind or
-                       (once ["Bool", "Char", "Float", "Int", "NativeString"]).has(mclass.name)
+                       (once ["Bool", "Char", "Float", "Int", "NativeString", "Byte"]).has(mclass.name)
 end
 
 redef class MNullableType
        redef fun cname do return mangled_cname
-       redef fun cname_blind do return "struct nitni_instance *"
        redef fun mangled_cname do return "nullable_{mtype.mangled_cname}"
        redef fun is_cprimitive do return false
 end
 
 redef class MVirtualType
-       redef fun mangled_cname: String do return to_s
+       redef fun mangled_cname do return to_s
 end
 
 redef class MGenericType
index 769f05b..592cc42 100644 (file)
@@ -207,7 +207,7 @@ bytenum = digit+ 'u8';
 hex_bytenum = ('0x' | '0X') hexdigit+ 'u8';
 bin_bytenum = ('0b' | '0B') bindigit+ 'u8';
 oct_bytenum = ('0o' | '0O') octdigit+ 'u8';
-float = digit* '.' digit+;
+float = digit* '.' digit+ | (digit+ | digit* '.' digit+) ('E'|'e') ('+'|'-'|) digit+;
 string = '"' str_body '"' | '"' '"' '"' long_str_body lsend1 | ''' ''' ''' long_sstr_body ''' ''' ''';
 start_string = '"' str_body '{' | '"' '"' '"' long_str_body lsend2;
 mid_string = '}' str_body '{' | '}' '}' '}' long_str_body lsend2;
index 6ec146f..9131c3e 100644 (file)
@@ -311,6 +311,35 @@ abstract class Token
        # May have disappeared in the AST
        var next_token: nullable Token = null
 
+       # Is `self` a token discarded from the AST?
+       #
+       # Loose tokens are not present in the AST.
+       # It means they were identified by the lexer but were discarded by the parser.
+       # It also means that they are not visited or manipulated by AST-related functions.
+       #
+       # Each loose token is attached to the non-loose token that precedes or follows it.
+       # The rules are the following:
+       #
+       # * tokens that follow a non-loose token on a same line are attached to it.
+       #   See `next_looses`.
+       # * other tokens, thus that precede a non-loose token on the same line or the next one,
+       # are attached to this one. See `prev_looses`.
+       #
+       # Loose tokens are mostly end of lines (`TEol`) and comments (`TComment`).
+       # Whitespace are ignored by the lexer, so they are not even considered as loose tokens.
+       # See `blank_before` to get the whitespace that separate tokens.
+       var is_loose = false
+
+       # Loose tokens that precede `self`.
+       #
+       # These tokens start the line or belong to a line with only loose tokens.
+       var prev_looses = new Array[Token] is lazy
+
+       # Loose tokens that follow `self`
+       #
+       # These tokens are on the same line than `self`.
+       var next_looses = new Array[Token] is lazy
+
        # The verbatim blank text between `prev_token` and `self`
        fun blank_before: String
        do
index c2eff11..a344fc7 100644 (file)
@@ -141,7 +141,8 @@ class Parser
                                var node1 = pop
                                assert node1 isa AModule
                                var node = new Start(node1, node2)
-                               (new ComputeProdLocationVisitor).enter_visit(node)
+                               node2.parent = node
+                               (new ComputeProdLocationVisitor(lexer.file.first_token)).enter_visit(node)
                                return node
                        else if action_type == 3 then # ERROR
                                # skip injected tokens
@@ -176,21 +177,55 @@ end
 # Uses existing token locations to infer location of productions.
 private class ComputeProdLocationVisitor
        super Visitor
+
+       # The current (or starting) cursor on the token sequence used to collect loose tokens
+       var token: nullable Token
+
        # Currently visited productions that need a first token
        var need_first_prods = new Array[Prod]
 
        # Already visited epsilon productions that waits something after them
        var need_after_epsilons = new Array[Prod]
 
-       # Location of the last visited token in the current production
-       var last_location: nullable Location = null
+       # The last visited token in the current production
+       var last_token: nullable Token = null
 
        redef fun visit(n: ANode)
        do
                if n isa Token then
+                       # Skip injected tokens
                        if not isset n._location then return
+
+                       # Collect loose tokens (not in the AST) and attach them to token in the AST
+                       var cursor = token
+                       if n != cursor then
+                               var lt = last_token
+                               # In order, we have the tokens:
+                               # * `lt` the previous visited token in the AST (if any)
+                               # * then `cursor` the loose tokens to attach
+                               # * then `n` the current visited token in the AST
+
+                               # In the following, we advance `cursor` to add them to `lt.next_looses` or to `n.prev_looses`.
+                               if lt != null then
+                                       var ltl = lt.location.line_end
+                                       # floating tokens on the same line of a AST-token follows it
+                                       while cursor != null and cursor != n and ltl == cursor.location.line_start do
+                                               cursor.is_loose = true
+                                               lt.next_looses.add cursor
+                                               cursor = cursor.next_token
+                                       end
+                               end
+                               # other loose tokens precede the next AST-token
+                               while cursor != null and cursor != n do
+                                       cursor.is_loose = true
+                                       n.prev_looses.add cursor
+                                       cursor = cursor.next_token
+                               end
+                       end
+                       token = n.next_token
+
                        var loc = n._location
-                       _last_location = loc
+                       _last_token = n
 
                        # Add a first token to productions that need one
                        if not _need_first_prods.is_empty then
@@ -217,8 +252,7 @@ private class ComputeProdLocationVisitor
                        var startl = n._first_location
                        if startl != null then
                                # Non-epsilon production
-                               var endl = _last_location
-                               assert endl != null
+                               var endl = _last_token.location
 
                                if startl == endl then
                                        n.location = startl
index ce36ccc..4fd03ae 100644 (file)
@@ -140,254 +140,258 @@ static const int lexer_goto_row19[] = {
        61, 61, 75
 };
 static const int lexer_goto_row20[] = {
-       9,
+       11,
        46, 46, 76,
        48, 57, 20,
        66, 66, 77,
-       79, 79, 78,
-       88, 88, 79,
-       98, 98, 80,
-       111, 111, 81,
-       117, 117, 82,
-       120, 120, 83
+       69, 69, 78,
+       79, 79, 79,
+       88, 88, 80,
+       98, 98, 81,
+       101, 101, 82,
+       111, 111, 83,
+       117, 117, 84,
+       120, 120, 85
 };
 static const int lexer_goto_row21[] = {
-       2,
+       4,
        46, 57, -21,
-       117, 117, 82
+       69, 69, 78,
+       101, 101, 82,
+       117, 117, 84
 };
 static const int lexer_goto_row22[] = {
        1,
-       58, 58, 84
+       58, 58, 86
 };
 static const int lexer_goto_row24[] = {
        2,
-       60, 60, 85,
-       61, 61, 86
+       60, 60, 87,
+       61, 61, 88
 };
 static const int lexer_goto_row25[] = {
        1,
-       61, 61, 87
+       61, 61, 89
 };
 static const int lexer_goto_row26[] = {
        2,
-       61, 61, 88,
-       62, 62, 89
+       61, 61, 90,
+       62, 62, 91
 };
 static const int lexer_goto_row28[] = {
        4,
-       48, 57, 90,
-       65, 90, 91,
-       95, 95, 92,
-       97, 122, 93
+       48, 57, 92,
+       65, 90, 93,
+       95, 95, 94,
+       97, 122, 95
 };
 static const int lexer_goto_row31[] = {
        1,
-       61, 61, 94
+       61, 61, 96
 };
 static const int lexer_goto_row32[] = {
        2,
-       95, 95, 95,
-       97, 122, 96
+       95, 95, 97,
+       97, 122, 98
 };
 static const int lexer_goto_row33[] = {
        1,
-       123, 123, 97
+       123, 123, 99
 };
 static const int lexer_goto_row34[] = {
        10,
-       48, 57, 98,
-       65, 90, 99,
-       95, 95, 100,
-       97, 97, 101,
-       98, 98, 102,
-       99, 109, 101,
-       110, 110, 103,
-       111, 114, 101,
-       115, 115, 104,
-       116, 122, 101
+       48, 57, 100,
+       65, 90, 101,
+       95, 95, 102,
+       97, 97, 103,
+       98, 98, 104,
+       99, 109, 103,
+       110, 110, 105,
+       111, 114, 103,
+       115, 115, 106,
+       116, 122, 103
 };
 static const int lexer_goto_row35[] = {
        4,
        48, 95, -35,
-       97, 113, 101,
-       114, 114, 105,
-       115, 122, 101
+       97, 113, 103,
+       114, 114, 107,
+       115, 122, 103
 };
 static const int lexer_goto_row36[] = {
        6,
        48, 95, -35,
-       97, 107, 101,
-       108, 108, 106,
-       109, 110, 101,
-       111, 111, 107,
-       112, 122, 101
+       97, 107, 103,
+       108, 108, 108,
+       109, 110, 103,
+       111, 111, 109,
+       112, 122, 103
 };
 static const int lexer_goto_row37[] = {
        4,
        48, 95, -35,
-       97, 110, 101,
-       111, 111, 108,
-       112, 122, 101
+       97, 110, 103,
+       111, 111, 110,
+       112, 122, 103
 };
 static const int lexer_goto_row38[] = {
        7,
        48, 107, -37,
-       108, 108, 109,
-       109, 109, 101,
-       110, 110, 110,
-       111, 119, 101,
-       120, 120, 111,
-       121, 122, 101
+       108, 108, 111,
+       109, 109, 103,
+       110, 110, 112,
+       111, 119, 103,
+       120, 120, 113,
+       121, 122, 103
 };
 static const int lexer_goto_row39[] = {
        7,
        48, 95, -35,
-       97, 97, 112,
-       98, 110, 101,
-       111, 111, 113,
-       112, 116, 101,
-       117, 117, 114,
-       118, 122, 101
+       97, 97, 114,
+       98, 110, 103,
+       111, 111, 115,
+       112, 116, 103,
+       117, 117, 116,
+       118, 122, 103
 };
 static const int lexer_goto_row40[] = {
        2,
        48, 95, -35,
-       97, 122, 101
+       97, 122, 103
 };
 static const int lexer_goto_row41[] = {
        9,
        48, 95, -35,
-       97, 101, 101,
-       102, 102, 115,
-       103, 108, 101,
-       109, 109, 116,
-       110, 110, 117,
-       111, 114, 101,
-       115, 115, 118,
-       116, 122, 101
+       97, 101, 103,
+       102, 102, 117,
+       103, 108, 103,
+       109, 109, 118,
+       110, 110, 119,
+       111, 114, 103,
+       115, 115, 120,
+       116, 122, 103
 };
 static const int lexer_goto_row42[] = {
        5,
        48, 95, -35,
-       97, 97, 119,
-       98, 110, 101,
-       111, 111, 120,
-       112, 122, 101
+       97, 97, 121,
+       98, 110, 103,
+       111, 111, 122,
+       112, 122, 103
 };
 static const int lexer_goto_row43[] = {
        3,
        48, 110, -38,
-       111, 111, 121,
-       112, 122, 101
+       111, 111, 123,
+       112, 122, 103
 };
 static const int lexer_goto_row44[] = {
        8,
        48, 95, -35,
-       97, 100, 101,
-       101, 101, 122,
-       102, 110, 101,
-       111, 111, 123,
-       112, 116, 101,
-       117, 117, 124,
-       118, 122, 101
+       97, 100, 103,
+       101, 101, 124,
+       102, 110, 103,
+       111, 111, 125,
+       112, 116, 103,
+       117, 117, 126,
+       118, 122, 103
 };
 static const int lexer_goto_row45[] = {
        6,
        48, 95, -35,
-       97, 109, 101,
-       110, 110, 125,
-       111, 113, 101,
-       114, 114, 126,
-       115, 122, 101
+       97, 109, 103,
+       110, 110, 127,
+       111, 113, 103,
+       114, 114, 128,
+       115, 122, 103
 };
 static const int lexer_goto_row46[] = {
        7,
        48, 95, -35,
-       97, 97, 127,
-       98, 113, 101,
-       114, 114, 128,
-       115, 116, 101,
-       117, 117, 129,
-       118, 122, 101
+       97, 97, 129,
+       98, 113, 103,
+       114, 114, 130,
+       115, 116, 103,
+       117, 117, 131,
+       118, 122, 103
 };
 static const int lexer_goto_row47[] = {
        3,
        48, 100, -45,
-       101, 101, 130,
-       102, 122, 101
+       101, 101, 132,
+       102, 122, 103
 };
 static const int lexer_goto_row48[] = {
        5,
        48, 100, -45,
-       101, 101, 131,
-       102, 116, 101,
-       117, 117, 132,
-       118, 122, 101
+       101, 101, 133,
+       102, 116, 103,
+       117, 117, 134,
+       118, 122, 103
 };
 static const int lexer_goto_row49[] = {
        8,
        48, 95, -35,
-       97, 103, 101,
-       104, 104, 133,
-       105, 113, 101,
-       114, 114, 134,
-       115, 120, 101,
-       121, 121, 135,
-       122, 122, 101
+       97, 103, 103,
+       104, 104, 135,
+       105, 113, 103,
+       114, 114, 136,
+       115, 120, 103,
+       121, 121, 137,
+       122, 122, 103
 };
 static const int lexer_goto_row50[] = {
        3,
        48, 109, -46,
-       110, 110, 136,
-       111, 122, 101
+       110, 110, 138,
+       111, 122, 103
 };
 static const int lexer_goto_row51[] = {
        3,
        48, 95, -35,
-       97, 97, 137,
-       98, 122, 101
+       97, 97, 139,
+       98, 122, 103
 };
 static const int lexer_goto_row52[] = {
        4,
        48, 103, -50,
-       104, 104, 138,
-       105, 105, 139,
-       106, 122, 101
+       104, 104, 140,
+       105, 105, 141,
+       106, 122, 103
 };
 static const int lexer_goto_row53[] = {
        1,
-       61, 61, 140
+       61, 61, 142
 };
 static const int lexer_goto_row54[] = {
        11,
-       0, 9, 141,
-       11, 12, 141,
-       14, 33, 141,
-       34, 34, 142,
-       35, 91, 141,
-       92, 92, 143,
-       93, 122, 141,
-       123, 123, 144,
-       124, 124, 141,
-       125, 125, 145,
-       126, 255, 141
+       0, 9, 143,
+       11, 12, 143,
+       14, 33, 143,
+       34, 34, 144,
+       35, 91, 143,
+       92, 92, 145,
+       93, 122, 143,
+       123, 123, 146,
+       124, 124, 143,
+       125, 125, 147,
+       126, 255, 143
 };
 static const int lexer_goto_row58[] = {
        3,
        0, 33, -8,
-       34, 34, 146,
+       34, 34, 148,
        35, 255, -8
 };
 static const int lexer_goto_row59[] = {
        1,
-       34, 34, 147
+       34, 34, 149
 };
 static const int lexer_goto_row60[] = {
        3,
-       0, 9, 148,
-       11, 12, 148,
-       14, 255, 148
+       0, 9, 150,
+       11, 12, 150,
+       14, 255, 150
 };
 static const int lexer_goto_row62[] = {
        1,
@@ -395,33 +399,34 @@ static const int lexer_goto_row62[] = {
 };
 static const int lexer_goto_row64[] = {
        1,
-       10, 10, 149
+       10, 10, 151
 };
 static const int lexer_goto_row67[] = {
        1,
-       39, 39, 150
+       39, 39, 152
 };
 static const int lexer_goto_row68[] = {
        1,
-       39, 39, 151
+       39, 39, 153
 };
 static const int lexer_goto_row69[] = {
        3,
-       0, 9, 152,
-       11, 12, 152,
-       14, 255, 152
+       0, 9, 154,
+       11, 12, 154,
+       14, 255, 154
 };
 static const int lexer_goto_row70[] = {
        1,
-       61, 61, 153
+       61, 61, 155
 };
 static const int lexer_goto_row74[] = {
        1,
-       46, 46, 154
+       46, 46, 156
 };
 static const int lexer_goto_row75[] = {
-       1,
-       48, 57, 74
+       2,
+       48, 57, 74,
+       69, 101, -22
 };
 static const int lexer_goto_row77[] = {
        1,
@@ -429,57 +434,59 @@ static const int lexer_goto_row77[] = {
 };
 static const int lexer_goto_row78[] = {
        3,
-       48, 48, 155,
-       49, 49, 156,
-       95, 95, 157
+       48, 48, 157,
+       49, 49, 158,
+       95, 95, 159
 };
 static const int lexer_goto_row79[] = {
-       2,
-       48, 55, 158,
-       95, 95, 159
+       3,
+       43, 43, 160,
+       45, 45, 161,
+       48, 57, 162
 };
 static const int lexer_goto_row80[] = {
-       4,
-       48, 57, 160,
-       65, 70, 161,
-       95, 95, 162,
-       97, 102, 163
+       2,
+       48, 55, 163,
+       95, 95, 164
 };
 static const int lexer_goto_row81[] = {
-       1,
-       48, 95, -79
+       4,
+       48, 57, 165,
+       65, 70, 166,
+       95, 95, 167,
+       97, 102, 168
 };
 static const int lexer_goto_row82[] = {
        1,
-       48, 95, -80
+       48, 95, -79
 };
 static const int lexer_goto_row83[] = {
        1,
-       56, 56, 164
+       43, 57, -80
 };
 static const int lexer_goto_row84[] = {
        1,
-       48, 102, -81
+       48, 95, -81
 };
-static const int lexer_goto_row86[] = {
+static const int lexer_goto_row85[] = {
        1,
-       61, 61, 165
+       56, 56, 169
 };
-static const int lexer_goto_row87[] = {
+static const int lexer_goto_row86[] = {
        1,
-       62, 62, 166
+       48, 102, -82
 };
-static const int lexer_goto_row90[] = {
+static const int lexer_goto_row88[] = {
        1,
-       61, 61, 167
+       61, 61, 170
 };
-static const int lexer_goto_row91[] = {
+static const int lexer_goto_row89[] = {
        1,
-       48, 122, -29
+       62, 62, 171
 };
 static const int lexer_goto_row92[] = {
        1,
-       48, 122, -29
+       61, 61, 172
 };
 static const int lexer_goto_row93[] = {
        1,
@@ -489,817 +496,809 @@ static const int lexer_goto_row94[] = {
        1,
        48, 122, -29
 };
+static const int lexer_goto_row95[] = {
+       1,
+       48, 122, -29
+};
 static const int lexer_goto_row96[] = {
        1,
-       100, 100, 168
+       48, 122, -29
+};
+static const int lexer_goto_row98[] = {
+       1,
+       100, 100, 173
 };
-static const int lexer_goto_row97[] = {
+static const int lexer_goto_row99[] = {
        4,
-       48, 57, 169,
-       65, 90, 170,
-       95, 95, 171,
-       97, 122, 172
+       48, 57, 174,
+       65, 90, 175,
+       95, 95, 176,
+       97, 122, 177
 };
-static const int lexer_goto_row98[] = {
+static const int lexer_goto_row100[] = {
        5,
-       0, 91, 173,
-       92, 92, 174,
-       93, 95, 173,
-       96, 96, 175,
-       97, 255, 173
+       0, 91, 178,
+       92, 92, 179,
+       93, 95, 178,
+       96, 96, 180,
+       97, 255, 178
 };
-static const int lexer_goto_row99[] = {
+static const int lexer_goto_row101[] = {
        1,
        48, 122, -41
 };
-static const int lexer_goto_row100[] = {
+static const int lexer_goto_row102[] = {
        1,
        48, 122, -41
 };
-static const int lexer_goto_row101[] = {
+static const int lexer_goto_row103[] = {
        1,
        48, 122, -41
 };
-static const int lexer_goto_row102[] = {
+static const int lexer_goto_row104[] = {
        1,
        48, 122, -41
 };
-static const int lexer_goto_row103[] = {
+static const int lexer_goto_row105[] = {
        5,
        48, 110, -38,
-       111, 111, 176,
-       112, 114, 101,
-       115, 115, 177,
-       116, 122, 101
+       111, 111, 181,
+       112, 114, 103,
+       115, 115, 182,
+       116, 122, 103
 };
-static const int lexer_goto_row104[] = {
+static const int lexer_goto_row106[] = {
        4,
        48, 95, -35,
-       97, 99, 101,
-       100, 100, 178,
-       101, 122, 101
+       97, 99, 103,
+       100, 100, 183,
+       101, 122, 103
 };
-static const int lexer_goto_row105[] = {
+static const int lexer_goto_row107[] = {
        4,
        48, 95, -35,
-       97, 114, 101,
-       115, 115, 179,
-       116, 122, 101
+       97, 114, 103,
+       115, 115, 184,
+       116, 122, 103
 };
-static const int lexer_goto_row106[] = {
+static const int lexer_goto_row108[] = {
        3,
        48, 100, -45,
-       101, 101, 180,
-       102, 122, 101
+       101, 101, 185,
+       102, 122, 103
 };
-static const int lexer_goto_row107[] = {
+static const int lexer_goto_row109[] = {
        3,
        48, 95, -35,
-       97, 97, 181,
-       98, 122, 101
+       97, 97, 186,
+       98, 122, 103
 };
-static const int lexer_goto_row108[] = {
+static const int lexer_goto_row110[] = {
        3,
        48, 109, -46,
-       110, 110, 182,
-       111, 122, 101
+       110, 110, 187,
+       111, 122, 103
 };
-static const int lexer_goto_row109[] = {
+static const int lexer_goto_row111[] = {
        1,
        48, 122, -41
 };
-static const int lexer_goto_row110[] = {
+static const int lexer_goto_row112[] = {
        3,
-       48, 114, -106,
-       115, 115, 183,
-       116, 122, 101
+       48, 114, -108,
+       115, 115, 188,
+       116, 122, 103
 };
-static const int lexer_goto_row111[] = {
+static const int lexer_goto_row113[] = {
        5,
-       48, 99, -105,
-       100, 100, 184,
-       101, 116, 101,
-       117, 117, 185,
-       118, 122, 101
+       48, 99, -107,
+       100, 100, 189,
+       101, 116, 103,
+       117, 117, 190,
+       118, 122, 103
 };
-static const int lexer_goto_row112[] = {
+static const int lexer_goto_row114[] = {
        4,
        48, 95, -35,
-       97, 115, 101,
-       116, 116, 186,
-       117, 122, 101
+       97, 115, 103,
+       116, 116, 191,
+       117, 122, 103
 };
-static const int lexer_goto_row113[] = {
+static const int lexer_goto_row115[] = {
        3,
        48, 107, -37,
-       108, 108, 187,
-       109, 122, 101
+       108, 108, 192,
+       109, 122, 103
 };
-static const int lexer_goto_row114[] = {
+static const int lexer_goto_row116[] = {
        3,
        48, 113, -36,
-       114, 114, 188,
-       115, 122, 101
+       114, 114, 193,
+       115, 122, 103
 };
-static const int lexer_goto_row115[] = {
+static const int lexer_goto_row117[] = {
        3,
        48, 109, -46,
-       110, 110, 189,
-       111, 122, 101
+       110, 110, 194,
+       111, 122, 103
 };
-static const int lexer_goto_row116[] = {
+static const int lexer_goto_row118[] = {
        1,
        48, 122, -41
 };
-static const int lexer_goto_row117[] = {
+static const int lexer_goto_row119[] = {
        4,
        48, 95, -35,
-       97, 111, 101,
-       112, 112, 190,
-       113, 122, 101
+       97, 111, 103,
+       112, 112, 195,
+       113, 122, 103
 };
-static const int lexer_goto_row118[] = {
+static const int lexer_goto_row120[] = {
        6,
        48, 95, -35,
-       97, 104, 101,
-       105, 105, 191,
-       106, 115, 101,
-       116, 116, 192,
-       117, 122, 101
+       97, 104, 103,
+       105, 105, 196,
+       106, 115, 103,
+       116, 116, 197,
+       117, 122, 103
 };
-static const int lexer_goto_row119[] = {
+static const int lexer_goto_row121[] = {
        5,
        48, 95, -35,
-       97, 97, 193,
-       98, 114, 101,
-       115, 115, 194,
-       116, 122, 101
+       97, 97, 198,
+       98, 114, 103,
+       115, 115, 199,
+       116, 122, 103
 };
-static const int lexer_goto_row120[] = {
+static const int lexer_goto_row122[] = {
        3,
        48, 97, -35,
-       98, 98, 195,
-       99, 122, 101
+       98, 98, 200,
+       99, 122, 103
 };
-static const int lexer_goto_row121[] = {
+static const int lexer_goto_row123[] = {
        3,
        48, 110, -38,
-       111, 111, 196,
-       112, 122, 101
+       111, 111, 201,
+       112, 122, 103
 };
-static const int lexer_goto_row122[] = {
+static const int lexer_goto_row124[] = {
        3,
-       48, 99, -105,
-       100, 100, 197,
-       101, 122, 101
+       48, 99, -107,
+       100, 100, 202,
+       101, 122, 103
 };
-static const int lexer_goto_row123[] = {
+static const int lexer_goto_row125[] = {
        4,
        48, 95, -35,
-       97, 118, 101,
-       119, 119, 198,
-       120, 122, 101
+       97, 118, 103,
+       119, 119, 203,
+       120, 122, 103
 };
-static const int lexer_goto_row124[] = {
+static const int lexer_goto_row126[] = {
        3,
-       48, 115, -113,
-       116, 116, 199,
-       117, 122, 101
+       48, 115, -115,
+       116, 116, 204,
+       117, 122, 103
 };
-static const int lexer_goto_row125[] = {
+static const int lexer_goto_row127[] = {
        3,
        48, 107, -37,
-       108, 108, 200,
-       109, 122, 101
+       108, 108, 205,
+       109, 122, 103
 };
-static const int lexer_goto_row126[] = {
+static const int lexer_goto_row128[] = {
        4,
        48, 95, -35,
-       97, 98, 101,
-       99, 99, 201,
-       100, 122, 101
+       97, 98, 103,
+       99, 99, 206,
+       100, 122, 103
 };
-static const int lexer_goto_row127[] = {
+static const int lexer_goto_row129[] = {
        1,
        48, 122, -41
 };
-static const int lexer_goto_row128[] = {
-       3,
-       48, 98, -127,
-       99, 99, 202,
-       100, 122, 101
-};
-static const int lexer_goto_row129[] = {
-       5,
-       48, 104, -119,
-       105, 105, 203,
-       106, 110, 101,
-       111, 111, 204,
-       112, 122, 101
-};
 static const int lexer_goto_row130[] = {
        3,
-       48, 97, -35,
-       98, 98, 205,
-       99, 122, 101
+       48, 98, -129,
+       99, 99, 207,
+       100, 122, 103
 };
 static const int lexer_goto_row131[] = {
        5,
-       48, 99, -105,
-       100, 100, 206,
-       101, 115, 101,
-       116, 116, 207,
-       117, 122, 101
+       48, 104, -121,
+       105, 105, 208,
+       106, 110, 103,
+       111, 111, 209,
+       112, 122, 103
 };
 static const int lexer_goto_row132[] = {
        3,
-       48, 107, -37,
-       108, 108, 208,
-       109, 122, 101
+       48, 97, -35,
+       98, 98, 210,
+       99, 122, 103
 };
 static const int lexer_goto_row133[] = {
-       3,
-       48, 111, -118,
-       112, 112, 209,
-       113, 122, 101
+       5,
+       48, 99, -107,
+       100, 100, 211,
+       101, 115, 103,
+       116, 116, 212,
+       117, 122, 103
 };
 static const int lexer_goto_row134[] = {
        3,
-       48, 100, -45,
-       101, 101, 210,
-       102, 122, 101
+       48, 107, -37,
+       108, 108, 213,
+       109, 122, 103
 };
 static const int lexer_goto_row135[] = {
-       4,
-       48, 95, -35,
-       97, 116, 101,
-       117, 117, 211,
-       118, 122, 101
+       3,
+       48, 111, -120,
+       112, 112, 214,
+       113, 122, 103
 };
 static const int lexer_goto_row136[] = {
        3,
-       48, 111, -118,
-       112, 112, 212,
-       113, 122, 101
+       48, 100, -45,
+       101, 101, 215,
+       102, 122, 103
 };
 static const int lexer_goto_row137[] = {
-       3,
-       48, 104, -119,
-       105, 105, 213,
-       106, 122, 101
+       4,
+       48, 95, -35,
+       97, 116, 103,
+       117, 117, 216,
+       118, 122, 103
 };
 static const int lexer_goto_row138[] = {
        3,
-       48, 113, -36,
-       114, 114, 214,
-       115, 122, 101
+       48, 111, -120,
+       112, 112, 217,
+       113, 122, 103
 };
 static const int lexer_goto_row139[] = {
        3,
-       48, 104, -119,
-       105, 105, 215,
-       106, 122, 101
+       48, 104, -121,
+       105, 105, 218,
+       106, 122, 103
 };
 static const int lexer_goto_row140[] = {
        3,
-       48, 115, -113,
-       116, 116, 216,
-       117, 122, 101
+       48, 113, -36,
+       114, 114, 219,
+       115, 122, 103
+};
+static const int lexer_goto_row141[] = {
+       3,
+       48, 104, -121,
+       105, 105, 220,
+       106, 122, 103
 };
 static const int lexer_goto_row142[] = {
+       3,
+       48, 115, -115,
+       116, 116, 221,
+       117, 122, 103
+};
+static const int lexer_goto_row144[] = {
        2,
        0, 123, -55,
-       124, 255, 141
+       124, 255, 143
 };
-static const int lexer_goto_row144[] = {
+static const int lexer_goto_row146[] = {
        3,
-       0, 9, 217,
-       11, 12, 217,
-       14, 255, 217
+       0, 9, 222,
+       11, 12, 222,
+       14, 255, 222
 };
-static const int lexer_goto_row146[] = {
+static const int lexer_goto_row148[] = {
        3,
        0, 124, -55,
-       125, 125, 218,
-       126, 255, 141
+       125, 125, 223,
+       126, 255, 143
 };
-static const int lexer_goto_row148[] = {
+static const int lexer_goto_row150[] = {
        11,
-       0, 9, 219,
-       10, 10, 220,
-       11, 12, 219,
-       13, 13, 221,
-       14, 33, 219,
-       34, 34, 222,
-       35, 91, 219,
-       92, 92, 223,
-       93, 122, 219,
-       123, 123, 224,
-       124, 255, 219
-};
-static const int lexer_goto_row149[] = {
+       0, 9, 224,
+       10, 10, 225,
+       11, 12, 224,
+       13, 13, 226,
+       14, 33, 224,
+       34, 34, 227,
+       35, 91, 224,
+       92, 92, 228,
+       93, 122, 224,
+       123, 123, 229,
+       124, 255, 224
+};
+static const int lexer_goto_row151[] = {
        1,
        0, 255, -59
 };
-static const int lexer_goto_row152[] = {
+static const int lexer_goto_row154[] = {
        9,
-       0, 9, 225,
-       10, 10, 226,
-       11, 12, 225,
-       13, 13, 227,
-       14, 38, 225,
-       39, 39, 228,
-       40, 91, 225,
-       92, 92, 229,
-       93, 255, 225
+       0, 9, 230,
+       10, 10, 231,
+       11, 12, 230,
+       13, 13, 232,
+       14, 38, 230,
+       39, 39, 233,
+       40, 91, 230,
+       92, 92, 234,
+       93, 255, 230
 };
-static const int lexer_goto_row153[] = {
+static const int lexer_goto_row155[] = {
        1,
-       39, 39, 230
+       39, 39, 235
 };
-static const int lexer_goto_row156[] = {
+static const int lexer_goto_row158[] = {
        2,
        48, 95, -79,
-       117, 117, 231
-};
-static const int lexer_goto_row157[] = {
-       1,
-       48, 117, -157
-};
-static const int lexer_goto_row158[] = {
-       1,
-       48, 117, -157
+       117, 117, 236
 };
 static const int lexer_goto_row159[] = {
-       2,
-       48, 95, -80,
-       117, 117, 232
+       1,
+       48, 117, -159
 };
 static const int lexer_goto_row160[] = {
        1,
-       48, 117, -160
+       48, 117, -159
 };
 static const int lexer_goto_row161[] = {
-       2,
-       48, 102, -81,
-       117, 117, 233
+       1,
+       48, 57, 162
 };
 static const int lexer_goto_row162[] = {
        1,
-       48, 117, -162
+       48, 57, 162
 };
 static const int lexer_goto_row163[] = {
        1,
-       48, 117, -162
+       48, 57, 162
 };
 static const int lexer_goto_row164[] = {
-       1,
-       48, 117, -162
+       2,
+       48, 95, -81,
+       117, 117, 237
 };
-static const int lexer_goto_row169[] = {
+static const int lexer_goto_row165[] = {
        1,
-       101, 101, 234
+       48, 117, -165
 };
-static const int lexer_goto_row170[] = {
-       1,
-       48, 122, -98
+static const int lexer_goto_row166[] = {
+       2,
+       48, 102, -82,
+       117, 117, 238
 };
-static const int lexer_goto_row171[] = {
+static const int lexer_goto_row167[] = {
        1,
-       48, 122, -98
+       48, 117, -167
 };
-static const int lexer_goto_row172[] = {
+static const int lexer_goto_row168[] = {
        1,
-       48, 122, -98
+       48, 117, -167
 };
-static const int lexer_goto_row173[] = {
+static const int lexer_goto_row169[] = {
        1,
-       48, 122, -98
+       48, 117, -167
 };
 static const int lexer_goto_row174[] = {
        1,
-       0, 255, -99
+       101, 101, 239
 };
 static const int lexer_goto_row175[] = {
        1,
-       0, 255, 235
+       48, 122, -100
 };
 static const int lexer_goto_row176[] = {
-       3,
-       0, 124, 236,
-       125, 125, 237,
-       126, 255, 236
+       1,
+       48, 122, -100
 };
 static const int lexer_goto_row177[] = {
-       3,
-       48, 113, -36,
-       114, 114, 238,
-       115, 122, 101
+       1,
+       48, 122, -100
 };
 static const int lexer_goto_row178[] = {
-       3,
-       48, 115, -113,
-       116, 116, 239,
-       117, 122, 101
+       1,
+       48, 122, -100
 };
 static const int lexer_goto_row179[] = {
        1,
-       48, 122, -41
+       0, 255, -101
 };
 static const int lexer_goto_row180[] = {
-       3,
-       48, 100, -45,
-       101, 101, 240,
-       102, 122, 101
+       1,
+       0, 255, 240
 };
 static const int lexer_goto_row181[] = {
        3,
-       48, 95, -35,
-       97, 97, 241,
-       98, 122, 101
+       0, 124, 241,
+       125, 125, 242,
+       126, 255, 241
 };
 static const int lexer_goto_row182[] = {
        3,
-       48, 114, -106,
-       115, 115, 242,
-       116, 122, 101
+       48, 113, -36,
+       114, 114, 243,
+       115, 122, 103
 };
 static const int lexer_goto_row183[] = {
        3,
-       48, 115, -113,
-       116, 116, 243,
-       117, 122, 101
+       48, 115, -115,
+       116, 116, 244,
+       117, 122, 103
 };
 static const int lexer_goto_row184[] = {
-       3,
-       48, 100, -45,
-       101, 101, 244,
-       102, 122, 101
-};
-static const int lexer_goto_row185[] = {
        1,
        48, 122, -41
 };
+static const int lexer_goto_row185[] = {
+       3,
+       48, 100, -45,
+       101, 101, 245,
+       102, 122, 103
+};
 static const int lexer_goto_row186[] = {
-       4,
+       3,
        48, 95, -35,
-       97, 108, 101,
-       109, 109, 245,
-       110, 122, 101
+       97, 97, 246,
+       98, 122, 103
 };
 static const int lexer_goto_row187[] = {
        3,
-       48, 100, -45,
-       101, 101, 246,
-       102, 122, 101
+       48, 114, -108,
+       115, 115, 247,
+       116, 122, 103
 };
 static const int lexer_goto_row188[] = {
        3,
-       48, 114, -106,
-       115, 115, 247,
-       116, 122, 101
+       48, 115, -115,
+       116, 116, 248,
+       117, 122, 103
 };
 static const int lexer_goto_row189[] = {
-       1,
-       48, 122, -41
+       3,
+       48, 100, -45,
+       101, 101, 249,
+       102, 122, 103
 };
 static const int lexer_goto_row190[] = {
        1,
        48, 122, -41
 };
 static const int lexer_goto_row191[] = {
-       5,
-       48, 107, -37,
-       108, 108, 248,
-       109, 110, 101,
-       111, 111, 249,
-       112, 122, 101
+       4,
+       48, 95, -35,
+       97, 108, 103,
+       109, 109, 250,
+       110, 122, 103
 };
 static const int lexer_goto_row192[] = {
        3,
-       48, 115, -113,
-       116, 116, 250,
-       117, 122, 101
-};
-static const int lexer_goto_row193[] = {
-       5,
        48, 100, -45,
        101, 101, 251,
-       102, 113, 101,
-       114, 114, 252,
-       115, 122, 101
+       102, 122, 103
+};
+static const int lexer_goto_row193[] = {
+       3,
+       48, 114, -108,
+       115, 115, 252,
+       116, 122, 103
 };
 static const int lexer_goto_row194[] = {
        1,
        48, 122, -41
 };
 static const int lexer_goto_row195[] = {
-       3,
-       48, 100, -45,
-       101, 101, 253,
-       102, 122, 101
+       1,
+       48, 122, -41
 };
 static const int lexer_goto_row196[] = {
-       3,
-       48, 100, -45,
-       101, 101, 254,
-       102, 122, 101
+       5,
+       48, 107, -37,
+       108, 108, 253,
+       109, 110, 103,
+       111, 111, 254,
+       112, 122, 103
 };
 static const int lexer_goto_row197[] = {
        3,
-       48, 111, -118,
-       112, 112, 255,
-       113, 122, 101
+       48, 115, -115,
+       116, 116, 255,
+       117, 122, 103
 };
 static const int lexer_goto_row198[] = {
-       3,
-       48, 116, -136,
-       117, 117, 256,
-       118, 122, 101
+       5,
+       48, 100, -45,
+       101, 101, 256,
+       102, 113, 103,
+       114, 114, 257,
+       115, 122, 103
 };
 static const int lexer_goto_row199[] = {
        1,
        48, 122, -41
 };
 static const int lexer_goto_row200[] = {
-       1,
-       48, 122, -41
+       3,
+       48, 100, -45,
+       101, 101, 258,
+       102, 122, 103
 };
 static const int lexer_goto_row201[] = {
        3,
-       48, 107, -37,
-       108, 108, 257,
-       109, 122, 101
+       48, 100, -45,
+       101, 101, 259,
+       102, 122, 103
 };
 static const int lexer_goto_row202[] = {
        3,
-       48, 100, -45,
-       101, 101, 258,
-       102, 122, 101
+       48, 111, -120,
+       112, 112, 260,
+       113, 122, 103
 };
 static const int lexer_goto_row203[] = {
-       4,
-       48, 95, -35,
-       97, 106, 101,
-       107, 107, 259,
-       108, 122, 101
+       3,
+       48, 116, -138,
+       117, 117, 261,
+       118, 122, 103
 };
 static const int lexer_goto_row204[] = {
-       4,
-       48, 95, -35,
-       97, 117, 101,
-       118, 118, 260,
-       119, 122, 101
+       1,
+       48, 122, -41
 };
 static const int lexer_goto_row205[] = {
-       3,
-       48, 115, -113,
-       116, 116, 261,
-       117, 122, 101
+       1,
+       48, 122, -41
 };
 static const int lexer_goto_row206[] = {
        3,
        48, 107, -37,
        108, 108, 262,
-       109, 122, 101
+       109, 122, 103
 };
 static const int lexer_goto_row207[] = {
        3,
        48, 100, -45,
        101, 101, 263,
-       102, 122, 101
+       102, 122, 103
 };
 static const int lexer_goto_row208[] = {
-       3,
-       48, 116, -136,
-       117, 117, 264,
-       118, 122, 101
+       4,
+       48, 95, -35,
+       97, 106, 103,
+       107, 107, 264,
+       108, 122, 103
 };
 static const int lexer_goto_row209[] = {
-       3,
-       48, 101, -42,
-       102, 102, 265,
-       103, 122, 101
+       4,
+       48, 95, -35,
+       97, 117, 103,
+       118, 118, 265,
+       119, 122, 103
 };
 static const int lexer_goto_row210[] = {
        3,
-       48, 100, -45,
-       101, 101, 266,
-       102, 122, 101
+       48, 115, -115,
+       116, 116, 266,
+       117, 122, 103
 };
 static const int lexer_goto_row211[] = {
        3,
-       48, 109, -46,
-       110, 110, 267,
-       111, 122, 101
+       48, 107, -37,
+       108, 108, 267,
+       109, 122, 103
 };
 static const int lexer_goto_row212[] = {
        3,
        48, 100, -45,
        101, 101, 268,
-       102, 122, 101
+       102, 122, 103
 };
 static const int lexer_goto_row213[] = {
        3,
-       48, 100, -45,
-       101, 101, 269,
-       102, 122, 101
+       48, 116, -138,
+       117, 117, 269,
+       118, 122, 103
 };
 static const int lexer_goto_row214[] = {
        3,
-       48, 117, -205,
-       118, 118, 270,
-       119, 122, 101
+       48, 101, -42,
+       102, 102, 270,
+       103, 122, 103
 };
 static const int lexer_goto_row215[] = {
-       1,
-       48, 122, -41
+       3,
+       48, 100, -45,
+       101, 101, 271,
+       102, 122, 103
 };
 static const int lexer_goto_row216[] = {
        3,
-       48, 107, -37,
-       108, 108, 271,
-       109, 122, 101
+       48, 109, -46,
+       110, 110, 272,
+       111, 122, 103
 };
 static const int lexer_goto_row217[] = {
        3,
-       48, 103, -50,
-       104, 104, 272,
-       105, 122, 101
+       48, 100, -45,
+       101, 101, 273,
+       102, 122, 103
 };
 static const int lexer_goto_row218[] = {
-       1,
-       0, 255, -143
+       3,
+       48, 100, -45,
+       101, 101, 274,
+       102, 122, 103
 };
 static const int lexer_goto_row219[] = {
-       11,
-       0, 9, 273,
-       10, 10, 274,
-       11, 12, 273,
-       13, 13, 275,
-       14, 33, 273,
-       34, 34, 276,
-       35, 91, 273,
-       92, 92, 277,
-       93, 122, 273,
-       123, 123, 278,
-       124, 255, 273
+       3,
+       48, 117, -210,
+       118, 118, 275,
+       119, 122, 103
 };
 static const int lexer_goto_row220[] = {
        1,
-       0, 255, -149
+       48, 122, -41
 };
 static const int lexer_goto_row221[] = {
-       1,
-       0, 255, -149
+       3,
+       48, 107, -37,
+       108, 108, 276,
+       109, 122, 103
 };
 static const int lexer_goto_row222[] = {
-       1,
-       0, 255, -149
+       3,
+       48, 103, -50,
+       104, 104, 277,
+       105, 122, 103
 };
 static const int lexer_goto_row223[] = {
-       5,
-       0, 33, -149,
-       34, 34, 279,
-       35, 122, -149,
-       123, 123, 280,
-       124, 255, 219
+       1,
+       0, 255, -145
 };
 static const int lexer_goto_row224[] = {
-       3,
-       0, 9, 281,
-       11, 12, 281,
-       14, 255, 281
+       11,
+       0, 9, 278,
+       10, 10, 279,
+       11, 12, 278,
+       13, 13, 280,
+       14, 33, 278,
+       34, 34, 281,
+       35, 91, 278,
+       92, 92, 282,
+       93, 122, 278,
+       123, 123, 283,
+       124, 255, 278
 };
 static const int lexer_goto_row225[] = {
-       5,
-       0, 33, -149,
-       34, 34, 282,
-       35, 122, -149,
-       123, 123, 283,
-       124, 255, 219
+       1,
+       0, 255, -151
 };
 static const int lexer_goto_row226[] = {
        1,
-       0, 255, -153
+       0, 255, -151
 };
 static const int lexer_goto_row227[] = {
        1,
-       0, 255, -153
+       0, 255, -151
 };
 static const int lexer_goto_row228[] = {
-       1,
-       0, 255, -153
+       5,
+       0, 33, -151,
+       34, 34, 284,
+       35, 122, -151,
+       123, 123, 285,
+       124, 255, 224
 };
 static const int lexer_goto_row229[] = {
-       9,
-       0, 9, 284,
-       10, 10, 285,
-       11, 12, 284,
-       13, 13, 286,
-       14, 38, 284,
-       39, 39, 287,
-       40, 91, 284,
-       92, 92, 288,
-       93, 255, 284
+       3,
+       0, 9, 286,
+       11, 12, 286,
+       14, 255, 286
 };
 static const int lexer_goto_row230[] = {
-       3,
-       0, 9, 289,
-       11, 12, 289,
-       14, 255, 289
+       5,
+       0, 33, -151,
+       34, 34, 287,
+       35, 122, -151,
+       123, 123, 288,
+       124, 255, 224
+};
+static const int lexer_goto_row231[] = {
+       1,
+       0, 255, -155
 };
 static const int lexer_goto_row232[] = {
        1,
-       56, 56, 290
+       0, 255, -155
 };
 static const int lexer_goto_row233[] = {
        1,
-       56, 56, 291
+       0, 255, -155
 };
 static const int lexer_goto_row234[] = {
-       1,
-       56, 56, 292
+       9,
+       0, 9, 289,
+       10, 10, 290,
+       11, 12, 289,
+       13, 13, 291,
+       14, 38, 289,
+       39, 39, 292,
+       40, 91, 289,
+       92, 92, 293,
+       93, 255, 289
 };
 static const int lexer_goto_row235[] = {
-       1,
-       98, 98, 293
+       3,
+       0, 9, 294,
+       11, 12, 294,
+       14, 255, 294
 };
-static const int lexer_goto_row236[] = {
+static const int lexer_goto_row237[] = {
        1,
-       0, 255, -99
+       56, 56, 295
 };
-static const int lexer_goto_row237[] = {
+static const int lexer_goto_row238[] = {
        1,
-       0, 255, -99
+       56, 56, 296
 };
 static const int lexer_goto_row239[] = {
-       3,
-       48, 115, -113,
-       116, 116, 294,
-       117, 122, 101
+       1,
+       56, 56, 297
 };
 static const int lexer_goto_row240[] = {
-       3,
-       48, 113, -36,
-       114, 114, 295,
-       115, 122, 101
+       1,
+       98, 98, 298
 };
 static const int lexer_goto_row241[] = {
-       3,
-       48, 113, -36,
-       114, 114, 296,
-       115, 122, 101
+       1,
+       0, 255, -101
 };
 static const int lexer_goto_row242[] = {
-       3,
-       48, 106, -204,
-       107, 107, 297,
-       108, 122, 101
-};
-static const int lexer_goto_row243[] = {
-       3,
-       48, 114, -106,
-       115, 115, 298,
-       116, 122, 101
+       1,
+       0, 255, -101
 };
 static const int lexer_goto_row244[] = {
        3,
-       48, 104, -119,
-       105, 105, 299,
-       106, 122, 101
+       48, 115, -115,
+       116, 116, 299,
+       117, 122, 103
 };
 static const int lexer_goto_row245[] = {
-       1,
-       48, 122, -41
+       3,
+       48, 113, -36,
+       114, 114, 300,
+       115, 122, 103
 };
 static const int lexer_goto_row246[] = {
-       1,
-       48, 122, -41
+       3,
+       48, 113, -36,
+       114, 114, 301,
+       115, 122, 103
 };
 static const int lexer_goto_row247[] = {
        3,
-       48, 113, -36,
-       114, 114, 300,
-       115, 122, 101
+       48, 106, -209,
+       107, 107, 302,
+       108, 122, 103
 };
 static const int lexer_goto_row248[] = {
        3,
-       48, 100, -45,
-       101, 101, 301,
-       102, 122, 101
+       48, 114, -108,
+       115, 115, 303,
+       116, 122, 103
 };
 static const int lexer_goto_row249[] = {
        3,
-       48, 104, -119,
-       105, 105, 302,
-       106, 122, 101
+       48, 104, -121,
+       105, 105, 304,
+       106, 122, 103
 };
 static const int lexer_goto_row250[] = {
-       3,
-       48, 113, -36,
-       114, 114, 303,
-       115, 122, 101
+       1,
+       48, 122, -41
 };
 static const int lexer_goto_row251[] = {
        1,
@@ -1308,26 +1307,26 @@ static const int lexer_goto_row251[] = {
 static const int lexer_goto_row252[] = {
        3,
        48, 113, -36,
-       114, 114, 304,
-       115, 122, 101
+       114, 114, 305,
+       115, 122, 103
 };
 static const int lexer_goto_row253[] = {
        3,
-       48, 116, -136,
-       117, 117, 305,
-       118, 122, 101
+       48, 100, -45,
+       101, 101, 306,
+       102, 122, 103
 };
 static const int lexer_goto_row254[] = {
        3,
-       48, 115, -113,
-       116, 116, 306,
-       117, 122, 101
+       48, 104, -121,
+       105, 105, 307,
+       106, 122, 103
 };
 static const int lexer_goto_row255[] = {
        3,
-       48, 107, -37,
-       108, 108, 307,
-       109, 122, 101
+       48, 113, -36,
+       114, 114, 308,
+       115, 122, 103
 };
 static const int lexer_goto_row256[] = {
        1,
@@ -1335,466 +1334,468 @@ static const int lexer_goto_row256[] = {
 };
 static const int lexer_goto_row257[] = {
        3,
-       48, 107, -37,
-       108, 108, 308,
-       109, 122, 101
+       48, 113, -36,
+       114, 114, 309,
+       115, 122, 103
 };
 static const int lexer_goto_row258[] = {
        3,
-       48, 95, -35,
-       97, 97, 309,
-       98, 122, 101
+       48, 116, -138,
+       117, 117, 310,
+       118, 122, 103
 };
 static const int lexer_goto_row259[] = {
+       3,
+       48, 115, -115,
+       116, 116, 311,
+       117, 122, 103
+};
+static const int lexer_goto_row260[] = {
+       3,
+       48, 107, -37,
+       108, 108, 312,
+       109, 122, 103
+};
+static const int lexer_goto_row261[] = {
        1,
        48, 122, -41
 };
-static const int lexer_goto_row260[] = {
+static const int lexer_goto_row262[] = {
+       3,
+       48, 107, -37,
+       108, 108, 313,
+       109, 122, 103
+};
+static const int lexer_goto_row263[] = {
        3,
        48, 95, -35,
-       97, 97, 310,
-       98, 122, 101
+       97, 97, 314,
+       98, 122, 103
 };
-static const int lexer_goto_row261[] = {
+static const int lexer_goto_row264[] = {
+       1,
+       48, 122, -41
+};
+static const int lexer_goto_row265[] = {
        3,
        48, 95, -35,
-       97, 97, 311,
-       98, 122, 101
+       97, 97, 315,
+       98, 122, 103
 };
-static const int lexer_goto_row262[] = {
+static const int lexer_goto_row266[] = {
+       3,
+       48, 95, -35,
+       97, 97, 316,
+       98, 122, 103
+};
+static const int lexer_goto_row267[] = {
        3,
        48, 100, -45,
-       101, 101, 312,
-       102, 122, 101
+       101, 101, 317,
+       102, 122, 103
 };
-static const int lexer_goto_row263[] = {
+static const int lexer_goto_row268[] = {
        3,
-       48, 104, -119,
-       105, 105, 313,
-       106, 122, 101
+       48, 104, -121,
+       105, 105, 318,
+       106, 122, 103
 };
-static const int lexer_goto_row264[] = {
+static const int lexer_goto_row269[] = {
        3,
        48, 101, -42,
-       102, 102, 314,
-       103, 122, 101
+       102, 102, 319,
+       103, 122, 103
 };
-static const int lexer_goto_row265[] = {
+static const int lexer_goto_row270[] = {
        3,
        48, 113, -36,
-       114, 114, 315,
-       115, 122, 101
+       114, 114, 320,
+       115, 122, 103
 };
-static const int lexer_goto_row266[] = {
+static const int lexer_goto_row271[] = {
        1,
        48, 122, -41
 };
-static const int lexer_goto_row267[] = {
+static const int lexer_goto_row272[] = {
        3,
        48, 113, -36,
-       114, 114, 316,
-       115, 122, 101
+       114, 114, 321,
+       115, 122, 103
 };
-static const int lexer_goto_row268[] = {
+static const int lexer_goto_row273[] = {
        1,
        48, 122, -41
 };
-static const int lexer_goto_row269[] = {
+static const int lexer_goto_row274[] = {
        1,
        48, 122, -41
 };
-static const int lexer_goto_row270[] = {
+static const int lexer_goto_row275[] = {
        1,
        48, 122, -41
 };
-static const int lexer_goto_row271[] = {
+static const int lexer_goto_row276[] = {
        3,
        48, 100, -45,
-       101, 101, 317,
-       102, 122, 101
+       101, 101, 322,
+       102, 122, 103
 };
-static const int lexer_goto_row272[] = {
+static const int lexer_goto_row277[] = {
        3,
        48, 100, -45,
-       101, 101, 318,
-       102, 122, 101
+       101, 101, 323,
+       102, 122, 103
 };
-static const int lexer_goto_row273[] = {
+static const int lexer_goto_row278[] = {
        1,
        48, 122, -41
 };
-static const int lexer_goto_row274[] = {
+static const int lexer_goto_row279[] = {
        1,
-       0, 255, -220
+       0, 255, -225
 };
-static const int lexer_goto_row275[] = {
+static const int lexer_goto_row280[] = {
        11,
-       0, 9, 319,
-       10, 10, 274,
-       11, 12, 319,
-       13, 13, 275,
-       14, 33, 319,
-       34, 34, 320,
-       35, 91, 319,
-       92, 92, 321,
-       93, 122, 319,
-       123, 123, 322,
-       124, 255, 319
+       0, 9, 324,
+       10, 10, 279,
+       11, 12, 324,
+       13, 13, 280,
+       14, 33, 324,
+       34, 34, 325,
+       35, 91, 324,
+       92, 92, 326,
+       93, 122, 324,
+       123, 123, 327,
+       124, 255, 324
 };
-static const int lexer_goto_row276[] = {
+static const int lexer_goto_row281[] = {
        1,
-       0, 255, -276
+       0, 255, -281
 };
-static const int lexer_goto_row277[] = {
+static const int lexer_goto_row282[] = {
        5,
-       0, 33, -276,
-       34, 34, 323,
-       35, 122, -276,
-       123, 123, 324,
-       124, 255, 319
+       0, 33, -281,
+       34, 34, 328,
+       35, 122, -281,
+       123, 123, 329,
+       124, 255, 324
 };
-static const int lexer_goto_row278[] = {
+static const int lexer_goto_row283[] = {
        3,
-       0, 9, 325,
-       11, 12, 325,
-       14, 255, 325
+       0, 9, 330,
+       11, 12, 330,
+       14, 255, 330
 };
-static const int lexer_goto_row279[] = {
+static const int lexer_goto_row284[] = {
        5,
-       0, 33, -276,
-       34, 34, 326,
-       35, 122, -276,
-       123, 123, 327,
-       124, 255, 319
+       0, 33, -281,
+       34, 34, 331,
+       35, 122, -281,
+       123, 123, 332,
+       124, 255, 324
 };
-static const int lexer_goto_row280[] = {
+static const int lexer_goto_row285[] = {
        3,
-       0, 33, -149,
-       34, 34, 328,
-       35, 255, -224
+       0, 33, -151,
+       34, 34, 333,
+       35, 255, -229
 };
-static const int lexer_goto_row281[] = {
+static const int lexer_goto_row286[] = {
        3,
-       0, 122, -226,
-       123, 123, 329,
-       124, 255, 219
+       0, 122, -231,
+       123, 123, 334,
+       124, 255, 224
 };
-static const int lexer_goto_row282[] = {
+static const int lexer_goto_row287[] = {
        1,
-       0, 255, -149
+       0, 255, -151
 };
-static const int lexer_goto_row283[] = {
+static const int lexer_goto_row288[] = {
        3,
-       0, 33, -149,
-       34, 34, 330,
-       35, 255, -224
+       0, 33, -151,
+       34, 34, 335,
+       35, 255, -229
 };
-static const int lexer_goto_row284[] = {
+static const int lexer_goto_row289[] = {
        3,
-       0, 122, -226,
-       123, 123, 331,
-       124, 255, 219
+       0, 122, -231,
+       123, 123, 336,
+       124, 255, 224
 };
-static const int lexer_goto_row285[] = {
+static const int lexer_goto_row290[] = {
        1,
-       0, 255, -153
+       0, 255, -155
 };
-static const int lexer_goto_row286[] = {
+static const int lexer_goto_row291[] = {
        1,
-       0, 255, -153
+       0, 255, -155
 };
-static const int lexer_goto_row287[] = {
+static const int lexer_goto_row292[] = {
        1,
-       0, 255, -153
+       0, 255, -155
 };
-static const int lexer_goto_row288[] = {
+static const int lexer_goto_row293[] = {
        9,
-       0, 9, 332,
-       10, 10, 333,
-       11, 12, 332,
-       13, 13, 334,
-       14, 38, 332,
-       39, 39, 335,
-       40, 91, 332,
-       92, 92, 336,
-       93, 255, 332
-};
-static const int lexer_goto_row289[] = {
-       3,
        0, 9, 337,
+       10, 10, 338,
        11, 12, 337,
-       14, 255, 337
+       13, 13, 339,
+       14, 38, 337,
+       39, 39, 340,
+       40, 91, 337,
+       92, 92, 341,
+       93, 255, 337
 };
-static const int lexer_goto_row290[] = {
+static const int lexer_goto_row294[] = {
+       3,
+       0, 9, 342,
+       11, 12, 342,
+       14, 255, 342
+};
+static const int lexer_goto_row295[] = {
        1,
-       0, 255, -153
+       0, 255, -155
 };
-static const int lexer_goto_row294[] = {
+static const int lexer_goto_row299[] = {
        1,
-       117, 117, 338
+       117, 117, 343
 };
-static const int lexer_goto_row295[] = {
+static const int lexer_goto_row300[] = {
        1,
        48, 122, -41
 };
-static const int lexer_goto_row296[] = {
+static const int lexer_goto_row301[] = {
        3,
        48, 95, -35,
-       97, 97, 339,
-       98, 122, 101
+       97, 97, 344,
+       98, 122, 103
 };
-static const int lexer_goto_row297[] = {
+static const int lexer_goto_row302[] = {
        3,
-       48, 115, -113,
-       116, 116, 340,
-       117, 122, 101
+       48, 115, -115,
+       116, 116, 345,
+       117, 122, 103
 };
-static const int lexer_goto_row298[] = {
+static const int lexer_goto_row303[] = {
        1,
        48, 122, -41
 };
-static const int lexer_goto_row299[] = {
+static const int lexer_goto_row304[] = {
        1,
        48, 122, -41
 };
-static const int lexer_goto_row300[] = {
+static const int lexer_goto_row305[] = {
        3,
        48, 109, -46,
-       110, 110, 341,
-       111, 122, 101
+       110, 110, 346,
+       111, 122, 103
 };
-static const int lexer_goto_row301[] = {
+static const int lexer_goto_row306[] = {
        3,
        48, 109, -46,
-       110, 110, 342,
-       111, 122, 101
+       110, 110, 347,
+       111, 122, 103
 };
-static const int lexer_goto_row302[] = {
+static const int lexer_goto_row307[] = {
        1,
        48, 122, -41
 };
-static const int lexer_goto_row303[] = {
+static const int lexer_goto_row308[] = {
        3,
        48, 100, -45,
-       101, 101, 343,
-       102, 122, 101
+       101, 101, 348,
+       102, 122, 103
 };
-static const int lexer_goto_row304[] = {
+static const int lexer_goto_row309[] = {
        3,
-       48, 115, -113,
-       116, 116, 344,
-       117, 122, 101
+       48, 115, -115,
+       116, 116, 349,
+       117, 122, 103
 };
-static const int lexer_goto_row305[] = {
+static const int lexer_goto_row310[] = {
        3,
        48, 101, -42,
-       102, 102, 345,
-       103, 122, 101
+       102, 102, 350,
+       103, 122, 103
 };
-static const int lexer_goto_row306[] = {
+static const int lexer_goto_row311[] = {
        3,
-       48, 99, -105,
-       100, 100, 346,
-       101, 122, 101
+       48, 99, -107,
+       100, 100, 351,
+       101, 122, 103
 };
-static const int lexer_goto_row307[] = {
+static const int lexer_goto_row312[] = {
        1,
        48, 122, -41
 };
-static const int lexer_goto_row308[] = {
+static const int lexer_goto_row313[] = {
        1,
        48, 122, -41
 };
-static const int lexer_goto_row309[] = {
+static const int lexer_goto_row314[] = {
        3,
        48, 100, -45,
-       101, 101, 347,
-       102, 122, 101
+       101, 101, 352,
+       102, 122, 103
 };
-static const int lexer_goto_row310[] = {
+static const int lexer_goto_row315[] = {
        3,
        48, 97, -35,
-       98, 98, 348,
-       99, 122, 101
+       98, 98, 353,
+       99, 122, 103
 };
-static const int lexer_goto_row311[] = {
+static const int lexer_goto_row316[] = {
        4,
        48, 95, -35,
-       97, 102, 101,
-       103, 103, 349,
-       104, 122, 101
+       97, 102, 103,
+       103, 103, 354,
+       104, 122, 103
 };
-static const int lexer_goto_row312[] = {
+static const int lexer_goto_row317[] = {
        3,
-       48, 115, -113,
-       116, 116, 350,
-       117, 122, 101
+       48, 115, -115,
+       116, 116, 355,
+       117, 122, 103
 };
-static const int lexer_goto_row313[] = {
+static const int lexer_goto_row318[] = {
        3,
-       48, 98, -127,
-       99, 99, 351,
-       100, 122, 101
+       48, 98, -129,
+       99, 99, 356,
+       100, 122, 103
 };
-static const int lexer_goto_row314[] = {
+static const int lexer_goto_row319[] = {
        3,
-       48, 98, -127,
-       99, 99, 352,
-       100, 122, 101
+       48, 98, -129,
+       99, 99, 357,
+       100, 122, 103
 };
-static const int lexer_goto_row315[] = {
+static const int lexer_goto_row320[] = {
        1,
        48, 122, -41
 };
-static const int lexer_goto_row316[] = {
+static const int lexer_goto_row321[] = {
        3,
        48, 109, -46,
-       110, 110, 353,
-       111, 122, 101
+       110, 110, 358,
+       111, 122, 103
 };
-static const int lexer_goto_row317[] = {
+static const int lexer_goto_row322[] = {
        1,
        48, 122, -41
 };
-static const int lexer_goto_row318[] = {
+static const int lexer_goto_row323[] = {
        3,
        48, 113, -36,
-       114, 114, 354,
-       115, 122, 101
+       114, 114, 359,
+       115, 122, 103
 };
-static const int lexer_goto_row319[] = {
+static const int lexer_goto_row324[] = {
        1,
        48, 122, -41
 };
-static const int lexer_goto_row320[] = {
-       1,
-       0, 255, -276
-};
-static const int lexer_goto_row321[] = {
-       1,
-       0, 255, -278
-};
-static const int lexer_goto_row322[] = {
-       3,
-       0, 9, 355,
-       11, 12, 355,
-       14, 255, 355
-};
-static const int lexer_goto_row323[] = {
-       1,
-       0, 255, -280
-};
-static const int lexer_goto_row324[] = {
-       3,
-       0, 33, -276,
-       34, 34, 356,
-       35, 255, -278
-};
 static const int lexer_goto_row325[] = {
-       3,
-       0, 122, -280,
-       123, 123, 357,
-       124, 255, 319
+       1,
+       0, 255, -281
 };
 static const int lexer_goto_row326[] = {
        1,
-       0, 255, -220
+       0, 255, -283
 };
 static const int lexer_goto_row327[] = {
        3,
-       0, 33, -276,
-       34, 34, 358,
-       35, 255, -278
+       0, 9, 360,
+       11, 12, 360,
+       14, 255, 360
 };
 static const int lexer_goto_row328[] = {
-       3,
-       0, 122, -280,
-       123, 123, 359,
-       124, 255, 319
+       1,
+       0, 255, -285
 };
 static const int lexer_goto_row329[] = {
-       1,
-       34, 34, 360
+       3,
+       0, 33, -281,
+       34, 34, 361,
+       35, 255, -283
 };
 static const int lexer_goto_row330[] = {
-       1,
-       0, 255, -285
+       3,
+       0, 122, -285,
+       123, 123, 362,
+       124, 255, 324
 };
 static const int lexer_goto_row331[] = {
        1,
-       0, 255, -281
+       0, 255, -225
 };
 static const int lexer_goto_row332[] = {
-       1,
-       123, 123, 361
+       3,
+       0, 33, -281,
+       34, 34, 363,
+       35, 255, -283
 };
 static const int lexer_goto_row333[] = {
-       1,
-       0, 255, -153
+       3,
+       0, 122, -285,
+       123, 123, 364,
+       124, 255, 324
 };
 static const int lexer_goto_row334[] = {
        1,
-       0, 255, -153
+       34, 34, 365
 };
 static const int lexer_goto_row335[] = {
        1,
-       0, 255, -153
+       0, 255, -290
+};
+static const int lexer_goto_row336[] = {
+       1,
+       0, 255, -286
 };
 static const int lexer_goto_row337[] = {
-       3,
-       0, 9, 362,
-       11, 12, 362,
-       14, 255, 362
+       1,
+       123, 123, 366
 };
 static const int lexer_goto_row338[] = {
        1,
-       0, 255, -153
+       0, 255, -155
 };
 static const int lexer_goto_row339[] = {
        1,
-       103, 103, 363
+       0, 255, -155
 };
 static const int lexer_goto_row340[] = {
-       3,
-       48, 98, -127,
-       99, 99, 364,
-       100, 122, 101
-};
-static const int lexer_goto_row341[] = {
        1,
-       48, 122, -41
+       0, 255, -155
 };
 static const int lexer_goto_row342[] = {
        3,
-       48, 116, -136,
-       117, 117, 365,
-       118, 122, 101
+       0, 9, 367,
+       11, 12, 367,
+       14, 255, 367
 };
 static const int lexer_goto_row343[] = {
        1,
-       48, 122, -41
+       0, 255, -155
 };
 static const int lexer_goto_row344[] = {
-       3,
-       48, 114, -106,
-       115, 115, 366,
-       116, 122, 101
+       1,
+       103, 103, 368
 };
 static const int lexer_goto_row345[] = {
-       1,
-       48, 122, -41
+       3,
+       48, 98, -129,
+       99, 99, 369,
+       100, 122, 103
 };
 static const int lexer_goto_row346[] = {
-       3,
-       48, 95, -35,
-       97, 97, 367,
-       98, 122, 101
+       1,
+       48, 122, -41
 };
 static const int lexer_goto_row347[] = {
        3,
-       48, 100, -45,
-       101, 101, 368,
-       102, 122, 101
+       48, 116, -138,
+       117, 117, 370,
+       118, 122, 103
 };
 static const int lexer_goto_row348[] = {
        1,
@@ -1802,113 +1803,115 @@ static const int lexer_goto_row348[] = {
 };
 static const int lexer_goto_row349[] = {
        3,
-       48, 107, -37,
-       108, 108, 369,
-       109, 122, 101
+       48, 114, -108,
+       115, 115, 371,
+       116, 122, 103
 };
 static const int lexer_goto_row350[] = {
-       3,
-       48, 100, -45,
-       101, 101, 370,
-       102, 122, 101
+       1,
+       48, 122, -41
 };
 static const int lexer_goto_row351[] = {
        3,
-       48, 100, -45,
-       101, 101, 371,
-       102, 122, 101
+       48, 95, -35,
+       97, 97, 372,
+       98, 122, 103
 };
 static const int lexer_goto_row352[] = {
        3,
-       48, 115, -113,
-       116, 116, 372,
-       117, 122, 101
+       48, 100, -45,
+       101, 101, 373,
+       102, 122, 103
 };
 static const int lexer_goto_row353[] = {
        1,
        48, 122, -41
 };
 static const int lexer_goto_row354[] = {
-       1,
-       48, 122, -41
+       3,
+       48, 107, -37,
+       108, 108, 374,
+       109, 122, 103
 };
 static const int lexer_goto_row355[] = {
        3,
-       48, 114, -106,
-       115, 115, 373,
-       116, 122, 101
+       48, 100, -45,
+       101, 101, 375,
+       102, 122, 103
 };
 static const int lexer_goto_row356[] = {
-       1,
-       0, 255, -276
+       3,
+       48, 100, -45,
+       101, 101, 376,
+       102, 122, 103
 };
 static const int lexer_goto_row357[] = {
-       1,
-       34, 34, 374
+       3,
+       48, 115, -115,
+       116, 116, 377,
+       117, 122, 103
 };
 static const int lexer_goto_row358[] = {
        1,
-       0, 255, -329
+       48, 122, -41
 };
 static const int lexer_goto_row359[] = {
        1,
-       0, 255, -325
+       48, 122, -41
 };
 static const int lexer_goto_row360[] = {
-       1,
-       123, 123, 375
+       3,
+       48, 114, -108,
+       115, 115, 378,
+       116, 122, 103
 };
 static const int lexer_goto_row361[] = {
        1,
-       34, 34, 360
+       0, 255, -281
 };
 static const int lexer_goto_row362[] = {
        1,
-       123, 123, 361
+       34, 34, 379
 };
 static const int lexer_goto_row363[] = {
        1,
-       0, 255, -153
+       0, 255, -334
 };
 static const int lexer_goto_row364[] = {
        1,
-       95, 95, 376
+       0, 255, -330
 };
 static const int lexer_goto_row365[] = {
-       3,
-       48, 115, -113,
-       116, 116, 377,
-       117, 122, 101
+       1,
+       123, 123, 380
 };
 static const int lexer_goto_row366[] = {
-       3,
-       48, 100, -45,
-       101, 101, 378,
-       102, 122, 101
+       1,
+       34, 34, 365
 };
 static const int lexer_goto_row367[] = {
        1,
-       48, 122, -41
+       123, 123, 366
 };
 static const int lexer_goto_row368[] = {
-       3,
-       48, 98, -127,
-       99, 99, 379,
-       100, 122, 101
+       1,
+       0, 255, -155
 };
 static const int lexer_goto_row369[] = {
        1,
-       48, 122, -41
+       95, 95, 381
 };
 static const int lexer_goto_row370[] = {
        3,
-       48, 100, -45,
-       101, 101, 380,
-       102, 122, 101
+       48, 115, -115,
+       116, 116, 382,
+       117, 122, 103
 };
 static const int lexer_goto_row371[] = {
-       1,
-       48, 122, -41
+       3,
+       48, 100, -45,
+       101, 101, 383,
+       102, 122, 103
 };
 static const int lexer_goto_row372[] = {
        1,
@@ -1916,67 +1919,91 @@ static const int lexer_goto_row372[] = {
 };
 static const int lexer_goto_row373[] = {
        3,
-       48, 100, -45,
-       101, 101, 381,
-       102, 122, 101
+       48, 98, -129,
+       99, 99, 384,
+       100, 122, 103
 };
 static const int lexer_goto_row374[] = {
-       3,
-       48, 95, -35,
-       97, 97, 382,
-       98, 122, 101
+       1,
+       48, 122, -41
 };
 static const int lexer_goto_row375[] = {
-       1,
-       34, 34, 374
+       3,
+       48, 100, -45,
+       101, 101, 385,
+       102, 122, 103
 };
 static const int lexer_goto_row376[] = {
        1,
-       123, 123, 375
+       48, 122, -41
 };
 static const int lexer_goto_row377[] = {
        1,
-       95, 95, 383
+       48, 122, -41
 };
 static const int lexer_goto_row378[] = {
+       3,
+       48, 100, -45,
+       101, 101, 386,
+       102, 122, 103
+};
+static const int lexer_goto_row379[] = {
+       3,
+       48, 95, -35,
+       97, 97, 387,
+       98, 122, 103
+};
+static const int lexer_goto_row380[] = {
+       1,
+       34, 34, 379
+};
+static const int lexer_goto_row381[] = {
+       1,
+       123, 123, 380
+};
+static const int lexer_goto_row382[] = {
+       1,
+       95, 95, 388
+};
+static const int lexer_goto_row383[] = {
        1,
        48, 122, -41
 };
-static const int lexer_goto_row379[] = {
+static const int lexer_goto_row384[] = {
        1,
        48, 122, -41
 };
-static const int lexer_goto_row380[] = {
+static const int lexer_goto_row385[] = {
        3,
        48, 100, -45,
-       101, 101, 384,
-       102, 122, 101
+       101, 101, 389,
+       102, 122, 103
 };
-static const int lexer_goto_row381[] = {
+static const int lexer_goto_row386[] = {
        1,
        48, 122, -41
 };
-static const int lexer_goto_row382[] = {
+static const int lexer_goto_row387[] = {
        3,
-       48, 99, -105,
-       100, 100, 385,
-       101, 122, 101
+       48, 99, -107,
+       100, 100, 390,
+       101, 122, 103
 };
-static const int lexer_goto_row383[] = {
+static const int lexer_goto_row388[] = {
        3,
        48, 107, -37,
-       108, 108, 386,
-       109, 122, 101
+       108, 108, 391,
+       109, 122, 103
 };
-static const int lexer_goto_row385[] = {
+static const int lexer_goto_row390[] = {
        1,
        48, 122, -41
 };
-static const int lexer_goto_row386[] = {
+static const int lexer_goto_row391[] = {
        1,
        48, 122, -41
 };
-static const int lexer_goto_row387[] = {
+static const int lexer_goto_row392[] = {
        1,
        48, 122, -41
 };
@@ -2066,19 +2093,19 @@ const int* const lexer_goto_table[] = {
        lexer_goto_row82,
        lexer_goto_row83,
        lexer_goto_row84,
-       lexer_goto_row_null,
+       lexer_goto_row85,
        lexer_goto_row86,
-       lexer_goto_row87,
+       lexer_goto_row_null,
+       lexer_goto_row88,
+       lexer_goto_row89,
        lexer_goto_row_null,
        lexer_goto_row_null,
-       lexer_goto_row90,
-       lexer_goto_row91,
        lexer_goto_row92,
        lexer_goto_row93,
        lexer_goto_row94,
-       lexer_goto_row_null,
+       lexer_goto_row95,
        lexer_goto_row96,
-       lexer_goto_row97,
+       lexer_goto_row_null,
        lexer_goto_row98,
        lexer_goto_row99,
        lexer_goto_row100,
@@ -2122,7 +2149,7 @@ const int* const lexer_goto_table[] = {
        lexer_goto_row138,
        lexer_goto_row139,
        lexer_goto_row140,
-       lexer_goto_row_null,
+       lexer_goto_row141,
        lexer_goto_row142,
        lexer_goto_row_null,
        lexer_goto_row144,
@@ -2130,15 +2157,15 @@ const int* const lexer_goto_table[] = {
        lexer_goto_row146,
        lexer_goto_row_null,
        lexer_goto_row148,
-       lexer_goto_row149,
+       lexer_goto_row_null,
+       lexer_goto_row150,
+       lexer_goto_row151,
        lexer_goto_row_null,
        lexer_goto_row_null,
-       lexer_goto_row152,
-       lexer_goto_row153,
+       lexer_goto_row154,
+       lexer_goto_row155,
        lexer_goto_row_null,
        lexer_goto_row_null,
-       lexer_goto_row156,
-       lexer_goto_row157,
        lexer_goto_row158,
        lexer_goto_row159,
        lexer_goto_row160,
@@ -2146,15 +2173,15 @@ const int* const lexer_goto_table[] = {
        lexer_goto_row162,
        lexer_goto_row163,
        lexer_goto_row164,
+       lexer_goto_row165,
+       lexer_goto_row166,
+       lexer_goto_row167,
+       lexer_goto_row168,
+       lexer_goto_row169,
        lexer_goto_row_null,
        lexer_goto_row_null,
        lexer_goto_row_null,
        lexer_goto_row_null,
-       lexer_goto_row169,
-       lexer_goto_row170,
-       lexer_goto_row171,
-       lexer_goto_row172,
-       lexer_goto_row173,
        lexer_goto_row174,
        lexer_goto_row175,
        lexer_goto_row176,
@@ -2212,19 +2239,19 @@ const int* const lexer_goto_table[] = {
        lexer_goto_row228,
        lexer_goto_row229,
        lexer_goto_row230,
-       lexer_goto_row_null,
+       lexer_goto_row231,
        lexer_goto_row232,
        lexer_goto_row233,
        lexer_goto_row234,
        lexer_goto_row235,
-       lexer_goto_row236,
-       lexer_goto_row237,
        lexer_goto_row_null,
+       lexer_goto_row237,
+       lexer_goto_row238,
        lexer_goto_row239,
        lexer_goto_row240,
        lexer_goto_row241,
        lexer_goto_row242,
-       lexer_goto_row243,
+       lexer_goto_row_null,
        lexer_goto_row244,
        lexer_goto_row245,
        lexer_goto_row246,
@@ -2272,14 +2299,14 @@ const int* const lexer_goto_table[] = {
        lexer_goto_row288,
        lexer_goto_row289,
        lexer_goto_row290,
+       lexer_goto_row291,
+       lexer_goto_row292,
+       lexer_goto_row293,
+       lexer_goto_row294,
+       lexer_goto_row295,
        lexer_goto_row_null,
        lexer_goto_row_null,
        lexer_goto_row_null,
-       lexer_goto_row294,
-       lexer_goto_row295,
-       lexer_goto_row296,
-       lexer_goto_row297,
-       lexer_goto_row298,
        lexer_goto_row299,
        lexer_goto_row300,
        lexer_goto_row301,
@@ -2317,12 +2344,12 @@ const int* const lexer_goto_table[] = {
        lexer_goto_row333,
        lexer_goto_row334,
        lexer_goto_row335,
-       lexer_goto_row_null,
+       lexer_goto_row336,
        lexer_goto_row337,
        lexer_goto_row338,
        lexer_goto_row339,
        lexer_goto_row340,
-       lexer_goto_row341,
+       lexer_goto_row_null,
        lexer_goto_row342,
        lexer_goto_row343,
        lexer_goto_row344,
@@ -2365,14 +2392,19 @@ const int* const lexer_goto_table[] = {
        lexer_goto_row381,
        lexer_goto_row382,
        lexer_goto_row383,
-       lexer_goto_row_null,
+       lexer_goto_row384,
        lexer_goto_row385,
        lexer_goto_row386,
-       lexer_goto_row387
+       lexer_goto_row387,
+       lexer_goto_row388,
+       lexer_goto_row_null,
+       lexer_goto_row390,
+       lexer_goto_row391,
+       lexer_goto_row392
 };
 
 const int lexer_accept_table[] = {
-       -1,0,1,1,0,94,114,2,80,83,-1,53,54,77,75,57,76,74,79,100,100,58,96,87,60,90,95,97,55,56,82,-1,-1,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,81,114,84,1,86,114,109,-1,110,2,2,2,65,69,115,115,115,78,63,61,62,73,108,64,-1,-1,-1,-1,-1,-1,-1,-1,59,89,88,85,91,92,97,97,97,97,68,-1,99,-1,98,98,98,98,98,98,47,98,98,98,16,98,98,98,98,98,98,23,98,29,15,98,98,98,98,98,98,98,31,98,98,98,98,98,98,98,98,98,98,98,98,98,67,114,112,-1,111,114,109,114,114,2,113,114,115,66,72,102,102,102,103,103,101,101,101,101,104,70,93,71,-1,99,99,99,99,-1,-1,-1,98,98,30,98,98,98,98,98,10,98,98,98,28,11,98,98,98,40,98,98,98,98,39,32,98,98,98,98,98,98,98,98,98,98,98,98,98,98,17,98,98,114,114,114,114,114,-1,-1,-1,114,114,114,-1,-1,113,-1,-1,-1,-1,-1,-1,116,98,98,98,98,98,98,25,9,98,98,98,98,13,98,98,98,98,27,98,46,41,98,98,98,98,98,98,43,98,24,44,12,98,98,51,114,-1,-1,112,-1,111,-1,-1,114,-1,-1,114,114,114,-1,-1,114,106,107,105,-1,37,98,98,36,6,98,98,45,98,98,98,98,49,50,98,98,98,98,98,98,14,98,42,98,26,-1,-1,-1,-1,-1,-1,114,-1,-1,109,-1,-1,110,114,114,114,109,-1,114,-1,98,38,98,18,98,5,98,98,4,98,98,98,98,19,34,98,-1,112,-1,-1,111,109,110,114,-1,98,98,33,98,22,98,3,21,98,98,112,111,-1,7,35,98,48,98,98,52,8,20,9
+       -1,0,1,1,0,94,114,2,80,83,-1,53,54,77,75,57,76,74,79,100,100,58,96,87,60,90,95,97,55,56,82,-1,-1,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,81,114,84,1,86,114,109,-1,110,2,2,2,65,69,115,115,115,78,63,61,62,73,108,64,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,59,89,88,85,91,92,97,97,97,97,68,-1,99,-1,98,98,98,98,98,98,47,98,98,98,16,98,98,98,98,98,98,23,98,29,15,98,98,98,98,98,98,98,31,98,98,98,98,98,98,98,98,98,98,98,98,98,67,114,112,-1,111,114,109,114,114,2,113,114,115,66,72,102,102,102,-1,-1,108,103,103,101,101,101,101,104,70,93,71,-1,99,99,99,99,-1,-1,-1,98,98,30,98,98,98,98,98,10,98,98,98,28,11,98,98,98,40,98,98,98,98,39,32,98,98,98,98,98,98,98,98,98,98,98,98,98,98,17,98,98,114,114,114,114,114,-1,-1,-1,114,114,114,-1,-1,113,-1,-1,-1,-1,-1,-1,116,98,98,98,98,98,98,25,9,98,98,98,98,13,98,98,98,98,27,98,46,41,98,98,98,98,98,98,43,98,24,44,12,98,98,51,114,-1,-1,112,-1,111,-1,-1,114,-1,-1,114,114,114,-1,-1,114,106,107,105,-1,37,98,98,36,6,98,98,45,98,98,98,98,49,50,98,98,98,98,98,98,14,98,42,98,26,-1,-1,-1,-1,-1,-1,114,-1,-1,109,-1,-1,110,114,114,114,109,-1,114,-1,98,38,98,18,98,5,98,98,4,98,98,98,98,19,34,98,-1,112,-1,-1,111,109,110,114,-1,98,98,33,98,22,98,3,21,98,98,112,111,-1,7,35,98,48,98,98,52,8,20,9
 };
 
 static int parser_action_row1[] = {
index 5f0faf1..682d23e 100644 (file)
@@ -115,7 +115,6 @@ redef class ToolContext
                                phase.process_nmodule(nmodule)
                                if errcount != self.error_count then
                                        self.check_errors
-                                       break
                                end
                                errcount = self.error_count
                                for nclassdef in nmodule.n_classdefs do
@@ -128,7 +127,6 @@ redef class ToolContext
                                end
                                if errcount != self.error_count then
                                        self.check_errors
-                                       break
                                end
                                for na in vannot.annotations do
                                        var p = na.parent
@@ -138,7 +136,6 @@ redef class ToolContext
                                end
                                if errcount != self.error_count then
                                        self.check_errors
-                                       break
                                end
                        end
                        self.check_errors
index a87bc94..9010dde 100644 (file)
@@ -218,13 +218,16 @@ class RapidTypeAnalysis
                while not todo.is_empty do
                        var mmethoddef = todo.shift
                        var mmeth = mmethoddef.mproperty
+                       var msignature = mmethoddef.msignature
+                       if msignature == null then continue # Skip broken method
+
                        #print "# visit {mmethoddef}"
                        var v = new RapidTypeVisitor(self, mmethoddef.mclassdef.bound_mtype, mmethoddef)
 
-                       var vararg_rank = mmethoddef.msignature.vararg_rank
+                       var vararg_rank = msignature.vararg_rank
                        if vararg_rank > -1 then
                                var node = self.modelbuilder.mpropdef2node(mmethoddef)
-                               var elttype = mmethoddef.msignature.mparameters[vararg_rank].mtype
+                               var elttype = msignature.mparameters[vararg_rank].mtype
                                #elttype = elttype.anchor_to(self.mainmodule, v.receiver)
                                var vararg = self.mainmodule.array_type(elttype)
                                v.add_type(vararg)
@@ -234,7 +237,7 @@ class RapidTypeAnalysis
                        end
 
                        # TODO? new_msignature
-                       var sig = mmethoddef.msignature.as(not null)
+                       var sig = msignature
                        var osig = mmeth.intro.msignature.as(not null)
                        for i in [0..sig.arity[ do
                                var origtype = osig.mparameters[i].mtype
@@ -255,7 +258,7 @@ class RapidTypeAnalysis
                                continue
                        else if mmethoddef.constant_value != null then
                                # Make the return type live
-                               v.add_type(mmethoddef.msignature.return_mtype.as(MClassType))
+                               v.add_type(msignature.return_mtype.as(MClassType))
                                continue
                        else if npropdef == null then
                                abort
@@ -275,7 +278,7 @@ class RapidTypeAnalysis
 
                        if mmethoddef.is_intern or mmethoddef.is_extern then
                                # UGLY: We force the "instantation" of the concrete return type if any
-                               var ret = mmethoddef.msignature.return_mtype
+                               var ret = msignature.return_mtype
                                if ret != null and ret isa MClassType and ret.mclass.kind != abstract_kind and ret.mclass.kind != interface_kind then
                                        v.add_type(ret)
                                end
@@ -297,10 +300,10 @@ class RapidTypeAnalysis
                                if not ot.can_resolve_for(t, t, mainmodule) then continue
                                var rt = ot.anchor_to(mainmodule, t)
                                if live_types.has(rt) then continue
+                               if not check_depth(rt) then continue
                                #print "{ot}/{t} -> {rt}"
                                live_types.add(rt)
                                todo_types.add(rt)
-                               check_depth(rt)
                        end
                end
                #print "MType {live_types.length}: {live_types.join(", ")}"
@@ -318,12 +321,14 @@ class RapidTypeAnalysis
                #print "cast MType {live_cast_types.length}: {live_cast_types.join(", ")}"
        end
 
-       private fun check_depth(mtype: MClassType)
+       private fun check_depth(mtype: MClassType): Bool
        do
                var d = mtype.length
                if d > 255 then
                        self.modelbuilder.toolcontext.fatal_error(null, "Fatal Error: limitation in the rapidtype analysis engine: a type depth of {d} is too important, the problematic type is `{mtype}`.")
+                       return false
                end
+               return true
        end
 
        fun add_new(recv: MClassType, mtype: MClassType)
@@ -450,10 +455,14 @@ class RapidTypeVisitor
 
        redef fun visit(n)
        do
-               n.accept_rapid_type_visitor(self)
                if n isa AExpr then
-                       var implicit_cast_to = n.implicit_cast_to
-                       if implicit_cast_to != null then self.add_cast_type(implicit_cast_to)
+                       if n.mtype != null or n.is_typed then
+                               n.accept_rapid_type_visitor(self)
+                               var implicit_cast_to = n.implicit_cast_to
+                               if implicit_cast_to != null then self.add_cast_type(implicit_cast_to)
+                       end
+               else
+                       n.accept_rapid_type_visitor(self)
                end
 
                # RTA does not enter in AAnnotations
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 9676168..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`
@@ -960,7 +960,7 @@ redef class AVarReassignExpr
 
                v.set_variable(self, variable, rettype)
 
-               self.is_typed = true
+               self.is_typed = rettype != null
        end
 end
 
@@ -1006,9 +1006,11 @@ redef class AReturnExpr
                        else
                                v.visit_expr(nexpr)
                                v.error(nexpr, "Error: `return` with value in a procedure.")
+                               return
                        end
                else if ret_type != null then
                        v.error(self, "Error: `return` without value in a function.")
+                       return
                end
                self.is_typed = true
        end
@@ -2061,7 +2063,7 @@ redef class AAttrAssignExpr
                var mtype = self.attr_type
 
                v.visit_expr_subtype(self.n_value, mtype)
-               self.is_typed = true
+               self.is_typed = mtype != null
        end
 end
 
@@ -2072,9 +2074,9 @@ redef class AAttrReassignExpr
                var mtype = self.attr_type
                if mtype == null then return # Skip error
 
-               self.resolve_reassignment(v, mtype, mtype)
+               var rettype = self.resolve_reassignment(v, mtype, mtype)
 
-               self.is_typed = true
+               self.is_typed = rettype != null
        end
 end
 
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
index ebe2c73..838b9bc 100644 (file)
@@ -104,7 +104,12 @@ redef class AExpr
                        var nadd = v.builder.make_call(recv, na.push_callsite.as(not null), [self])
                        place.replace_with(nadd)
                end
-               super
+
+               visit_all(v)
+
+               if mtype == null and not is_typed then return # Skip broken
+
+               accept_transform_visitor(v)
        end
 
        redef fun replace_with(other)
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 33f4c8d..42e331a 100644 (file)
@@ -27,4 +27,5 @@ while t2 != null do
                t2 = t2.next #alt2# t2 = null
        end
        #alt3#t2 = t2.next
+       #alt3#exit(0)
 end
index cfbb80f..e342e07 100644 (file)
@@ -48,6 +48,6 @@ loop
        if i != null then
                bar(i)
        else
-               break #alt4#
+               break #alt4# exit(0)
        end
 end
diff --git a/tests/base_do_block.nit b/tests/base_do_block.nit
new file mode 100644 (file)
index 0000000..b9fdad4
--- /dev/null
@@ -0,0 +1,41 @@
+# 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.
+
+class Foo
+       fun start do end
+       fun finish do end
+end
+fun foo: Foo do return new Foo
+
+do do
+       1.output
+end
+while false do do
+       2.output
+end
+if true then do
+       3.output
+end else do
+       4.output
+end
+for i in [0..1] do do
+       5.output
+end
+with foo do do
+       6.output
+end
+loop do
+       7.output
+       return
+end
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
diff --git a/tests/sav/base_do_block.res b/tests/sav/base_do_block.res
new file mode 100644 (file)
index 0000000..f99d451
--- /dev/null
@@ -0,0 +1,11 @@
+base_do_block.nit:21,4--23,3: Warning: superfluous `do` block.
+base_do_block.nit:24,16--26,3: Warning: superfluous `do` block.
+base_do_block.nit:32,20--34,3: Warning: superfluous `do` block.
+base_do_block.nit:35,13--37,3: Warning: superfluous `do` block.
+base_do_block.nit:38,6--41,3: Warning: superfluous `do` block.
+1
+3
+5
+5
+6
+7
index 4fcab0a..debc62f 100644 (file)
@@ -1 +1 @@
-alt/base_import_alt3.nit:1,8--21: Error: cannot find module `fail` from `project1`. Tried: ., ../lib/standard, ../lib/standard/collection, alt, ../lib.
+alt/base_import_alt3.nit:1,8--21: Error: cannot find module `fail` from `project1`. Tried: ., ../lib/standard, ../lib/standard/collection, alt, ../lib, ../contrib.
index 20bc8ca..29ce68b 100644 (file)
@@ -1 +1 @@
-error_mod_unk.nit:17,8--11: Error: cannot find module `dfgd` from `error_mod_unk`. Tried: ., ../lib/standard, ../lib/standard/collection, alt, ../lib.
+error_mod_unk.nit:17,8--11: Error: cannot find module `dfgd` from `error_mod_unk`. Tried: ., ../lib/standard, ../lib/standard/collection, alt, ../lib, ../contrib.
index 0d6a211..a732359 100644 (file)
@@ -1457,7 +1457,7 @@ Edge
 8:MPropDef
 13:MAttributeDef
 =properties=JsonObject(5):
-{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:25,1---1,1","visibility":"public","name":"THE_ANSWER","mdoc":["\u000e2\u00080\u0009cAnswer to the Ultimate Question of Life, the Universe, and Everything.","\u000e2\u00080\u0009c"],"is_intro":true}
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:25,1---1,1","visibility":"public","name":"THE_ANSWER","mdoc":["“Answer to the Ultimate Question of Life, the Universe, and Everything.","“"],"is_intro":true}
 ----
 =to=Entity#0:
 =labels=Array(4):
@@ -1481,7 +1481,7 @@ Edge
 8:MPropDef
 13:MAttributeDef
 =properties=JsonObject(5):
-{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:25,1---1,1","visibility":"public","name":"THE_ANSWER","mdoc":["\u000e2\u00080\u0009cAnswer to the Ultimate Question of Life, the Universe, and Everything.","\u000e2\u00080\u0009c"],"is_intro":true}
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:25,1---1,1","visibility":"public","name":"THE_ANSWER","mdoc":["“Answer to the Ultimate Question of Life, the Universe, and Everything.","“"],"is_intro":true}
 ----
 =to=Entity#0:
 =labels=Array(4):
@@ -1722,7 +1722,7 @@ Edge
 8:MPropDef
 13:MAttributeDef
 =properties=JsonObject(5):
-{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:25,1---1,1","visibility":"public","name":"THE_ANSWER","mdoc":["\u000e2\u00080\u0009cAnswer to the Ultimate Question of Life, the Universe, and Everything.","\u000e2\u00080\u0009c"],"is_intro":true}
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:25,1---1,1","visibility":"public","name":"THE_ANSWER","mdoc":["“Answer to the Ultimate Question of Life, the Universe, and Everything.","“"],"is_intro":true}
 
 
 Edge
index 70cda4d..5e63fb7 100644 (file)
@@ -1457,7 +1457,7 @@ Edge
 8:MPropDef
 13:MAttributeDef
 =properties=JsonObject(5):
-{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:25,1---1,1","visibility":"public","name":"THE_ANSWER","mdoc":["\u000e2\u00080\u0009cAnswer to the Ultimate Question of Life, the Universe, and Everything.","\u000e2\u00080\u0009c"],"is_intro":true}
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:25,1---1,1","visibility":"public","name":"THE_ANSWER","mdoc":["“Answer to the Ultimate Question of Life, the Universe, and Everything.","“"],"is_intro":true}
 ----
 =to=Entity#0:
 =labels=Array(4):
@@ -1481,7 +1481,7 @@ Edge
 8:MPropDef
 13:MAttributeDef
 =properties=JsonObject(5):
-{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:25,1---1,1","visibility":"public","name":"THE_ANSWER","mdoc":["\u000e2\u00080\u0009cAnswer to the Ultimate Question of Life, the Universe, and Everything.","\u000e2\u00080\u0009c"],"is_intro":true}
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:25,1---1,1","visibility":"public","name":"THE_ANSWER","mdoc":["“Answer to the Ultimate Question of Life, the Universe, and Everything.","“"],"is_intro":true}
 ----
 =to=Entity#0:
 =labels=Array(4):
@@ -1722,7 +1722,7 @@ Edge
 8:MPropDef
 13:MAttributeDef
 =properties=JsonObject(5):
-{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:25,1---1,1","visibility":"public","name":"THE_ANSWER","mdoc":["\u000e2\u00080\u0009cAnswer to the Ultimate Question of Life, the Universe, and Everything.","\u000e2\u00080\u0009c"],"is_intro":true}
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:25,1---1,1","visibility":"public","name":"THE_ANSWER","mdoc":["“Answer to the Ultimate Question of Life, the Universe, and Everything.","“"],"is_intro":true}
 
 
 Edge
index cd932ee..feaed3f 100644 (file)
@@ -5,3 +5,9 @@
 12.346
 12.3
 12
+0.5
+0.000
+0.000003125
+3410.0
+400.0
+10.0
diff --git a/tests/sav/test_keep_going.res b/tests/sav/test_keep_going.res
new file mode 100644 (file)
index 0000000..346b309
--- /dev/null
@@ -0,0 +1 @@
+test_keep_going.nit:15,11--14: Error: class `Fail` not found in module `test_keep_going`.
index 112bdb0..64d374b 100644 (file)
@@ -1,3 +1,2 @@
-../examples/nitcorn/src/xymus_net.nit:24,8--14: Error: cannot find module `tnitter` from `nitcorn`. Tried: alt, ../lib, ../examples/nitcorn.
-../examples/nitcorn/src/xymus_net.nit:25,8--26: Error: cannot find module `benitlux_controller` from `nitcorn`. Tried: alt, ../lib, ../examples/nitcorn.
-../examples/nitcorn/src/xymus_net.nit:26,8--29: Error: cannot find module `opportunity_controller` from `nitcorn`. Tried: alt, ../lib, ../examples/nitcorn.
+../examples/nitcorn/src/xymus_net.nit:25,8--26: Error: cannot find module `benitlux_controller` from `nitcorn`. Tried: alt, ../lib, ../contrib, ../examples/nitcorn.
+../examples/nitcorn/src/xymus_net.nit:26,8--29: Error: cannot find module `opportunity_controller` from `nitcorn`. Tried: alt, ../lib, ../contrib, ../examples/nitcorn.
index ffac1cd..2295927 100644 (file)
@@ -1,7 +1,5 @@
 # This file is part of NIT ( http://www.nitlanguage.org ).
 #
-# Copyright 2011-2013 Alexis Laferrière <alexis.laf@xymus.net>
-#
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
 # You may obtain a copy of the License at
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-fun opposite( v : Bool ) : Bool `{
+fun opposite(v: Bool): Bool `{
        return v == 0;
 `}
-fun plus_10( v : Char ) : Char `{
+
+fun plus_10(v: Char): Char `{
        return v + 10;
 `}
-fun plus_1000( v : Int ) : Int `{
+
+fun plus_1000(v: Int): Int `{
        return v + 1000;
 `}
-fun multiply_by_100( v : Float ) : Float `{
+
+fun multiply_by_100(v: Float): Float `{
        return v * 100;
 `}
-fun print_ns( s : NativeString ) `{
-       printf( "%s\n", s );
+
+fun plus_0x10(v: Byte): Byte `{
+       return v + 0x10;
+`}
+
+fun print_ns(s: NativeString) `{
+       printf("%s\n", s);
 `}
 
-print opposite( true )
-print opposite( false )
+print opposite(true)
+print opposite(false)
+
+print plus_10('a')
 
-print plus_10( 'a' )
+print plus_1000(1234)
 
-print plus_1000( 1234 )
+print multiply_by_100(123.45)
 
-print multiply_by_100( 123.45 )
+print plus_0x10(0x2u8)
 
-print_ns( "hello world".to_cstring )
+print_ns("hello world".to_cstring)
index 76c1172..16375e3 100644 (file)
@@ -17,7 +17,7 @@ in "C++ Header" `{
 `}
 
 fun print_a(str: String) import String.to_cstring in "C++" `{
-       puts(String_to_cstring(str));
+       puts(reinterpret_cast<char*>(String_to_cstring(str)));
 `}
 
 print_a "Hello from `a`."
index 01eb25c..e4631dc 100644 (file)
@@ -19,7 +19,7 @@ in "C++ header" `{
 `}
 
 fun print_b(str: String) import String.to_cstring in "C++" `{
-       puts(String_to_cstring(str));
+       puts(reinterpret_cast<char*>(String_to_cstring(str)));
 `}
 
 print_a "Hello from `a`."
index 387c312..a997f01 100644 (file)
@@ -23,3 +23,14 @@ print(f.to_s)
 print(f.to_precision(3))
 print(f.to_precision(1))
 print(f.to_precision(0))
+f = 5.0e-1
+print(f)
+f = 3.125e-6
+print(f.to_precision(3))
+print(f.to_precision(9))
+f = 3.41e3
+print f
+f = 4e2
+print f
+f = .1e2
+print f
diff --git a/tests/test_keep_going.nit b/tests/test_keep_going.nit
new file mode 100755 (executable)
index 0000000..b3bedaa
--- /dev/null
@@ -0,0 +1,47 @@
+# 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.
+
+fun plop: Fail
+do
+       print 1
+end
+
+1.output
+if false then
+       plop
+end
+2.output
+if false then
+       fail
+end
+3.output
+if false then
+       var x = new Fail
+       x.output
+end
+4.output
+if false then
+       if 1 then abort
+end
+5.output
+if false then
+       abort
+       999.output
+end
+6.output
+if false then
+       var a = new Sys.fail
+       a.output
+end
+7.output