From: Jean Privat Date: Wed, 10 Jun 2015 01:47:05 +0000 (-0400) Subject: Merge: Work on the Curl module X-Git-Tag: v0.7.6~52 X-Git-Url: http://nitlanguage.org?hp=563de11890c120f3a335d1592b7ca26024fc2498 Merge: Work on the Curl module Changes: * Simplify callbacks so they do not break light FFI only engines. * Remove about 8 classes and 3 C structures. * Remove the custom implementation of NativeFile. * Update style to the latest best practices. Note that it was one of the first large module based on the FFI, a lot has changed since then. * Revamp and rename CurlMail, its API is now nicer to use: ~~~ import curl var mail = new CurlMail("sender@example.org", ["to@example.org"], cc=["bob@example.org"]) mail.subject = "Hello From My Nit Program" mail.body = "

Here you can write HTML stuff.

" mail.headers_body["Content-Type:"] = """text/html; charset="UTF-8"""" mail.headers_body["Content-Transfer-Encoding:"] = "quoted-printable" # Set mail server var error = mail.set_outgoing_server("smtps://smtp.example.org:465", "user@example.org", "mypassword") assert error == null # Send error = mail.execute assert error == null ~~~ Thoughts on what's to do next: * Extract the request API so Curl is only an implementation. The abstract API could also be implemented on Android where we can use Java services instead. * Clean up `CurlHTTPRequest`. * Use `Error` and differentiate between internal Curl errors and normal transfert failures. * Replace the C structure linked to reading data and add tests for its usage. * Add dead simple services: `Text::download: nullable String`, `Text::download_to_file(filepath: Text)`, `Text::download_to_stream(stream: Writer)` or something like that. * Make more classes of native_curl private as we cannot make the module private because it defines the user-customizable callbacks. Some modules (neo4j) use what would be private, so it requires updating them also. --- Should fix #936 and other problems when importing but not using Curl. Also helps #1443 correctly report unsupported programs. Pull-Request: #1445 Reviewed-by: Alexandre Terrasa Reviewed-by: Lucas Bajolet Reviewed-by: Jean Privat --- diff --git a/examples/rosettacode/24_game.nit b/examples/rosettacode/24_game.nit new file mode 100644 index 0000000..e6fa12d --- /dev/null +++ b/examples/rosettacode/24_game.nit @@ -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: + +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" diff --git a/lib/date.nit b/lib/date.nit new file mode 100755 index 0000000..19e8ceb --- /dev/null +++ b/lib/date.nit @@ -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 diff --git a/lib/java/collections.nit b/lib/java/collections.nit index 37f822e..0c24718 100644 --- a/lib/java/collections.nit +++ b/lib/java/collections.nit @@ -46,6 +46,48 @@ extern class AbstractJavaArray[E: Object] redef fun reverse_iterator do return new JavaArrayReverseIterator[E](self) end +# Java primitive array `int[]` +extern class JavaIntArray in "Java" `{ int[] `} + super AbstractJavaArray[Int] + + # Get a new array of the given `size` + new (size: Int) in "Java" `{ return new int[(int)size]; `} + + redef fun [](i) in "Java" `{ return self[(int)i]; `} + + redef fun []=(i, e) in "Java" `{ self[(int)i] = (int)e; `} + + redef fun length in "Java" `{ return self.length; `} +end + +# Java primitive array `short[]` +extern class JavaShortArray in "Java" `{ short[] `} + super AbstractJavaArray[Int] + + # Get a new array of the given `size` + new (size: Int) in "Java" `{ return new short[(int)size]; `} + + redef fun [](i) in "Java" `{ return (short)self[(int)i]; `} + + redef fun []=(i, e) in "Java" `{ self[(int)i] = (short)e; `} + + redef fun length in "Java" `{ return self.length; `} +end + +# Java primitive array `long[]` +extern class JavaLongArray in "Java" `{ long[] `} + super AbstractJavaArray[Int] + + # Get a new array of the given `size` + new (size: Int) in "Java" `{ return new long[(int)size]; `} + + redef fun [](i) in "Java" `{ return self[(int)i]; `} + + redef fun []=(i, e) in "Java" `{ self[(int)i] = (long)e; `} + + redef fun length in "Java" `{ return self.length; `} +end + # Java primitive array `float[]` # # Note that Nit `Float` is the size of a double, so storing them in a @@ -91,13 +133,47 @@ extern class JavaArray in "Java" `{ java.lang.Object[] `} redef fun length in "Java" `{ return self.length; `} end -# TODO other primitive arrays: -# * Java primitive array `byte[]` -# * Java primitive array `short[]` -# * Java primitive array `int[]` -# * Java primitive array `long[]` -# * Java primitive array `boolean[]` -# * Java primitive array `char[]` +# Java primitive array `boolean[]` +extern class JavaBoolArray in "Java" `{ boolean[] `} + super AbstractJavaArray[Bool] + + # Get a new array of the given `size` + new (size: Int) in "Java" `{ return new boolean[(int)size]; `} + + redef fun [](i) in "Java" `{ return self[(int)i]; `} + + redef fun []=(i, e) in "Java" `{self[(int)i] = (boolean)e; `} + + redef fun length in "Java" `{ return self.length; `} +end + +# Java primitive array `byte[]` +extern class JavaByteArray in "Java" `{ byte[] `} + super AbstractJavaArray[Int] + + # Get a new array of the given `size` + new (size: Int) in "Java" `{ return new byte[(int)size]; `} + + redef fun [](i) in "Java" `{ return (byte)self[(int)i]; `} + + redef fun []=(i, e) in "Java" `{ self[(int)i] = (byte)e; `} + + redef fun length in "Java" `{ return self.length; `} +end + +# Java primitive array `char[]` +extern class JavaCharArray in "Java" `{ char[] `} + super AbstractJavaArray[Char] + + # Get a new array of the given `size` + new (size: Int) in "Java" `{ return new char[(int)size]; `} + + redef fun [](i) in "Java" `{ return (char)self[(int)i]; `} + + redef fun []=(i, e) in "Java" `{ self[(int)i] = (char)e; `} + + redef fun length in "Java" `{ return self.length; `} +end # An `Iterator` on Java primitive arrays private class JavaArrayIterator[E: Object] diff --git a/lib/standard/file.nit b/lib/standard/file.nit index 46c52ec..9687b0c 100644 --- a/lib/standard/file.nit +++ b/lib/standard/file.nit @@ -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 diff --git a/src/c_tools.nit b/src/c_tools.nit index df2ddd8..0b80817 100644 --- a/src/c_tools.nit +++ b/src/c_tools.nit @@ -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 diff --git a/src/compiler/abstract_compiler.nit b/src/compiler/abstract_compiler.nit index a095201..c48aab9 100644 --- a/src/compiler/abstract_compiler.nit +++ b/src/compiler/abstract_compiler.nit @@ -1672,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 @@ -1697,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 @@ -2454,7 +2457,7 @@ redef class AAttrPropdef var res if is_lazy then var set - var ret = self.mpropdef.static_mtype + var ret = self.mtype var useiset = not ret.is_c_primitive and not ret isa MNullableType var guard = self.mlazypropdef.mproperty if useiset then @@ -2482,7 +2485,7 @@ redef class AAttrPropdef assert arguments.length == 2 v.write_attribute(self.mpropdef.mproperty, arguments.first, arguments[1]) if is_lazy then - var ret = self.mpropdef.static_mtype + var ret = self.mtype var useiset = not ret.is_c_primitive and not ret isa MNullableType if not useiset then v.write_attribute(self.mlazypropdef.mproperty, arguments.first, v.bool_instance(true)) @@ -2504,11 +2507,11 @@ redef class AAttrPropdef var oldnode = v.current_node v.current_node = self var old_frame = v.frame - var frame = new StaticFrame(v, self.mpropdef.as(not null), recv.mcasttype.undecorate.as(MClassType), [recv]) + var frame = new StaticFrame(v, self.mreadpropdef.as(not null), recv.mcasttype.undecorate.as(MClassType), [recv]) v.frame = frame var value - var mtype = self.mpropdef.static_mtype + var mtype = self.mtype assert mtype != null var nexpr = self.n_expr diff --git a/src/compiler/separate_compiler.nit b/src/compiler/separate_compiler.nit index f50a2a7..e07f125 100644 --- a/src/compiler/separate_compiler.nit +++ b/src/compiler/separate_compiler.nit @@ -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}" diff --git a/src/ffi/java.nit b/src/ffi/java.nit index d5852f6..c26fea2 100644 --- a/src/ffi/java.nit +++ b/src/ffi/java.nit @@ -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 diff --git a/src/frontend/simple_misc_analysis.nit b/src/frontend/simple_misc_analysis.nit index 885d794..f61b10a 100644 --- a/src/frontend/simple_misc_analysis.nit +++ b/src/frontend/simple_misc_analysis.nit @@ -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 diff --git a/src/interpreter/naive_interpreter.nit b/src/interpreter/naive_interpreter.nit index 16e0b48..53f2f41 100644 --- a/src/interpreter/naive_interpreter.nit +++ b/src/interpreter/naive_interpreter.nit @@ -1245,13 +1245,13 @@ redef class AAttrPropdef do if is_lazy then return if has_value then - var f = v.new_frame(self, mpropdef.as(not null), [recv]) + var f = v.new_frame(self, mreadpropdef.as(not null), [recv]) evaluate_expr(v, recv, f) return end var mpropdef = self.mpropdef if mpropdef == null then return - var mtype = mpropdef.static_mtype.as(not null) + var mtype = self.mtype.as(not null) mtype = mtype.anchor_to(v.mainmodule, recv.mtype.as(MClassType)) if mtype isa MNullableType then v.write_attribute(self.mpropdef.mproperty, recv, v.null_instance) diff --git a/src/loader.nit b/src/loader.nit index 0e6878b..d78ac71 100644 --- a/src/loader.nit +++ b/src/loader.nit @@ -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) diff --git a/src/modelize/modelize_property.nit b/src/modelize/modelize_property.nit index 91c552f..1afce19 100644 --- a/src/modelize/modelize_property.nit +++ b/src/modelize/modelize_property.nit @@ -158,9 +158,6 @@ redef class ModelBuilder return end - # Is the class forbid constructors? - if not mclassdef.mclass.kind.need_init then return - # Is there already a constructor defined? var defined_init: nullable MMethodDef = null for mpropdef in mclassdef.mpropdefs do @@ -182,18 +179,11 @@ redef class ModelBuilder var initializers = new Array[MProperty] for npropdef in nclassdef.n_propdefs do if npropdef isa AMethPropdef then + if not npropdef.is_autoinit then continue # Skip non tagged autoinit if npropdef.mpropdef == null then return # Skip broken method - var at = npropdef.get_single_annotation("autoinit", self) - if at == null then continue # Skip non tagged init - var sig = npropdef.mpropdef.msignature if sig == null then continue # Skip broken method - if not npropdef.mpropdef.is_intro then - self.error(at, "Error: `autoinit` cannot be set on redefinitions.") - continue - end - for param in sig.mparameters do var ret_type = param.mtype var mparameter = new MParameter(param.name, ret_type, false, ret_type isa MNullableType) @@ -743,6 +733,8 @@ end redef class AMethPropdef redef type MPROPDEF: MMethodDef + # Is the method annotated `autoinit`? + var is_autoinit = false # Can self be used as a root init? private fun look_like_a_root_init(modelbuilder: ModelBuilder, mclassdef: MClassDef): Bool @@ -988,6 +980,17 @@ redef class AMethPropdef # Check annotations var at = self.get_single_annotation("lazy", modelbuilder) if at != null then modelbuilder.error(at, "Syntax Error: `lazy` must be used on attributes.") + + var atautoinit = self.get_single_annotation("autoinit", modelbuilder) + if atautoinit != null then + if not mpropdef.is_intro then + modelbuilder.error(atautoinit, "Error: `autoinit` cannot be set on redefinitions.") + else if not mclassdef.is_intro then + modelbuilder.error(atautoinit, "Error: `autoinit` cannot be used in class refinements.") + else + self.is_autoinit = true + end + end end redef fun check_signature(modelbuilder) @@ -1135,6 +1138,10 @@ end redef class AAttrPropdef redef type MPROPDEF: MAttributeDef + # The static type of the property (declared, inferred or inherited) + # This attribute is also used to check if the property was analyzed and is valid. + var mtype: nullable MType + # Is the node tagged `noinit`? var noinit = false @@ -1209,8 +1216,7 @@ redef class AAttrPropdef return end if atabstract != null then - modelbuilder.error(atnoinit, "Error: `noautoinit` attributes cannot be abstract.") - return + modelbuilder.warning(atnoinit, "useless-noautoinit", "Warning: superfluous `noautoinit` on abstract attribute.") end end @@ -1282,6 +1288,22 @@ redef class AAttrPropdef modelbuilder.mpropdef2npropdef[mwritepropdef] = self mwritepropdef.mdoc = mreadpropdef.mdoc if atabstract != null then mwritepropdef.is_abstract = true + + var atautoinit = self.get_single_annotation("autoinit", modelbuilder) + if atautoinit != null then + if has_value then + modelbuilder.error(atautoinit, "Error: `autoinit` attributes cannot have an initial value.") + else if not mwritepropdef.is_intro then + modelbuilder.error(atautoinit, "Error: `autoinit` attributes cannot be set on redefinitions.") + else if not mclassdef.is_intro then + modelbuilder.error(atautoinit, "Error: `autoinit` attributes cannot be used in class refinements.") + else if atabstract == null then + modelbuilder.warning(atautoinit, "useless-autoinit", "Warning: superfluous `autoinit` on attribute.") + end + else if atabstract != null then + # By default, abstract attribute are not autoinit + noinit = true + end end redef fun build_signature(modelbuilder) @@ -1359,6 +1381,8 @@ redef class AAttrPropdef return end + self.mtype = mtype + if mpropdef != null then mpropdef.static_mtype = mtype end @@ -1389,7 +1413,7 @@ redef class AAttrPropdef var mpropdef = self.mpropdef if mpropdef == null then return # Error thus skipped var ntype = self.n_type - var mtype = self.mpropdef.static_mtype + var mtype = self.mtype if mtype == null then return # Error thus skipped var mclassdef = mpropdef.mclassdef diff --git a/src/nitni/nitni_base.nit b/src/nitni/nitni_base.nit index cc30171..f5cccc0 100644 --- a/src/nitni/nitni_base.nit +++ b/src/nitni/nitni_base.nit @@ -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 @@ -111,7 +112,7 @@ redef class MClassType if name == "Byte" then return "unsigned 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 diff --git a/src/phase.nit b/src/phase.nit index 5f0faf1..682d23e 100644 --- a/src/phase.nit +++ b/src/phase.nit @@ -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 diff --git a/src/rapid_type_analysis.nit b/src/rapid_type_analysis.nit index e27a98e..9010dde 100644 --- a/src/rapid_type_analysis.nit +++ b/src/rapid_type_analysis.nit @@ -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) @@ -354,7 +359,7 @@ class RapidTypeAnalysis for npropdef in modelbuilder.collect_attr_propdef(cd) do if not npropdef.has_value then continue - var mpropdef = npropdef.mpropdef.as(not null) + var mpropdef = npropdef.mreadpropdef.as(not null) var v = new RapidTypeVisitor(self, bound_mtype, mpropdef) v.enter_visit(npropdef.n_expr) v.enter_visit(npropdef.n_block) @@ -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 diff --git a/src/semantize/scope.nit b/src/semantize/scope.nit index a69c57a..4106660 100644 --- a/src/semantize/scope.nit +++ b/src/semantize/scope.nit @@ -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 diff --git a/src/semantize/typing.nit b/src/semantize/typing.nit index 44ed320..b37e4a4 100644 --- a/src/semantize/typing.nit +++ b/src/semantize/typing.nit @@ -648,7 +648,7 @@ end redef class Variable # The declared type of the variable - var declared_type: nullable MType + var declared_type: nullable MType is writable # Was the variable type-adapted? # This is used to speedup type retrieval while it remains `false` @@ -760,15 +760,15 @@ redef class AAttrPropdef do if not has_value then return - var mpropdef = self.mpropdef - if mpropdef == null then return # skip error + var mpropdef = self.mreadpropdef + if mpropdef == null or mpropdef.msignature == null then return # skip error var v = new TypeVisitor(modelbuilder, mpropdef.mclassdef.mmodule, mpropdef) self.selfvariable = v.selfvariable var nexpr = self.n_expr if nexpr != null then - var mtype = self.mpropdef.static_mtype + var mtype = self.mtype v.visit_expr_subtype(nexpr, mtype) end var nblock = self.n_block @@ -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 index 0000000..634dfa3 --- /dev/null +++ b/src/ssa.nit @@ -0,0 +1,1138 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Copyright 2015 Julien Pagès +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Single-Static Assignment algorithm from an AST +module ssa + +import semantize +import astbuilder + +# Represent a sequence of the program +# A basic block is composed of several instructions without a jump +class BasicBlock + # First instruction of the basic block + var first: ANode is noinit + + # Last instruction of the basic block + var last: ANode is noinit + + # Direct successors + var successors = new Array[BasicBlock] + + # Direct predecessors + var predecessors = new Array[BasicBlock] + + # Parts of AST that contain a read to a variable + var read_sites = new Array[AVarFormExpr] + + # Parts of AST that contain a write to a variable + var write_sites = new Array[AVarFormExpr] + + # Parts of AST that contain a variable access (read or write) + var variables_sites = new Array[AExpr] + + # The iterated dominance frontier of this block + # i.e. the set of blocks this block dominate directly or indirectly + var dominance_frontier: Array[BasicBlock] = new Array[BasicBlock] is lazy + + # Self is the old block to link to the new, + # The two blocks are not linked if the current ends with a `AReturnExpr` or `ABreakExpr` + # i.e. self is the predecessor of `successor` + # `successor` The successor block + fun link(successor: BasicBlock) + do + # Do not link the two blocks if the current block end with a return, break or continue + if last isa AReturnExpr or last isa ABreakExpr or last isa AContinueExpr then return + + successors.add(successor) + successor.predecessors.add(self) + end + + # Self is the old block to link to the new + # i.e. self is the predecessor of `successor` + # `successor` The successor block + fun link_special(successor: BasicBlock) + do + # Link the two blocks even if the current block ends with a return or a break + successors.add(successor) + successor.predecessors.add(self) + end + + # Add the `block` to the dominance frontier of this block + fun add_df(block: BasicBlock) + do + dominance_frontier.add(block) + + # Add this block recursively in super-blocks to compute the iterated + # dominance frontier + for successor in block.successors do + # If this successor has not already been add to the dominance frontier + if not dominance_frontier.has(successor) then + add_df(successor) + end + end + end + + # Compute recursively the dominance frontier of self block and its successors + private fun compute_df + do + # Treat each block only one time + df_computed = true + + for s in successors do + add_df(s) + + if not s.df_computed then s.compute_df + end + end + + # Used to handle recursions by treating only one time each block + var treated: Bool = false + + # Used to dump the BasicBlock to dot + var treated_debug: Bool = false + + # If true, the iterated dominance frontier of this block has been computed + var df_computed: Bool = false + + # Indicate the BasicBlock is newly created and needs to be updated + var need_update: Bool = false + + # Indicate if the variables renaming step has been made for this block + var is_renaming: Bool = false + + # The variables that are accessed in this block + var variables = new Array[Variable] is lazy + + # The PhiFunction this block contains at the beginning + var phi_functions = new Array[PhiFunction] is lazy +end + +# Contain the currently analyzed propdef +class SSA + # The currently analyzed APropdef + var propdef: APropdef + + # The PhiFunction `current_propdef` contains + var phi_functions = new Array[PhiFunction] + + # Recursively generate the basic blocks for this propdef + fun generate_basic_blocks + do + propdef.generate_basic_blocks(self) + end +end + +redef class Variable + # The expressions of AST of this variable depends + var dep_exprs = new Array[AExpr] + + # The blocks in which this variable is assigned + var assignment_blocks: Array[BasicBlock] = new Array[BasicBlock] is lazy + + # Part of the program where this variable is read + var read_blocks: Array[BasicBlock] = new Array[BasicBlock] is lazy + + # The stack of this variable, used for SSA renaming + var stack = new Array[Variable] is lazy + + # The original Variable in case of renaming + var original_variable: nullable Variable = self + + # If true, this variable is a parameter of a method + var parameter: Bool = false +end + +# A PhiFunction is a kind of Variable used in SSA-construction, +# it is placed at the beginning of a BasicBlock with many incoming blocks +class PhiFunction + super Variable + + # The dependences of this variable for SSA-Algorithm + var dependences = new Array[Couple[Variable, BasicBlock]] + + # The position in the AST of the phi-function + var block: BasicBlock + + # Set the dependences for the phi-function + # *`block` BasicBlock in which we go through the dominance-frontier + # *`v` The variable to looking for + fun add_dependences(block: BasicBlock, v: Variable) + do + # Look in which blocks of DF(block) `v` has been assigned + for b in block.predecessors do + if v.assignment_blocks.has(b) then + var dep = new Couple[Variable, BasicBlock](v, b) + dependences.add(dep) + end + end + end + + # Print the PhiFunction with all its dependences + redef fun to_s: String + do + var s = "" + s += " dependences = [ " + for d in dependences do + s += d.first.to_s + " " + end + s += "]" + + return s + end +end + +redef class APropdef + # The variables contained in the body on this propdef + var variables: HashSet[Variable] = new HashSet[Variable] is lazy + + # The first basic block of the code + var basic_block: nullable BasicBlock + + # If true, the basic blocks where generated + var is_generated: Bool = false + + # Generate all basic blocks for this code + fun generate_basic_blocks(ssa: SSA) is abstract + + # Contain all AST-parts related to object mechanisms the propdef has: + # instantiation, method dispatch, attribute access, subtyping-test + var object_sites: Array[AExpr] = new Array[AExpr] + + # Compute the three steps of SSA-algorithm + # `ssa` A new instance of SSA class initialized with `self` + fun compute_ssa(ssa: SSA) + do + if is_generated then return + + # The first step is to generate the basic blocks + generate_basic_blocks(ssa) + + # The propdef has no body (abstract) + if not is_generated then return + + # Once basic blocks were generated, compute SSA algorithm + compute_phi(ssa) + rename_variables(ssa) + ssa_destruction(ssa) + end + + # Compute the first phase of SSA algorithm: placing phi-functions + fun compute_phi(ssa: SSA) + do + var root_block = basic_block.as(not null) + + # Compute the iterated dominance frontier of the graph of basic blocks + root_block.compute_df + + # Places where a phi-function is added per variable + var phi_blocks = new HashMap[Variable, Array[BasicBlock]] + + # For each variables in the propdef + for v in variables do + var phi_variables = new Array[BasicBlock] + + var read_blocks = new Array[BasicBlock] + read_blocks.add_all(v.read_blocks) + read_blocks.add_all(v.assignment_blocks) + + # While we have not treated each part accessing `v` + while not read_blocks.is_empty do + # Remove a block from the array + var block = read_blocks.shift + + # For each block in the dominance frontier of `block` + for df in block.dominance_frontier do + # If we have not yet put a phi-function at the beginning of this block + if not phi_variables.has(df) then + phi_variables.add(df) + + # Create a new phi-function and set its dependences + var phi = new PhiFunction("phi", df) + phi.add_dependences(df, v) + phi.block = df + phi.original_variable = phi + phi.declared_type = v.declared_type + + # Indicate this phi-function is assigned in this block + phi.assignment_blocks.add(block) + ssa.phi_functions.add(phi) + + # Add a phi-function at the beginning of df for variable v + df.phi_functions.add(phi) + + if not v.read_blocks.has(df) or not v.assignment_blocks.has(df) then read_blocks.add(df) + end + end + end + + # Add `phi-variables` to the global map + phi_blocks[v] = phi_variables + end + end + + # Compute the second phase of SSA algorithm: renaming variables + # NOTE: `compute_phi` must has been called before + fun rename_variables(ssa: SSA) + do + # A counter for each variable + # The key is the variable, the value the number of assignment into the variable + var counter = new HashMap[Variable, Int] + + for v in variables do + counter[v] = 0 + v.stack.push(v) + end + + for phi in ssa.phi_functions do counter[phi] = 0 + + # Launch the recursive renaming from the root block + rename(basic_block.as(not null), counter, ssa) + end + + # Recursively rename each variable from `block` + # *`block` The starting basic block + # *`counter` The key is the variable, the value the number of assignment into the variable + fun rename(block: BasicBlock, counter: HashMap[Variable, Int], ssa: SSA) + do + if block.is_renaming then return + + block.is_renaming = true + + # For each phi-function of this block + for phi in block.phi_functions do + generate_name(phi, counter, block.first, ssa) + + # Replace the phi into the block + block.phi_functions[block.phi_functions.index_of(phi)] = phi.original_variable.stack.last.as(PhiFunction) + end + + # For each variable read in `block` + for vread in block.read_sites do + # Replace the old variable in AST + vread.variable = vread.variable.original_variable.stack.last + end + + # For each variable write + for vwrite in block.write_sites do + generate_name(vwrite.variable.as(not null), counter, vwrite, ssa) + + var new_version = vwrite.variable.original_variable.stack.last + + # Set dependence of the new variable + if vwrite isa AVarReassignExpr then + new_version.dep_exprs.add(vwrite.n_value) + else if vwrite isa AVarAssignExpr then + new_version.dep_exprs.add(vwrite.n_value) + end + + # Replace the old variable by the last created + vwrite.variable = new_version + end + + # Rename occurrence of old names in phi-function + for successor in block.dominance_frontier do + for sphi in successor.phi_functions do + # Go over the couples in the phi dependences to rename variables + for couple in sphi.dependences do + if couple.second == block then + # Rename this variable + couple.first = couple.first.original_variable.stack.last + end + end + end + end + + # Recurse in successor blocks + for successor in block.successors do + rename(successor, counter, ssa) + end + + # Pop old names off the stack for each phi-function + for phi in block.phi_functions do + if not phi.stack.is_empty then phi.stack.pop + end + end + + # Generate a new version of the variable `v` and return it + # *`v` The variable for which we generate a name + # *`counter` The key is the variable, the value the number of assignment into the variable + # *`expr` The AST node in which the assignment of v is made + # *`ssa` The instance of SSA + fun generate_name(v: Variable, counter: HashMap[Variable, Int], expr: ANode, ssa: SSA): Variable + do + var original_variable = v.original_variable.as(not null) + + var i = counter[original_variable] + + var new_version: Variable + + # Create a new version of Variable + if original_variable isa PhiFunction then + var block = original_variable.block + new_version = new PhiFunction(original_variable.name + i.to_s, block) + new_version.dependences.add_all(original_variable.dependences) + ssa.phi_functions.add(new_version) + else + new_version = new Variable(original_variable.name + i.to_s) + new_version.declared_type = expr.as(AVarFormExpr).variable.declared_type + variables.add(new_version) + end + + # Recopy the fields into the new version + new_version.location = expr.location + new_version.original_variable = original_variable + + # Push a new version on the stack + original_variable.stack.add(new_version) + counter[v] = i + 1 + + return new_version + end + + # Transform SSA-representation into an executable code (delete phi-functions) + # `ssa` Current instance of SSA + fun ssa_destruction(ssa: SSA) + do + var builder = new ASTBuilder(mpropdef.mclassdef.mmodule, mpropdef.mclassdef.bound_mtype) + + # Iterate over all phi-functions + for phi in ssa.phi_functions do + for dep in phi.dependences do + # dep.second is the block where we need to create a varassign + var var_read = builder.make_var_read(dep.first, dep.first.declared_type.as(not null)) + var nvar = builder.make_var_assign(dep.first, var_read) + + var block = dep.second.last.parent + + # This variable read must be add to a ABlockExpr + if block isa ABlockExpr then + block.add(nvar) + end + + propagate_dependences(phi, phi.block) + ssa.propdef.variables.add(dep.first) + end + end + end + + # Propagate the dependences of the phi-functions into following variables + # `phi` The PhiFunction + # `block` Current block where we propagate dependences + fun propagate_dependences(phi: PhiFunction, block: BasicBlock) + do + # Treat each block once + if block.treated then return + + # For each variable access site in the block + for site in block.variables_sites do + if site isa AVarExpr then + # Propagate the dependences of the phi-function in variables after the phi + for dep in phi.dependences do + for expr in dep.first.dep_exprs do + if site.variable.dep_exprs.has(expr) then break + + if dep.first.original_variable == site.variable.original_variable then + site.variable.dep_exprs.add(expr) + end + end + end + else + # The site is a variable write, we stop the propagation + return + end + end + + block.treated = true + + # If we do not meet a variable write, continue the propagation + for b in block.successors do propagate_dependences(phi, b) + end +end + +redef class AAttrPropdef + redef fun generate_basic_blocks(ssa: SSA) + do + basic_block = new BasicBlock + basic_block.first = self + basic_block.last = self + + # Add the self variable + if self.selfvariable != null then variables.add(selfvariable.as(not null)) + + # Recursively goes into the nodes + if n_block != null then + n_block.generate_basic_blocks(ssa, basic_block.as(not null)) + is_generated = true + end + end +end + +redef class AMethPropdef + + # The return variable of the propdef + # Create an empty variable for the return of the method + # and treat returns like variable assignments + var returnvar: Variable = new Variable("returnvar") + + redef fun generate_basic_blocks(ssa: SSA) + do + basic_block = new BasicBlock + basic_block.first = self + basic_block.last = self + + # If the method has a signature + if n_signature != null then + for p in n_signature.n_params do + # Add parameters to the local variables + variables.add(p.variable.as(not null)) + p.variable.parameter = true + end + end + + # Add the return variable + variables.add(returnvar) + + # Add the self variable + if self.selfvariable != null then variables.add(selfvariable.as(not null)) + + # Recursively goes into the nodes + if n_block != null then + n_block.generate_basic_blocks(ssa, basic_block.as(not null)) + is_generated = true + end + end +end + +# Utility class for dump basic block and SSA output to dot files +class BlockDebug + # The output file + var file: FileWriter + + # Dump all the hierarchy of BasicBlock from `block` to the leaves + fun dump(block: BasicBlock) + do + # Write the basic blocks hierarchy in output file + file.write("digraph basic_blocks\n\{\n") + var i = 0 + file.write(print_block(block, i)) + file.write("\n\}") + + file.close + end + + # Print all the block recursively from `block` to the leaves + # *`block` The root BasicBlock + # *`i` Used for the recursion + private fun print_block(block: BasicBlock, i: Int): String + do + # Precise the type and location of the begin and end of current block + var s = "block{block.hash.to_s} [shape=record, label="+"\"\{" + s += "block" + block.to_s.escape_to_dot + s += "|\{" + block.first.location.file.filename.to_s + block.first.location.line_start.to_s + s += " | " + block.first.to_s.escape_to_dot + + # Print phi-functions if any + for phi in block.phi_functions do + s += " | " + phi.to_s.escape_to_dot + " " + end + + s += "}|\{" + block.last.location.file.filename.to_s + block.last.location.line_start.to_s + s += " | " + block.last.to_s.escape_to_dot + "}}\"];"+ "\n" + + i += 1 + block.treated_debug = true + + for b in block.successors do + # Print edges to successors + s += "block{block.hash.to_s} -> " + " block{b.hash.to_s};\n" + + # Recursively print child blocks + if not b.treated_debug then s += print_block(b, i) + end + + return s + end +end + +redef class AExpr + # Generate recursively basic block for this expression + # *`ssa` An instance of the SSA class initialized with the enclosing `APropdef` + # *`old_block` A basic block not completely filled + # Return the last created block (the last block can be nested) + fun generate_basic_blocks(ssa: SSA, old_block: BasicBlock): BasicBlock + do + return old_block + end +end + +redef class AVarFormExpr + # The original variable + var original_variable: nullable Variable = variable +end + +redef class AVarExpr + redef fun generate_basic_blocks(ssa, old_block) + do + self.variable.as(not null).read_blocks.add(old_block) + old_block.variables.add(self.variable.as(not null)) + + self.variable.as(not null).original_variable = self.variable.as(not null) + # Save this read site in the block + old_block.read_sites.add(self) + old_block.variables_sites.add(self) + + return old_block + end +end + +redef class AVardeclExpr + redef fun generate_basic_blocks(ssa, old_block) + do + var decl = self.variable.as(not null) + + # Add the corresponding variable to the enclosing mpropdef + ssa.propdef.variables.add(decl) + + decl.original_variable = decl + decl.assignment_blocks.add(old_block) + old_block.variables.add(decl) + + if self.n_expr != null then + self.variable.dep_exprs.add(self.n_expr.as(not null)) + old_block = self.n_expr.generate_basic_blocks(ssa, old_block) + end + + return old_block + end +end + +redef class AVarAssignExpr + redef fun generate_basic_blocks(ssa, old_block) + do + self.variable.as(not null).assignment_blocks.add(old_block) + old_block.variables.add(self.variable.as(not null)) + self.variable.as(not null).original_variable = self.variable.as(not null) + + # Save this write site in the block + old_block.write_sites.add(self) + old_block.variables_sites.add(self) + + ssa.propdef.variables.add(self.variable.as(not null)) + + return self.n_value.generate_basic_blocks(ssa, old_block) + end +end + +redef class AVarReassignExpr + redef fun generate_basic_blocks(ssa, old_block) + do + self.variable.as(not null).assignment_blocks.add(old_block) + old_block.variables.add(self.variable.as(not null)) + self.variable.as(not null).original_variable = self.variable.as(not null) + + # Save this write site in the block + old_block.write_sites.add(self) + old_block.variables_sites.add(self) + + ssa.propdef.variables.add(self.variable.as(not null)) + return self.n_value.generate_basic_blocks(ssa, old_block) + end +end + +redef class ABreakExpr + redef fun generate_basic_blocks(ssa, old_block) + do + # Finish the old block + old_block.last = self + + return old_block + end +end + +redef class AContinueExpr + redef fun generate_basic_blocks(ssa, old_block) + do + return old_block + end +end + +redef class AReturnExpr + redef fun generate_basic_blocks(ssa, old_block) + do + # The return just set the current block and stop the recursion + if self.n_expr != null then + old_block = self.n_expr.generate_basic_blocks(ssa, old_block) + + # Store the return expression in the dependences of the dedicated returnvar + if ssa.propdef isa AMethPropdef then + ssa.propdef.as(AMethPropdef).returnvar.dep_exprs.add(n_expr.as(not null)) + end + end + + old_block.last = self + + return old_block + end +end + +redef class AAssertExpr + redef fun generate_basic_blocks(ssa, old_block) + do + self.n_expr.generate_basic_blocks(ssa, old_block) + + # The condition of the assert is the last expression of the previous block + old_block.last = self.n_expr + + # The block if the assert fail + var block_false = new BasicBlock + + if self.n_else != null then + block_false.first = self.n_else.as(not null) + block_false.last = self.n_else.as(not null) + self.n_else.generate_basic_blocks(ssa, block_false) + else + block_false.first = self + block_false.first = self + end + + old_block.link(block_false) + + # The block if the assert is true: the execution continue + var block_true = new BasicBlock + block_true.first = self + block_true.last = self + + old_block.link(block_true) + + return block_true + end +end + +redef class AOrExpr + redef fun generate_basic_blocks(ssa, old_block) + do + self.n_expr.generate_basic_blocks(ssa, old_block) + return self.n_expr2.generate_basic_blocks(ssa, old_block) + end +end + +redef class AImpliesExpr + redef fun generate_basic_blocks(ssa, old_block) + do + self.n_expr.generate_basic_blocks(ssa, old_block) + return self.n_expr2.generate_basic_blocks(ssa, old_block) + end +end + +redef class AAndExpr + redef fun generate_basic_blocks(ssa, old_block) + do + self.n_expr.generate_basic_blocks(ssa, old_block) + return self.n_expr2.generate_basic_blocks(ssa, old_block) + end +end + +redef class ANotExpr + redef fun generate_basic_blocks(ssa, old_block) + do + return self.n_expr.generate_basic_blocks(ssa, old_block) + end +end + +redef class AOrElseExpr + redef fun generate_basic_blocks(ssa, old_block) + do + self.n_expr.generate_basic_blocks(ssa, old_block) + return self.n_expr2.generate_basic_blocks(ssa, old_block) + end +end + +redef class AArrayExpr + redef fun generate_basic_blocks(ssa, old_block) + do + for nexpr in self.n_exprs do + old_block = nexpr.generate_basic_blocks(ssa, old_block) + end + + return old_block + end +end + +redef class ASuperstringExpr + redef fun generate_basic_blocks(ssa, old_block) + do + for nexpr in self.n_exprs do old_block = nexpr.generate_basic_blocks(ssa, old_block) + + return old_block + end +end + +redef class ACrangeExpr + redef fun generate_basic_blocks(ssa, old_block) + do + self.n_expr.generate_basic_blocks(ssa, old_block) + return self.n_expr2.generate_basic_blocks(ssa, old_block) + end +end + +redef class AOrangeExpr + redef fun generate_basic_blocks(ssa, old_block) + do + self.n_expr.generate_basic_blocks(ssa, old_block) + return self.n_expr2.generate_basic_blocks(ssa, old_block) + end +end + +redef class AIsaExpr + redef fun generate_basic_blocks(ssa, old_block) + do + ssa.propdef.object_sites.add(self) + + return self.n_expr.generate_basic_blocks(ssa, old_block) + end +end + +redef class AAsCastExpr + redef fun generate_basic_blocks(ssa, old_block) + do + ssa.propdef.object_sites.add(self) + + return self.n_expr.generate_basic_blocks(ssa, old_block) + end +end + +redef class AAsNotnullExpr + redef fun generate_basic_blocks(ssa, old_block) + do + return self.n_expr.generate_basic_blocks(ssa, old_block) + end +end + +redef class AParExpr + redef fun generate_basic_blocks(ssa, old_block) + do + return self.n_expr.generate_basic_blocks(ssa, old_block) + end +end + +redef class AOnceExpr + redef fun generate_basic_blocks(ssa, old_block) + do + return self.n_expr.generate_basic_blocks(ssa, old_block) + end +end + +redef class ASendExpr + redef fun generate_basic_blocks(ssa, old_block) + do + # A call does not finish the current block, + # because we create intra-procedural basic blocks here + + ssa.propdef.object_sites.add(self) + + # Recursively goes into arguments to find variables if any + for e in self.raw_arguments do e.generate_basic_blocks(ssa, old_block) + + return self.n_expr.generate_basic_blocks(ssa, old_block) + end +end + +redef class ASendReassignFormExpr + redef fun generate_basic_blocks(ssa, old_block) + do + self.n_expr.generate_basic_blocks(ssa, old_block) + + ssa.propdef.object_sites.add(self) + + # Recursively goes into arguments to find variables if any + for e in self.raw_arguments do e.generate_basic_blocks(ssa, old_block) + + return self.n_value.generate_basic_blocks(ssa, old_block) + end +end + +redef class ASuperExpr + redef fun generate_basic_blocks(ssa, old_block) + do + # Recursively goes into arguments to find variables if any + for arg in self.n_args.n_exprs do arg.generate_basic_blocks(ssa, old_block) + + return old_block + end +end + +redef class ANewExpr + redef fun generate_basic_blocks(ssa, old_block) + do + for e in self.n_args.n_exprs do e.generate_basic_blocks(ssa, old_block) + + ssa.propdef.object_sites.add(self) + + return old_block + end +end + +redef class AAttrExpr + redef fun generate_basic_blocks(ssa, old_block) + do + ssa.propdef.object_sites.add(self) + + return self.n_expr.generate_basic_blocks(ssa, old_block) + end +end + +redef class AAttrAssignExpr + redef fun generate_basic_blocks(ssa, old_block) + do + ssa.propdef.object_sites.add(self) + + return self.n_expr.generate_basic_blocks(ssa, old_block) + end +end + +redef class AAttrReassignExpr + redef fun generate_basic_blocks(ssa, old_block) + do + ssa.propdef.object_sites.add(self) + + return self.n_expr.generate_basic_blocks(ssa, old_block) + end +end + +redef class AIssetAttrExpr + redef fun generate_basic_blocks(ssa, old_block) + do + return self.n_expr.generate_basic_blocks(ssa, old_block) + end +end + +redef class ABlockExpr + # The block needs to know if a new block is created + redef fun generate_basic_blocks(ssa, old_block) + do + var last_block = old_block + var current_block: BasicBlock + + # Recursively continue in the body of the block + for i in [0..self.n_expr.length[ do + current_block = self.n_expr[i].generate_basic_blocks(ssa, last_block) + + if current_block.need_update then + if i < (self.n_expr.length-1) then + # Current_block must be filled + current_block.first = self.n_expr[i+1] + current_block.last = self.n_expr[i+1] + current_block.need_update = false + else + # Put the current block at the end of the block + current_block.first = last_block.last + current_block.last = last_block.last + end + end + + if not current_block.last isa AEscapeExpr or current_block.last isa AReturnExpr then + # Re-affected the last block + current_block.last = self.n_expr[i] + end + + last_block = current_block + end + + return last_block + end +end + +redef class AIfExpr + redef fun generate_basic_blocks(ssa, old_block) + do + # Terminate the previous block + old_block.last = self + + # We start two new blocks if the if has two branches + var block_then = new BasicBlock + + # Visit the test of the if + self.n_expr.generate_basic_blocks(ssa, old_block) + + # Launch the recursion in two successors if they exist + if self.n_then != null then + old_block.link(block_then) + + block_then.first = self.n_then.as(not null) + block_then.last = self.n_then.as(not null) + self.n_then.generate_basic_blocks(ssa, block_then) + end + + var block_else = new BasicBlock + + if self.n_else != null then + old_block.link(block_else) + + block_else.first = self.n_else.as(not null) + block_else.last = self.n_else.as(not null) + self.n_else.generate_basic_blocks(ssa, block_else) + end + + # Create a new BasicBlock to represent the two successor + # branches of the if + var new_block = new BasicBlock + new_block.first = self + new_block.last = self + + if self.n_then != null then block_then.link(new_block) + + # The new block needs to be filled by the caller + new_block.need_update = true + + if block_else.predecessors.length != 0 then block_else.link(new_block) + + return new_block + end +end + +redef class AIfexprExpr + redef fun generate_basic_blocks(ssa, old_block) + do + # Terminate the previous block + old_block.last = self + + # We start two new blocks if the if has two branches + var block_then = new BasicBlock + + # Visit the test of the if + self.n_expr.generate_basic_blocks(ssa, old_block) + + # Launch the recursion in two successors if they exist + old_block.link(block_then) + + block_then.first = self.n_then + block_then.last = self.n_then + self.n_then.generate_basic_blocks(ssa, block_then) + + var block_else = new BasicBlock + + old_block.link(block_else) + + block_else.first = self.n_else + block_else.last = self.n_else + self.n_else.generate_basic_blocks(ssa, block_else) + + # Create a new BasicBlock to represent the two successor + # branches of the if + var new_block = new BasicBlock + new_block.first = self + new_block.last = self + + block_then.link(new_block) + + # The new block needs to be filled by the caller + new_block.need_update = true + + block_else.link(new_block) + + return new_block + end +end + +redef class ADoExpr + redef fun generate_basic_blocks(ssa, old_block) + do + old_block.last = self + + # The beginning of the block is the first instruction + var block = new BasicBlock + block.first = self.n_block.as(not null) + block.last = self.n_block.as(not null) + + old_block.link(block) + return self.n_block.generate_basic_blocks(ssa, block) + end +end + +redef class AWhileExpr + redef fun generate_basic_blocks(ssa, old_block) + do + old_block.last = self + + # The beginning of the block is the test of the while + var block = new BasicBlock + block.first = self.n_expr + block.last = self.n_block.as(not null) + + old_block.link(block) + + self.n_expr.generate_basic_blocks(ssa, old_block) + var inside_block = self.n_block.generate_basic_blocks(ssa, block) + + # Link the inside of the block to the previous block + block.link_special(old_block) + + # Create a new Block after the while + var new_block = new BasicBlock + new_block.need_update = true + + old_block.link_special(new_block) + + return new_block + end +end + +redef class ALoopExpr + redef fun generate_basic_blocks(ssa, old_block) + do + old_block.last = self + + # The beginning of the block is the first instruction + var block = new BasicBlock + block.first = self.n_block.as(not null) + block.last = self.n_block.as(not null) + + old_block.link(block) + self.n_block.generate_basic_blocks(ssa, block) + + return block + end +end + +redef class AForExpr + redef fun generate_basic_blocks(ssa, old_block) + do + old_block.last = self + + # The beginning of the block is the first instruction + var block = new BasicBlock + block.first = self.n_expr + block.last = self.n_block.as(not null) + + # Visit the test of the if + self.n_expr.generate_basic_blocks(ssa, block) + + # Collect the variables declared in the for + for v in variables do + ssa.propdef.variables.add(v) + end + + old_block.link(block) + + block.link(old_block) + + var new_block = new BasicBlock + new_block.need_update = true + + return new_block + end +end diff --git a/src/transform.nit b/src/transform.nit index ebe2c73..838b9bc 100644 --- a/src/transform.nit +++ b/src/transform.nit @@ -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 index 0000000..5dca966 --- /dev/null +++ b/src/vm/compilation.nit @@ -0,0 +1,60 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Copyright 2015 Julien Pagès +# +# 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 diff --git a/src/vm/variables_numbering.nit b/src/vm/variables_numbering.nit index 4de0eb4..d01b390 100644 --- a/src/vm/variables_numbering.nit +++ b/src/vm/variables_numbering.nit @@ -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 diff --git a/src/vm/vm.nit b/src/vm/vm.nit index 4027a15..e98d2da 100644 --- a/src/vm/vm.nit +++ b/src/vm/vm.nit @@ -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 index 0000000..7b80b80 --- /dev/null +++ b/tests/24_game.inputs @@ -0,0 +1,3 @@ +8/4 +8*2 +16+8 diff --git a/tests/base_adaptive_loop3.nit b/tests/base_adaptive_loop3.nit index 33f4c8d..42e331a 100644 --- a/tests/base_adaptive_loop3.nit +++ b/tests/base_adaptive_loop3.nit @@ -27,4 +27,5 @@ while t2 != null do t2 = t2.next #alt2# t2 = null end #alt3#t2 = t2.next + #alt3#exit(0) end diff --git a/tests/base_adaptive_loop_null.nit b/tests/base_adaptive_loop_null.nit index cfbb80f..e342e07 100644 --- a/tests/base_adaptive_loop_null.nit +++ b/tests/base_adaptive_loop_null.nit @@ -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_attr4.nit b/tests/base_attr4.nit index b8f02dc..1b88711 100644 --- a/tests/base_attr4.nit +++ b/tests/base_attr4.nit @@ -31,9 +31,15 @@ end class C super B redef fun foo: Int do return 100 - redef fun bar=(i: Int) do i.output + redef fun bar=(i: Int) do + super + i.output + end redef fun baz: Int do return 400 - redef fun baz=(i: Int) do i.output + redef fun baz=(i: Int) do + super + i.output + end end var a = new A diff --git a/tests/base_attr_abstract.nit b/tests/base_attr_abstract.nit index 34c1e4c..d4b07a7 100644 --- a/tests/base_attr_abstract.nit +++ b/tests/base_attr_abstract.nit @@ -14,25 +14,27 @@ import kernel -interface Foo +class Foo var a: Object is abstract - #alt1#var b = 1 is abstract - #alt2#var b is abstract, noautoinit + var b: Object = 10 is abstract + #alt1#var b is abstract, noautoinit + #alt1#var c = 1 is abstract, lazy + #alt1#var d = 1 is abstract, autoinit + #alt1#var e = 1 is abstract, readonly end class Bar super Foo redef var a + redef var b is noinit end class Baz super Foo - redef fun a do return 100 - redef fun a=(x) do (101).output -end - -class FooBar - super Foo + redef fun a do return 100 #alt2# + redef fun a=(x) do (101).output #alt3# + redef fun b do return 200 #alt4# + redef fun b=(x) do (201).output #alt5# end var f: Foo = new Bar(1) @@ -40,11 +42,21 @@ f.a.output f.a = 2 f.a.output +'\n'.output + +f.b.output +f.b = 20 +f.b.output + +'\n'.output + f = new Baz f.a.output f.a = 3 f.a.output -f = new FooBar -#alt3#f.a.output -#alt4#f.a = 4 +'\n'.output + +f.b.output +f.b = 30 +f.b.output diff --git a/tests/base_attr_abstract2.nit b/tests/base_attr_abstract2.nit index 931f334..0a5b8e9 100644 --- a/tests/base_attr_abstract2.nit +++ b/tests/base_attr_abstract2.nit @@ -16,7 +16,7 @@ import standard::kernel abstract class A var x: Int - var y: Int is abstract + var y: Int is abstract, autoinit end class B diff --git a/tests/base_attr_abstract3.nit b/tests/base_attr_abstract3.nit new file mode 100644 index 0000000..d67a45f --- /dev/null +++ b/tests/base_attr_abstract3.nit @@ -0,0 +1,76 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import standard::kernel + +interface A + var i: Int is abstract, autoinit + fun j: Int is abstract, autoinit + fun j=(o: Int) is abstract, autoinit +end + +class B + super A + var k: Int is abstract, autoinit + fun l: Int is abstract, autoinit + fun l=(o: Int) is abstract, autoinit +end + +class C + super B + redef fun i do + 'i'.output + return 1 + end + redef fun i=(o) do + 'i'.output + '='.output + o.output + end + redef fun j do + 'j'.output + return 2 + end + redef fun j=(o) do + 'j'.output + '='.output + o.output + end + redef fun k do + 'k'.output + return 3 + end + redef fun k=(o) + do + 'k'.output + '='.output + o.output + end + redef fun l do + 'l'.output + return 4 + end + redef fun l=(o) do + 'l'.output + '='.output + o.output + end +end + +var c = new C(10,20,30,40) +'\n'.output +c.i.output +c.j.output +c.k.output +c.l.output diff --git a/tests/base_attr_abstract4.nit b/tests/base_attr_abstract4.nit new file mode 100644 index 0000000..876b85a --- /dev/null +++ b/tests/base_attr_abstract4.nit @@ -0,0 +1,75 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import standard::kernel + +interface A + var i: Int is abstract + fun j: Int is abstract + fun j=(o: Int) is abstract +end + +class B + super A + var k: Int is abstract + fun l: Int is abstract + fun l=(o: Int) is abstract +end + +class C + super B + redef fun i do + 'i'.output + return 1 + end + redef fun i=(o) do + 'i'.output + '='.output + o.output + end + redef fun j do + 'j'.output + return 2 + end + redef fun j=(o) do + 'j'.output + '='.output + o.output + end + redef fun k do + 'k'.output + return 3 + end + redef fun k=(o) + do + 'k'.output + '='.output + o.output + end + redef fun l do + 'l'.output + return 4 + end + redef fun l=(o) do + 'l'.output + '='.output + o.output + end +end + +var c = new C +c.i.output +c.j.output +c.k.output +c.l.output diff --git a/tests/base_attr_annot.nit b/tests/base_attr_annot.nit new file mode 100644 index 0000000..17f7076 --- /dev/null +++ b/tests/base_attr_annot.nit @@ -0,0 +1,34 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import standard::kernel + +class A + var a: Object is + #alt2# noautoinit + #alt3# autoinit + #alt4# lazy + #alt5# readonly + #alt6# abstract + #alt7# lateinit + writable + end #1alt1# do return 1 +end + +class B + super A +end + +var b = new B(1) #alt1,2,4,5,6,7# var b = new B +b.a.output diff --git a/tests/base_do_block.nit b/tests/base_do_block.nit new file mode 100644 index 0000000..b9fdad4 --- /dev/null +++ b/tests/base_do_block.nit @@ -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/base_init_setter.nit b/tests/base_init_setter.nit new file mode 100644 index 0000000..52a4c94 --- /dev/null +++ b/tests/base_init_setter.nit @@ -0,0 +1,37 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import standard::kernel + +class A + var i: Int = 1 +end + +class B + super A + redef fun i=(v) + do + super + 'i'.output + v.output + end +end + +var a = new A +a.i.output + +'\n'.output + +var b = new B +b.i.output diff --git a/tests/sav/24_game.res b/tests/sav/24_game.res new file mode 100644 index 0000000..bcbdec9 --- /dev/null +++ b/tests/sav/24_game.res @@ -0,0 +1,4 @@ +numbers: 8, 4, 8, 8 +numbers: 8, 8, 2 +numbers: 8, 16 +CONGRATULATIONS diff --git a/tests/sav/base_attr4.res b/tests/sav/base_attr4.res index 635a8c2..3278c31 100644 --- a/tests/sav/base_attr4.res +++ b/tests/sav/base_attr4.res @@ -9,6 +9,6 @@ 100 200 -30 +200 300 400 diff --git a/tests/sav/base_attr4_alt1.res b/tests/sav/base_attr4_alt1.res index 5d77e90..2fa9ce5 100644 --- a/tests/sav/base_attr4_alt1.res +++ b/tests/sav/base_attr4_alt1.res @@ -1 +1 @@ -alt/base_attr4_alt1.nit:40,3--5: Error: method `foo=` does not exists in `A`. +alt/base_attr4_alt1.nit:46,3--5: Error: method `foo=` does not exists in `A`. diff --git a/tests/sav/base_attr4_alt2.res b/tests/sav/base_attr4_alt2.res index 30b0f43..2f0440d 100644 --- a/tests/sav/base_attr4_alt2.res +++ b/tests/sav/base_attr4_alt2.res @@ -1 +1 @@ -alt/base_attr4_alt2.nit:43,3--5: Error: method `bar` does not exists in `A`. +alt/base_attr4_alt2.nit:49,3--5: Error: method `bar` does not exists in `A`. diff --git a/tests/sav/base_attr_abstract.res b/tests/sav/base_attr_abstract.res index 36f0f1a..fa5258d 100644 --- a/tests/sav/base_attr_abstract.res +++ b/tests/sav/base_attr_abstract.res @@ -1,5 +1,3 @@ -1 -2 -100 -101 -100 +base_attr_abstract.nit:19,24--31: Error: `abstract` attributes cannot have an initial value. +base_attr_abstract.nit:37,12--13: Error: no property `Baz::b=` is inherited. Remove the `redef` keyword to define a new property. +base_attr_abstract.nit:37,15: Error: untyped parameter `x'. diff --git a/tests/sav/base_attr_abstract3.res b/tests/sav/base_attr_abstract3.res new file mode 100644 index 0000000..d328d13 --- /dev/null +++ b/tests/sav/base_attr_abstract3.res @@ -0,0 +1,9 @@ +i=10 +jj=20 +k=30 +ll=40 + +i1 +j2 +k3 +l4 diff --git a/tests/sav/base_attr_abstract4.res b/tests/sav/base_attr_abstract4.res new file mode 100644 index 0000000..4d4bee4 --- /dev/null +++ b/tests/sav/base_attr_abstract4.res @@ -0,0 +1,4 @@ +i1 +j2 +k3 +l4 diff --git a/tests/sav/base_attr_abstract_alt1.res b/tests/sav/base_attr_abstract_alt1.res index 4b97e69..e3a1ef5 100644 --- a/tests/sav/base_attr_abstract_alt1.res +++ b/tests/sav/base_attr_abstract_alt1.res @@ -1 +1,7 @@ -alt/base_attr_abstract_alt1.nit:19,15--22: Error: `abstract` attributes cannot have an initial value. +alt/base_attr_abstract_alt1.nit:19,24--31: Error: `abstract` attributes cannot have an initial value. +alt/base_attr_abstract_alt1.nit:20,6: Error: a property `b` is already defined in class `Foo` at line 19. +alt/base_attr_abstract_alt1.nit:21,15--22: Error: `abstract` attributes cannot have an initial value. +alt/base_attr_abstract_alt1.nit:22,15--22: Error: `abstract` attributes cannot have an initial value. +alt/base_attr_abstract_alt1.nit:23,15--22: Error: `abstract` attributes cannot have an initial value. +alt/base_attr_abstract_alt1.nit:37,12--13: Error: no property `Baz::b=` is inherited. Remove the `redef` keyword to define a new property. +alt/base_attr_abstract_alt1.nit:37,15: Error: untyped parameter `x'. diff --git a/tests/sav/base_attr_abstract_alt2.res b/tests/sav/base_attr_abstract_alt2.res index af3a672..f79bebd 100644 --- a/tests/sav/base_attr_abstract_alt2.res +++ b/tests/sav/base_attr_abstract_alt2.res @@ -1,2 +1,3 @@ -alt/base_attr_abstract_alt2.nit:20,6: Error: untyped attribute `base_attr_abstract_alt2#Foo#b`. -alt/base_attr_abstract_alt2.nit:20,21--30: Error: `noautoinit` attributes cannot be abstract. +alt/base_attr_abstract_alt2.nit:19,24--31: Error: `abstract` attributes cannot have an initial value. +alt/base_attr_abstract_alt2.nit:37,12--13: Error: no property `Baz::b=` is inherited. Remove the `redef` keyword to define a new property. +alt/base_attr_abstract_alt2.nit:37,15: Error: untyped parameter `x'. diff --git a/tests/sav/base_attr_abstract_alt3.res b/tests/sav/base_attr_abstract_alt3.res index 4052598..b112e42 100644 --- a/tests/sav/base_attr_abstract_alt3.res +++ b/tests/sav/base_attr_abstract_alt3.res @@ -1,6 +1,3 @@ -Runtime error: Abstract method `a` called on `FooBar` (alt/base_attr_abstract_alt3.nit:18) -1 -2 -100 -101 -100 +alt/base_attr_abstract_alt3.nit:19,24--31: Error: `abstract` attributes cannot have an initial value. +alt/base_attr_abstract_alt3.nit:37,12--13: Error: no property `Baz::b=` is inherited. Remove the `redef` keyword to define a new property. +alt/base_attr_abstract_alt3.nit:37,15: Error: untyped parameter `x'. diff --git a/tests/sav/base_attr_abstract_alt4.res b/tests/sav/base_attr_abstract_alt4.res index 09d65f9..0d349af 100644 --- a/tests/sav/base_attr_abstract_alt4.res +++ b/tests/sav/base_attr_abstract_alt4.res @@ -1,6 +1,3 @@ -Runtime error: Abstract method `a=` called on `FooBar` (alt/base_attr_abstract_alt4.nit:18) -1 -2 -100 -101 -100 +alt/base_attr_abstract_alt4.nit:19,24--31: Error: `abstract` attributes cannot have an initial value. +alt/base_attr_abstract_alt4.nit:37,12--13: Error: no property `Baz::b=` is inherited. Remove the `redef` keyword to define a new property. +alt/base_attr_abstract_alt4.nit:37,15: Error: untyped parameter `x'. diff --git a/tests/sav/base_attr_abstract_alt5.res b/tests/sav/base_attr_abstract_alt5.res new file mode 100644 index 0000000..431493f --- /dev/null +++ b/tests/sav/base_attr_abstract_alt5.res @@ -0,0 +1 @@ +alt/base_attr_abstract_alt5.nit:19,24--31: Error: `abstract` attributes cannot have an initial value. diff --git a/tests/sav/base_attr_annot.res b/tests/sav/base_attr_annot.res new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/tests/sav/base_attr_annot.res @@ -0,0 +1 @@ +1 diff --git a/tests/sav/base_attr_annot_1alt1.res b/tests/sav/base_attr_annot_1alt1.res new file mode 100644 index 0000000..4cd5256 --- /dev/null +++ b/tests/sav/base_attr_annot_1alt1.res @@ -0,0 +1 @@ +alt/base_attr_annot_1alt1.nit:33,9--11: Error: expected 0 argument(s) for `init`; got 1. See introduction at `standard::Object::init`. diff --git a/tests/sav/base_attr_annot_1alt1_alt1.res b/tests/sav/base_attr_annot_1alt1_alt1.res new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/tests/sav/base_attr_annot_1alt1_alt1.res @@ -0,0 +1 @@ +1 diff --git a/tests/sav/base_attr_annot_1alt1_alt2.res b/tests/sav/base_attr_annot_1alt1_alt2.res new file mode 100644 index 0000000..225f15c --- /dev/null +++ b/tests/sav/base_attr_annot_1alt1_alt2.res @@ -0,0 +1 @@ +alt/base_attr_annot_1alt1_alt2.nit:19,3--12: Error: `noautoinit` attributes cannot have an initial value. diff --git a/tests/sav/base_attr_annot_1alt1_alt3.res b/tests/sav/base_attr_annot_1alt1_alt3.res new file mode 100644 index 0000000..dac6bc0 --- /dev/null +++ b/tests/sav/base_attr_annot_1alt1_alt3.res @@ -0,0 +1 @@ +alt/base_attr_annot_1alt1_alt3.nit:19,3--20,10: Error: `autoinit` attributes cannot have an initial value. diff --git a/tests/sav/base_attr_annot_1alt1_alt4.res b/tests/sav/base_attr_annot_1alt1_alt4.res new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/tests/sav/base_attr_annot_1alt1_alt4.res @@ -0,0 +1 @@ +1 diff --git a/tests/sav/base_attr_annot_1alt1_alt5.res b/tests/sav/base_attr_annot_1alt1_alt5.res new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/tests/sav/base_attr_annot_1alt1_alt5.res @@ -0,0 +1 @@ +1 diff --git a/tests/sav/base_attr_annot_1alt1_alt6.res b/tests/sav/base_attr_annot_1alt1_alt6.res new file mode 100644 index 0000000..0bd4036 --- /dev/null +++ b/tests/sav/base_attr_annot_1alt1_alt6.res @@ -0,0 +1 @@ +alt/base_attr_annot_1alt1_alt6.nit:19,3--23,10: Error: `abstract` attributes cannot have an initial value. diff --git a/tests/sav/base_attr_annot_1alt1_alt7.res b/tests/sav/base_attr_annot_1alt1_alt7.res new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/tests/sav/base_attr_annot_1alt1_alt7.res @@ -0,0 +1 @@ +1 diff --git a/tests/sav/base_attr_annot_alt1.res b/tests/sav/base_attr_annot_alt1.res new file mode 100644 index 0000000..0b649c6 --- /dev/null +++ b/tests/sav/base_attr_annot_alt1.res @@ -0,0 +1 @@ +alt/base_attr_annot_alt1.nit:33,9--11: Error: expected 1 argument(s) for `init(a: Object)`; got 0. See introduction at `standard::Object::init`. diff --git a/tests/sav/base_attr_annot_alt2.res b/tests/sav/base_attr_annot_alt2.res new file mode 100644 index 0000000..1211ed7 --- /dev/null +++ b/tests/sav/base_attr_annot_alt2.res @@ -0,0 +1 @@ +Runtime error: Uninitialized attribute _a (alt/base_attr_annot_alt2.nit:18) diff --git a/tests/sav/base_attr_annot_alt3.res b/tests/sav/base_attr_annot_alt3.res new file mode 100644 index 0000000..fdf9917 --- /dev/null +++ b/tests/sav/base_attr_annot_alt3.res @@ -0,0 +1,2 @@ +alt/base_attr_annot_alt3.nit:19,3--20,10: Warning: superfluous `autoinit` on attribute. +1 diff --git a/tests/sav/base_attr_annot_alt4.res b/tests/sav/base_attr_annot_alt4.res new file mode 100644 index 0000000..c1a929e --- /dev/null +++ b/tests/sav/base_attr_annot_alt4.res @@ -0,0 +1 @@ +alt/base_attr_annot_alt4.nit:19,3--21,6: Error: `lazy` attributes need a value. diff --git a/tests/sav/base_attr_annot_alt5.res b/tests/sav/base_attr_annot_alt5.res new file mode 100644 index 0000000..21b6b60 --- /dev/null +++ b/tests/sav/base_attr_annot_alt5.res @@ -0,0 +1 @@ +alt/base_attr_annot_alt5.nit:19,3--22,10: Error: `readonly` attributes need a value. diff --git a/tests/sav/base_attr_annot_alt6.res b/tests/sav/base_attr_annot_alt6.res new file mode 100644 index 0000000..a594cce --- /dev/null +++ b/tests/sav/base_attr_annot_alt6.res @@ -0,0 +1 @@ +Runtime error: Abstract method `a` called on `B` (alt/base_attr_annot_alt6.nit:18) diff --git a/tests/sav/base_attr_annot_alt7.res b/tests/sav/base_attr_annot_alt7.res new file mode 100644 index 0000000..75208d1 --- /dev/null +++ b/tests/sav/base_attr_annot_alt7.res @@ -0,0 +1 @@ +alt/base_attr_annot_alt7.nit:19,3--24,10: Error: `lateinit` attributes need a value. diff --git a/tests/sav/base_do_block.res b/tests/sav/base_do_block.res new file mode 100644 index 0000000..f99d451 --- /dev/null +++ b/tests/sav/base_do_block.res @@ -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 diff --git a/tests/sav/base_import_alt3.res b/tests/sav/base_import_alt3.res index 4fcab0a..debc62f 100644 --- a/tests/sav/base_import_alt3.res +++ b/tests/sav/base_import_alt3.res @@ -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. diff --git a/tests/sav/base_init_setter.res b/tests/sav/base_init_setter.res new file mode 100644 index 0000000..a594e14 --- /dev/null +++ b/tests/sav/base_init_setter.res @@ -0,0 +1,3 @@ +1 + +1 diff --git a/tests/sav/error_class_glob.res b/tests/sav/error_class_glob.res index 38a9af9..2fd90b2 100644 --- a/tests/sav/error_class_glob.res +++ b/tests/sav/error_class_glob.res @@ -1 +1,12 @@ +../lib/standard/kernel.nit:24,1--95,3: Error: `kernel#Object` does not specialize `module_0#Object`. Possible duplication of the root class `Object`? ../lib/standard/kernel.nit:97,1--111,3: Error: `kernel#Sys` does not specialize `module_0#Object`. Possible duplication of the root class `Object`? +../lib/standard/kernel.nit:124,1--182,3: Error: `kernel#Comparable` does not specialize `module_0#Object`. Possible duplication of the root class `Object`? +../lib/standard/kernel.nit:184,1--221,3: Error: `kernel#Discrete` does not specialize `module_0#Object`. Possible duplication of the root class `Object`? +../lib/standard/kernel.nit:223,1--240,3: Error: `kernel#Cloneable` does not specialize `module_0#Object`. Possible duplication of the root class `Object`? +../lib/standard/kernel.nit:242,1--297,3: Error: `kernel#Numeric` does not specialize `module_0#Object`. Possible duplication of the root class `Object`? +../lib/standard/kernel.nit:303,1--326,3: Error: `kernel#Bool` does not specialize `module_0#Object`. Possible duplication of the root class `Object`? +../lib/standard/kernel.nit:328,1--410,3: Error: `kernel#Float` does not specialize `module_0#Object`. Possible duplication of the root class `Object`? +../lib/standard/kernel.nit:412,1--514,3: Error: `kernel#Byte` does not specialize `module_0#Object`. Possible duplication of the root class `Object`? +../lib/standard/kernel.nit:516,1--707,3: Error: `kernel#Int` does not specialize `module_0#Object`. Possible duplication of the root class `Object`? +../lib/standard/kernel.nit:709,1--849,3: Error: `kernel#Char` does not specialize `module_0#Object`. Possible duplication of the root class `Object`? +../lib/standard/kernel.nit:851,1--858,3: Error: `kernel#Pointer` does not specialize `module_0#Object`. Possible duplication of the root class `Object`? diff --git a/tests/sav/error_mod_unk.res b/tests/sav/error_mod_unk.res index 20bc8ca..29ce68b 100644 --- a/tests/sav/error_mod_unk.res +++ b/tests/sav/error_mod_unk.res @@ -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. diff --git a/tests/sav/niti/base_attr_annot_alt2.res b/tests/sav/niti/base_attr_annot_alt2.res new file mode 100644 index 0000000..f51ab75 --- /dev/null +++ b/tests/sav/niti/base_attr_annot_alt2.res @@ -0,0 +1 @@ +Runtime error: Uninitialized attribute _a (alt/base_attr_annot_alt2.nit:34) diff --git a/tests/sav/test_ffi_c_primitives.res b/tests/sav/test_ffi_c_primitives.res index c68bddc..1a3828f 100644 --- a/tests/sav/test_ffi_c_primitives.res +++ b/tests/sav/test_ffi_c_primitives.res @@ -3,4 +3,5 @@ true k 2234 12345.0 +0x12 hello world diff --git a/tests/sav/test_keep_going.res b/tests/sav/test_keep_going.res new file mode 100644 index 0000000..346b309 --- /dev/null +++ b/tests/sav/test_keep_going.res @@ -0,0 +1 @@ +test_keep_going.nit:15,11--14: Error: class `Fail` not found in module `test_keep_going`. diff --git a/tests/sav/xymus_net.res b/tests/sav/xymus_net.res index 112bdb0..64d374b 100644 --- a/tests/sav/xymus_net.res +++ b/tests/sav/xymus_net.res @@ -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. diff --git a/tests/test_ffi_c_primitives.nit b/tests/test_ffi_c_primitives.nit index ffac1cd..2295927 100644 --- a/tests/test_ffi_c_primitives.nit +++ b/tests/test_ffi_c_primitives.nit @@ -1,7 +1,5 @@ # This file is part of NIT ( http://www.nitlanguage.org ). # -# Copyright 2011-2013 Alexis Laferrière -# # 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 @@ -14,29 +12,39 @@ # 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) diff --git a/tests/test_keep_going.nit b/tests/test_keep_going.nit new file mode 100755 index 0000000..b3bedaa --- /dev/null +++ b/tests/test_keep_going.nit @@ -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