--- /dev/null
+#!/usr/bin/env nit
+#
+# This file is part of NIT ( http://www.nitlanguage.org ).
+# This program is public domain
+
+# Task: 24 game
+# SEE: <http://rosettacode.org/wiki/24_game>
+
+redef class Char
+ fun is_op: Bool do return "-+/*".has(self)
+end
+
+# Get `numbers` and `operands` from string `operation` collect with `gets` in `main` function
+# Fill `numbers` and `operands` array with previous extraction
+fun exportation(operation: String, numbers: Array[Int], operands: Array[Char]) do
+ var previous_char: nullable Char = null
+ var number: nullable Int = null
+ var negative = false
+
+ for i in operation.length.times do
+ var current_char = operation[i]
+ var current_int = current_char.to_i
+
+ if (previous_char == null or previous_char.is_op) and current_char == '-' then
+ negative = true
+ continue
+ end
+
+ if current_char.is_digit then
+ if number == null then
+ number = current_int
+ else
+ number = number * 10 + current_int
+ end
+ end
+
+ if negative and (current_char.is_op or i == operation.length - 1) then
+ number = number - number * 2
+ negative = false
+ end
+
+ if (current_char.is_op or i == operation.length - 1) and number != null then
+ numbers.add(number)
+ number = null
+ end
+
+ if not negative and current_char.is_op then
+ operands.add(current_char)
+ end
+ previous_char = current_char
+ end
+ # Update `numbers` and `operands` array in main function with pointer
+end
+
+# Create random numbers between 1 to 9
+fun random: Array[Int] do
+ return [for i in 4.times do 1 + 9.rand]
+end
+
+# Make mathematical operation with `numbers` and `operands` and add the operation result into `random_numbers`
+fun calculation(random_numbers, numbers: Array[Int], operands: Array[Char]) do
+ var number = 0
+ var temp_numbers = numbers.clone
+
+ while temp_numbers.length > 1 do
+ var operand = operands.shift
+ var a = temp_numbers.shift
+ var b = temp_numbers.shift
+
+ if operand == '+' then number = a + b
+ if operand == '-' then number = a - b
+ if operand == '*' then number = a * b
+ if operand == '/' then number = a / b
+
+ temp_numbers.unshift(number)
+ end
+ if number != 0 then random_numbers.add(number)
+end
+
+# Check if used `numbers` exist in the `random_numbers` created
+fun numbers_exists(random_numbers, numbers: Array[Int]): Bool do
+ for number in numbers do
+ if not random_numbers.count(number) >= numbers.count(number) then return false
+ end
+ return true
+end
+
+# Remove `numbers` when they are used
+fun remove_numbers(random_numbers, numbers: Array[Int]) do
+ for number in numbers do random_numbers.remove(number)
+end
+
+# Check if the mathematical `operation` is valid
+fun check(operation: String): Bool do
+ var previous_char: nullable Char = null
+ var next_char: nullable Char = null
+ var next_1_char: nullable Char = null
+
+ for i in operation.length.times do
+ var current_char = operation[i]
+
+ if i + 1 < operation.length then
+ next_char = operation[i + 1]
+ if i + 2 < operation.length then
+ next_1_char = operation[i + 2]
+ else
+ next_1_char = null
+ end
+ else
+ next_char = null
+ end
+
+ if not current_char.is_op and not current_char.is_digit then return false
+ if next_char == null and current_char.is_op then return false
+
+ if previous_char == null then
+ if next_char == null or next_1_char == null then return false
+ if current_char == '-' and not next_char.is_digit then return false
+ if current_char != '-' and not current_char.is_digit then return false
+ else
+ if next_char != null then
+ if previous_char.is_digit and current_char.is_op and
+ not (next_char == '-' and next_1_char != null and
+ next_1_char.is_digit or next_char.is_digit) then
+ return false
+ end
+ end
+ end
+ previous_char = current_char
+ end
+ return true
+end
+
+var random_numbers = new Array[Int]
+var operation = ""
+
+random_numbers = random
+while not random_numbers.has(24) and random_numbers.length > 1 do
+ var numbers = new Array[Int]
+ var operands = new Array[Char]
+
+ print "numbers: " + random_numbers.join(", ")
+ operation = gets
+ if check(operation) then
+ exportation(operation, numbers, operands)
+ if numbers_exists(random_numbers, numbers) then
+ calculation(random_numbers, numbers, operands)
+ remove_numbers(random_numbers, numbers)
+ else
+ print "NUMBERS ERROR!"
+ end
+ else
+ print "STRING ERROR!"
+ end
+end
+
+if random_numbers.has(24) then print "CONGRATULATIONS" else print "YOU LOSE"
--- /dev/null
+# 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
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
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]
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:
#
# 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
# 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"
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
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
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
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
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))
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
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}"
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
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
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
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
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)
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
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
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)
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
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)
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
# 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)
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
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
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)
return
end
+ self.mtype = mtype
+
if mpropdef != null then
mpropdef.static_mtype = mtype
end
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
# 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
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)
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
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
end
if errcount != self.error_count then
self.check_errors
- break
end
for na in vannot.annotations do
var p = na.parent
end
if errcount != self.error_count then
self.check_errors
- break
end
end
self.check_errors
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)
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
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
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
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(", ")}"
#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)
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)
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
# 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
redef class AVarFormExpr
# The associated variable
- var variable: nullable Variable
+ var variable: nullable Variable is writable
end
redef class ACallFormExpr
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`
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
v.set_variable(self, variable, rettype)
- self.is_typed = true
+ self.is_typed = rettype != null
end
end
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
var mtype = self.attr_type
v.visit_expr_subtype(self.n_value, mtype)
- self.is_typed = true
+ self.is_typed = mtype != null
end
end
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
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2015 Julien Pagès <julien.pages@lirmm.fr>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Single-Static Assignment algorithm from an AST
+module ssa
+
+import semantize
+import astbuilder
+
+# Represent a sequence of the program
+# A basic block is composed of several instructions without a jump
+class BasicBlock
+ # First instruction of the basic block
+ var first: ANode is noinit
+
+ # Last instruction of the basic block
+ var last: ANode is noinit
+
+ # Direct successors
+ var successors = new Array[BasicBlock]
+
+ # Direct predecessors
+ var predecessors = new Array[BasicBlock]
+
+ # Parts of AST that contain a read to a variable
+ var read_sites = new Array[AVarFormExpr]
+
+ # Parts of AST that contain a write to a variable
+ var write_sites = new Array[AVarFormExpr]
+
+ # Parts of AST that contain a variable access (read or write)
+ var variables_sites = new Array[AExpr]
+
+ # The iterated dominance frontier of this block
+ # i.e. the set of blocks this block dominate directly or indirectly
+ var dominance_frontier: Array[BasicBlock] = new Array[BasicBlock] is lazy
+
+ # Self is the old block to link to the new,
+ # The two blocks are not linked if the current ends with a `AReturnExpr` or `ABreakExpr`
+ # i.e. self is the predecessor of `successor`
+ # `successor` The successor block
+ fun link(successor: BasicBlock)
+ do
+ # Do not link the two blocks if the current block end with a return, break or continue
+ if last isa AReturnExpr or last isa ABreakExpr or last isa AContinueExpr then return
+
+ successors.add(successor)
+ successor.predecessors.add(self)
+ end
+
+ # Self is the old block to link to the new
+ # i.e. self is the predecessor of `successor`
+ # `successor` The successor block
+ fun link_special(successor: BasicBlock)
+ do
+ # Link the two blocks even if the current block ends with a return or a break
+ successors.add(successor)
+ successor.predecessors.add(self)
+ end
+
+ # Add the `block` to the dominance frontier of this block
+ fun add_df(block: BasicBlock)
+ do
+ dominance_frontier.add(block)
+
+ # Add this block recursively in super-blocks to compute the iterated
+ # dominance frontier
+ for successor in block.successors do
+ # If this successor has not already been add to the dominance frontier
+ if not dominance_frontier.has(successor) then
+ add_df(successor)
+ end
+ end
+ end
+
+ # Compute recursively the dominance frontier of self block and its successors
+ private fun compute_df
+ do
+ # Treat each block only one time
+ df_computed = true
+
+ for s in successors do
+ add_df(s)
+
+ if not s.df_computed then s.compute_df
+ end
+ end
+
+ # Used to handle recursions by treating only one time each block
+ var treated: Bool = false
+
+ # Used to dump the BasicBlock to dot
+ var treated_debug: Bool = false
+
+ # If true, the iterated dominance frontier of this block has been computed
+ var df_computed: Bool = false
+
+ # Indicate the BasicBlock is newly created and needs to be updated
+ var need_update: Bool = false
+
+ # Indicate if the variables renaming step has been made for this block
+ var is_renaming: Bool = false
+
+ # The variables that are accessed in this block
+ var variables = new Array[Variable] is lazy
+
+ # The PhiFunction this block contains at the beginning
+ var phi_functions = new Array[PhiFunction] is lazy
+end
+
+# Contain the currently analyzed propdef
+class SSA
+ # The currently analyzed APropdef
+ var propdef: APropdef
+
+ # The PhiFunction `current_propdef` contains
+ var phi_functions = new Array[PhiFunction]
+
+ # Recursively generate the basic blocks for this propdef
+ fun generate_basic_blocks
+ do
+ propdef.generate_basic_blocks(self)
+ end
+end
+
+redef class Variable
+ # The expressions of AST of this variable depends
+ var dep_exprs = new Array[AExpr]
+
+ # The blocks in which this variable is assigned
+ var assignment_blocks: Array[BasicBlock] = new Array[BasicBlock] is lazy
+
+ # Part of the program where this variable is read
+ var read_blocks: Array[BasicBlock] = new Array[BasicBlock] is lazy
+
+ # The stack of this variable, used for SSA renaming
+ var stack = new Array[Variable] is lazy
+
+ # The original Variable in case of renaming
+ var original_variable: nullable Variable = self
+
+ # If true, this variable is a parameter of a method
+ var parameter: Bool = false
+end
+
+# A PhiFunction is a kind of Variable used in SSA-construction,
+# it is placed at the beginning of a BasicBlock with many incoming blocks
+class PhiFunction
+ super Variable
+
+ # The dependences of this variable for SSA-Algorithm
+ var dependences = new Array[Couple[Variable, BasicBlock]]
+
+ # The position in the AST of the phi-function
+ var block: BasicBlock
+
+ # Set the dependences for the phi-function
+ # *`block` BasicBlock in which we go through the dominance-frontier
+ # *`v` The variable to looking for
+ fun add_dependences(block: BasicBlock, v: Variable)
+ do
+ # Look in which blocks of DF(block) `v` has been assigned
+ for b in block.predecessors do
+ if v.assignment_blocks.has(b) then
+ var dep = new Couple[Variable, BasicBlock](v, b)
+ dependences.add(dep)
+ end
+ end
+ end
+
+ # Print the PhiFunction with all its dependences
+ redef fun to_s: String
+ do
+ var s = ""
+ s += " dependences = [ "
+ for d in dependences do
+ s += d.first.to_s + " "
+ end
+ s += "]"
+
+ return s
+ end
+end
+
+redef class APropdef
+ # The variables contained in the body on this propdef
+ var variables: HashSet[Variable] = new HashSet[Variable] is lazy
+
+ # The first basic block of the code
+ var basic_block: nullable BasicBlock
+
+ # If true, the basic blocks where generated
+ var is_generated: Bool = false
+
+ # Generate all basic blocks for this code
+ fun generate_basic_blocks(ssa: SSA) is abstract
+
+ # Contain all AST-parts related to object mechanisms the propdef has:
+ # instantiation, method dispatch, attribute access, subtyping-test
+ var object_sites: Array[AExpr] = new Array[AExpr]
+
+ # Compute the three steps of SSA-algorithm
+ # `ssa` A new instance of SSA class initialized with `self`
+ fun compute_ssa(ssa: SSA)
+ do
+ if is_generated then return
+
+ # The first step is to generate the basic blocks
+ generate_basic_blocks(ssa)
+
+ # The propdef has no body (abstract)
+ if not is_generated then return
+
+ # Once basic blocks were generated, compute SSA algorithm
+ compute_phi(ssa)
+ rename_variables(ssa)
+ ssa_destruction(ssa)
+ end
+
+ # Compute the first phase of SSA algorithm: placing phi-functions
+ fun compute_phi(ssa: SSA)
+ do
+ var root_block = basic_block.as(not null)
+
+ # Compute the iterated dominance frontier of the graph of basic blocks
+ root_block.compute_df
+
+ # Places where a phi-function is added per variable
+ var phi_blocks = new HashMap[Variable, Array[BasicBlock]]
+
+ # For each variables in the propdef
+ for v in variables do
+ var phi_variables = new Array[BasicBlock]
+
+ var read_blocks = new Array[BasicBlock]
+ read_blocks.add_all(v.read_blocks)
+ read_blocks.add_all(v.assignment_blocks)
+
+ # While we have not treated each part accessing `v`
+ while not read_blocks.is_empty do
+ # Remove a block from the array
+ var block = read_blocks.shift
+
+ # For each block in the dominance frontier of `block`
+ for df in block.dominance_frontier do
+ # If we have not yet put a phi-function at the beginning of this block
+ if not phi_variables.has(df) then
+ phi_variables.add(df)
+
+ # Create a new phi-function and set its dependences
+ var phi = new PhiFunction("phi", df)
+ phi.add_dependences(df, v)
+ phi.block = df
+ phi.original_variable = phi
+ phi.declared_type = v.declared_type
+
+ # Indicate this phi-function is assigned in this block
+ phi.assignment_blocks.add(block)
+ ssa.phi_functions.add(phi)
+
+ # Add a phi-function at the beginning of df for variable v
+ df.phi_functions.add(phi)
+
+ if not v.read_blocks.has(df) or not v.assignment_blocks.has(df) then read_blocks.add(df)
+ end
+ end
+ end
+
+ # Add `phi-variables` to the global map
+ phi_blocks[v] = phi_variables
+ end
+ end
+
+ # Compute the second phase of SSA algorithm: renaming variables
+ # NOTE: `compute_phi` must has been called before
+ fun rename_variables(ssa: SSA)
+ do
+ # A counter for each variable
+ # The key is the variable, the value the number of assignment into the variable
+ var counter = new HashMap[Variable, Int]
+
+ for v in variables do
+ counter[v] = 0
+ v.stack.push(v)
+ end
+
+ for phi in ssa.phi_functions do counter[phi] = 0
+
+ # Launch the recursive renaming from the root block
+ rename(basic_block.as(not null), counter, ssa)
+ end
+
+ # Recursively rename each variable from `block`
+ # *`block` The starting basic block
+ # *`counter` The key is the variable, the value the number of assignment into the variable
+ fun rename(block: BasicBlock, counter: HashMap[Variable, Int], ssa: SSA)
+ do
+ if block.is_renaming then return
+
+ block.is_renaming = true
+
+ # For each phi-function of this block
+ for phi in block.phi_functions do
+ generate_name(phi, counter, block.first, ssa)
+
+ # Replace the phi into the block
+ block.phi_functions[block.phi_functions.index_of(phi)] = phi.original_variable.stack.last.as(PhiFunction)
+ end
+
+ # For each variable read in `block`
+ for vread in block.read_sites do
+ # Replace the old variable in AST
+ vread.variable = vread.variable.original_variable.stack.last
+ end
+
+ # For each variable write
+ for vwrite in block.write_sites do
+ generate_name(vwrite.variable.as(not null), counter, vwrite, ssa)
+
+ var new_version = vwrite.variable.original_variable.stack.last
+
+ # Set dependence of the new variable
+ if vwrite isa AVarReassignExpr then
+ new_version.dep_exprs.add(vwrite.n_value)
+ else if vwrite isa AVarAssignExpr then
+ new_version.dep_exprs.add(vwrite.n_value)
+ end
+
+ # Replace the old variable by the last created
+ vwrite.variable = new_version
+ end
+
+ # Rename occurrence of old names in phi-function
+ for successor in block.dominance_frontier do
+ for sphi in successor.phi_functions do
+ # Go over the couples in the phi dependences to rename variables
+ for couple in sphi.dependences do
+ if couple.second == block then
+ # Rename this variable
+ couple.first = couple.first.original_variable.stack.last
+ end
+ end
+ end
+ end
+
+ # Recurse in successor blocks
+ for successor in block.successors do
+ rename(successor, counter, ssa)
+ end
+
+ # Pop old names off the stack for each phi-function
+ for phi in block.phi_functions do
+ if not phi.stack.is_empty then phi.stack.pop
+ end
+ end
+
+ # Generate a new version of the variable `v` and return it
+ # *`v` The variable for which we generate a name
+ # *`counter` The key is the variable, the value the number of assignment into the variable
+ # *`expr` The AST node in which the assignment of v is made
+ # *`ssa` The instance of SSA
+ fun generate_name(v: Variable, counter: HashMap[Variable, Int], expr: ANode, ssa: SSA): Variable
+ do
+ var original_variable = v.original_variable.as(not null)
+
+ var i = counter[original_variable]
+
+ var new_version: Variable
+
+ # Create a new version of Variable
+ if original_variable isa PhiFunction then
+ var block = original_variable.block
+ new_version = new PhiFunction(original_variable.name + i.to_s, block)
+ new_version.dependences.add_all(original_variable.dependences)
+ ssa.phi_functions.add(new_version)
+ else
+ new_version = new Variable(original_variable.name + i.to_s)
+ new_version.declared_type = expr.as(AVarFormExpr).variable.declared_type
+ variables.add(new_version)
+ end
+
+ # Recopy the fields into the new version
+ new_version.location = expr.location
+ new_version.original_variable = original_variable
+
+ # Push a new version on the stack
+ original_variable.stack.add(new_version)
+ counter[v] = i + 1
+
+ return new_version
+ end
+
+ # Transform SSA-representation into an executable code (delete phi-functions)
+ # `ssa` Current instance of SSA
+ fun ssa_destruction(ssa: SSA)
+ do
+ var builder = new ASTBuilder(mpropdef.mclassdef.mmodule, mpropdef.mclassdef.bound_mtype)
+
+ # Iterate over all phi-functions
+ for phi in ssa.phi_functions do
+ for dep in phi.dependences do
+ # dep.second is the block where we need to create a varassign
+ var var_read = builder.make_var_read(dep.first, dep.first.declared_type.as(not null))
+ var nvar = builder.make_var_assign(dep.first, var_read)
+
+ var block = dep.second.last.parent
+
+ # This variable read must be add to a ABlockExpr
+ if block isa ABlockExpr then
+ block.add(nvar)
+ end
+
+ propagate_dependences(phi, phi.block)
+ ssa.propdef.variables.add(dep.first)
+ end
+ end
+ end
+
+ # Propagate the dependences of the phi-functions into following variables
+ # `phi` The PhiFunction
+ # `block` Current block where we propagate dependences
+ fun propagate_dependences(phi: PhiFunction, block: BasicBlock)
+ do
+ # Treat each block once
+ if block.treated then return
+
+ # For each variable access site in the block
+ for site in block.variables_sites do
+ if site isa AVarExpr then
+ # Propagate the dependences of the phi-function in variables after the phi
+ for dep in phi.dependences do
+ for expr in dep.first.dep_exprs do
+ if site.variable.dep_exprs.has(expr) then break
+
+ if dep.first.original_variable == site.variable.original_variable then
+ site.variable.dep_exprs.add(expr)
+ end
+ end
+ end
+ else
+ # The site is a variable write, we stop the propagation
+ return
+ end
+ end
+
+ block.treated = true
+
+ # If we do not meet a variable write, continue the propagation
+ for b in block.successors do propagate_dependences(phi, b)
+ end
+end
+
+redef class AAttrPropdef
+ redef fun generate_basic_blocks(ssa: SSA)
+ do
+ basic_block = new BasicBlock
+ basic_block.first = self
+ basic_block.last = self
+
+ # Add the self variable
+ if self.selfvariable != null then variables.add(selfvariable.as(not null))
+
+ # Recursively goes into the nodes
+ if n_block != null then
+ n_block.generate_basic_blocks(ssa, basic_block.as(not null))
+ is_generated = true
+ end
+ end
+end
+
+redef class AMethPropdef
+
+ # The return variable of the propdef
+ # Create an empty variable for the return of the method
+ # and treat returns like variable assignments
+ var returnvar: Variable = new Variable("returnvar")
+
+ redef fun generate_basic_blocks(ssa: SSA)
+ do
+ basic_block = new BasicBlock
+ basic_block.first = self
+ basic_block.last = self
+
+ # If the method has a signature
+ if n_signature != null then
+ for p in n_signature.n_params do
+ # Add parameters to the local variables
+ variables.add(p.variable.as(not null))
+ p.variable.parameter = true
+ end
+ end
+
+ # Add the return variable
+ variables.add(returnvar)
+
+ # Add the self variable
+ if self.selfvariable != null then variables.add(selfvariable.as(not null))
+
+ # Recursively goes into the nodes
+ if n_block != null then
+ n_block.generate_basic_blocks(ssa, basic_block.as(not null))
+ is_generated = true
+ end
+ end
+end
+
+# Utility class for dump basic block and SSA output to dot files
+class BlockDebug
+ # The output file
+ var file: FileWriter
+
+ # Dump all the hierarchy of BasicBlock from `block` to the leaves
+ fun dump(block: BasicBlock)
+ do
+ # Write the basic blocks hierarchy in output file
+ file.write("digraph basic_blocks\n\{\n")
+ var i = 0
+ file.write(print_block(block, i))
+ file.write("\n\}")
+
+ file.close
+ end
+
+ # Print all the block recursively from `block` to the leaves
+ # *`block` The root BasicBlock
+ # *`i` Used for the recursion
+ private fun print_block(block: BasicBlock, i: Int): String
+ do
+ # Precise the type and location of the begin and end of current block
+ var s = "block{block.hash.to_s} [shape=record, label="+"\"\{"
+ s += "block" + block.to_s.escape_to_dot
+ s += "|\{" + block.first.location.file.filename.to_s + block.first.location.line_start.to_s
+ s += " | " + block.first.to_s.escape_to_dot
+
+ # Print phi-functions if any
+ for phi in block.phi_functions do
+ s += " | " + phi.to_s.escape_to_dot + " "
+ end
+
+ s += "}|\{" + block.last.location.file.filename.to_s + block.last.location.line_start.to_s
+ s += " | " + block.last.to_s.escape_to_dot + "}}\"];"+ "\n"
+
+ i += 1
+ block.treated_debug = true
+
+ for b in block.successors do
+ # Print edges to successors
+ s += "block{block.hash.to_s} -> " + " block{b.hash.to_s};\n"
+
+ # Recursively print child blocks
+ if not b.treated_debug then s += print_block(b, i)
+ end
+
+ return s
+ end
+end
+
+redef class AExpr
+ # Generate recursively basic block for this expression
+ # *`ssa` An instance of the SSA class initialized with the enclosing `APropdef`
+ # *`old_block` A basic block not completely filled
+ # Return the last created block (the last block can be nested)
+ fun generate_basic_blocks(ssa: SSA, old_block: BasicBlock): BasicBlock
+ do
+ return old_block
+ end
+end
+
+redef class AVarFormExpr
+ # The original variable
+ var original_variable: nullable Variable = variable
+end
+
+redef class AVarExpr
+ redef fun generate_basic_blocks(ssa, old_block)
+ do
+ self.variable.as(not null).read_blocks.add(old_block)
+ old_block.variables.add(self.variable.as(not null))
+
+ self.variable.as(not null).original_variable = self.variable.as(not null)
+ # Save this read site in the block
+ old_block.read_sites.add(self)
+ old_block.variables_sites.add(self)
+
+ return old_block
+ end
+end
+
+redef class AVardeclExpr
+ redef fun generate_basic_blocks(ssa, old_block)
+ do
+ var decl = self.variable.as(not null)
+
+ # Add the corresponding variable to the enclosing mpropdef
+ ssa.propdef.variables.add(decl)
+
+ decl.original_variable = decl
+ decl.assignment_blocks.add(old_block)
+ old_block.variables.add(decl)
+
+ if self.n_expr != null then
+ self.variable.dep_exprs.add(self.n_expr.as(not null))
+ old_block = self.n_expr.generate_basic_blocks(ssa, old_block)
+ end
+
+ return old_block
+ end
+end
+
+redef class AVarAssignExpr
+ redef fun generate_basic_blocks(ssa, old_block)
+ do
+ self.variable.as(not null).assignment_blocks.add(old_block)
+ old_block.variables.add(self.variable.as(not null))
+ self.variable.as(not null).original_variable = self.variable.as(not null)
+
+ # Save this write site in the block
+ old_block.write_sites.add(self)
+ old_block.variables_sites.add(self)
+
+ ssa.propdef.variables.add(self.variable.as(not null))
+
+ return self.n_value.generate_basic_blocks(ssa, old_block)
+ end
+end
+
+redef class AVarReassignExpr
+ redef fun generate_basic_blocks(ssa, old_block)
+ do
+ self.variable.as(not null).assignment_blocks.add(old_block)
+ old_block.variables.add(self.variable.as(not null))
+ self.variable.as(not null).original_variable = self.variable.as(not null)
+
+ # Save this write site in the block
+ old_block.write_sites.add(self)
+ old_block.variables_sites.add(self)
+
+ ssa.propdef.variables.add(self.variable.as(not null))
+ return self.n_value.generate_basic_blocks(ssa, old_block)
+ end
+end
+
+redef class ABreakExpr
+ redef fun generate_basic_blocks(ssa, old_block)
+ do
+ # Finish the old block
+ old_block.last = self
+
+ return old_block
+ end
+end
+
+redef class AContinueExpr
+ redef fun generate_basic_blocks(ssa, old_block)
+ do
+ return old_block
+ end
+end
+
+redef class AReturnExpr
+ redef fun generate_basic_blocks(ssa, old_block)
+ do
+ # The return just set the current block and stop the recursion
+ if self.n_expr != null then
+ old_block = self.n_expr.generate_basic_blocks(ssa, old_block)
+
+ # Store the return expression in the dependences of the dedicated returnvar
+ if ssa.propdef isa AMethPropdef then
+ ssa.propdef.as(AMethPropdef).returnvar.dep_exprs.add(n_expr.as(not null))
+ end
+ end
+
+ old_block.last = self
+
+ return old_block
+ end
+end
+
+redef class AAssertExpr
+ redef fun generate_basic_blocks(ssa, old_block)
+ do
+ self.n_expr.generate_basic_blocks(ssa, old_block)
+
+ # The condition of the assert is the last expression of the previous block
+ old_block.last = self.n_expr
+
+ # The block if the assert fail
+ var block_false = new BasicBlock
+
+ if self.n_else != null then
+ block_false.first = self.n_else.as(not null)
+ block_false.last = self.n_else.as(not null)
+ self.n_else.generate_basic_blocks(ssa, block_false)
+ else
+ block_false.first = self
+ block_false.first = self
+ end
+
+ old_block.link(block_false)
+
+ # The block if the assert is true: the execution continue
+ var block_true = new BasicBlock
+ block_true.first = self
+ block_true.last = self
+
+ old_block.link(block_true)
+
+ return block_true
+ end
+end
+
+redef class AOrExpr
+ redef fun generate_basic_blocks(ssa, old_block)
+ do
+ self.n_expr.generate_basic_blocks(ssa, old_block)
+ return self.n_expr2.generate_basic_blocks(ssa, old_block)
+ end
+end
+
+redef class AImpliesExpr
+ redef fun generate_basic_blocks(ssa, old_block)
+ do
+ self.n_expr.generate_basic_blocks(ssa, old_block)
+ return self.n_expr2.generate_basic_blocks(ssa, old_block)
+ end
+end
+
+redef class AAndExpr
+ redef fun generate_basic_blocks(ssa, old_block)
+ do
+ self.n_expr.generate_basic_blocks(ssa, old_block)
+ return self.n_expr2.generate_basic_blocks(ssa, old_block)
+ end
+end
+
+redef class ANotExpr
+ redef fun generate_basic_blocks(ssa, old_block)
+ do
+ return self.n_expr.generate_basic_blocks(ssa, old_block)
+ end
+end
+
+redef class AOrElseExpr
+ redef fun generate_basic_blocks(ssa, old_block)
+ do
+ self.n_expr.generate_basic_blocks(ssa, old_block)
+ return self.n_expr2.generate_basic_blocks(ssa, old_block)
+ end
+end
+
+redef class AArrayExpr
+ redef fun generate_basic_blocks(ssa, old_block)
+ do
+ for nexpr in self.n_exprs do
+ old_block = nexpr.generate_basic_blocks(ssa, old_block)
+ end
+
+ return old_block
+ end
+end
+
+redef class ASuperstringExpr
+ redef fun generate_basic_blocks(ssa, old_block)
+ do
+ for nexpr in self.n_exprs do old_block = nexpr.generate_basic_blocks(ssa, old_block)
+
+ return old_block
+ end
+end
+
+redef class ACrangeExpr
+ redef fun generate_basic_blocks(ssa, old_block)
+ do
+ self.n_expr.generate_basic_blocks(ssa, old_block)
+ return self.n_expr2.generate_basic_blocks(ssa, old_block)
+ end
+end
+
+redef class AOrangeExpr
+ redef fun generate_basic_blocks(ssa, old_block)
+ do
+ self.n_expr.generate_basic_blocks(ssa, old_block)
+ return self.n_expr2.generate_basic_blocks(ssa, old_block)
+ end
+end
+
+redef class AIsaExpr
+ redef fun generate_basic_blocks(ssa, old_block)
+ do
+ ssa.propdef.object_sites.add(self)
+
+ return self.n_expr.generate_basic_blocks(ssa, old_block)
+ end
+end
+
+redef class AAsCastExpr
+ redef fun generate_basic_blocks(ssa, old_block)
+ do
+ ssa.propdef.object_sites.add(self)
+
+ return self.n_expr.generate_basic_blocks(ssa, old_block)
+ end
+end
+
+redef class AAsNotnullExpr
+ redef fun generate_basic_blocks(ssa, old_block)
+ do
+ return self.n_expr.generate_basic_blocks(ssa, old_block)
+ end
+end
+
+redef class AParExpr
+ redef fun generate_basic_blocks(ssa, old_block)
+ do
+ return self.n_expr.generate_basic_blocks(ssa, old_block)
+ end
+end
+
+redef class AOnceExpr
+ redef fun generate_basic_blocks(ssa, old_block)
+ do
+ return self.n_expr.generate_basic_blocks(ssa, old_block)
+ end
+end
+
+redef class ASendExpr
+ redef fun generate_basic_blocks(ssa, old_block)
+ do
+ # A call does not finish the current block,
+ # because we create intra-procedural basic blocks here
+
+ ssa.propdef.object_sites.add(self)
+
+ # Recursively goes into arguments to find variables if any
+ for e in self.raw_arguments do e.generate_basic_blocks(ssa, old_block)
+
+ return self.n_expr.generate_basic_blocks(ssa, old_block)
+ end
+end
+
+redef class ASendReassignFormExpr
+ redef fun generate_basic_blocks(ssa, old_block)
+ do
+ self.n_expr.generate_basic_blocks(ssa, old_block)
+
+ ssa.propdef.object_sites.add(self)
+
+ # Recursively goes into arguments to find variables if any
+ for e in self.raw_arguments do e.generate_basic_blocks(ssa, old_block)
+
+ return self.n_value.generate_basic_blocks(ssa, old_block)
+ end
+end
+
+redef class ASuperExpr
+ redef fun generate_basic_blocks(ssa, old_block)
+ do
+ # Recursively goes into arguments to find variables if any
+ for arg in self.n_args.n_exprs do arg.generate_basic_blocks(ssa, old_block)
+
+ return old_block
+ end
+end
+
+redef class ANewExpr
+ redef fun generate_basic_blocks(ssa, old_block)
+ do
+ for e in self.n_args.n_exprs do e.generate_basic_blocks(ssa, old_block)
+
+ ssa.propdef.object_sites.add(self)
+
+ return old_block
+ end
+end
+
+redef class AAttrExpr
+ redef fun generate_basic_blocks(ssa, old_block)
+ do
+ ssa.propdef.object_sites.add(self)
+
+ return self.n_expr.generate_basic_blocks(ssa, old_block)
+ end
+end
+
+redef class AAttrAssignExpr
+ redef fun generate_basic_blocks(ssa, old_block)
+ do
+ ssa.propdef.object_sites.add(self)
+
+ return self.n_expr.generate_basic_blocks(ssa, old_block)
+ end
+end
+
+redef class AAttrReassignExpr
+ redef fun generate_basic_blocks(ssa, old_block)
+ do
+ ssa.propdef.object_sites.add(self)
+
+ return self.n_expr.generate_basic_blocks(ssa, old_block)
+ end
+end
+
+redef class AIssetAttrExpr
+ redef fun generate_basic_blocks(ssa, old_block)
+ do
+ return self.n_expr.generate_basic_blocks(ssa, old_block)
+ end
+end
+
+redef class ABlockExpr
+ # The block needs to know if a new block is created
+ redef fun generate_basic_blocks(ssa, old_block)
+ do
+ var last_block = old_block
+ var current_block: BasicBlock
+
+ # Recursively continue in the body of the block
+ for i in [0..self.n_expr.length[ do
+ current_block = self.n_expr[i].generate_basic_blocks(ssa, last_block)
+
+ if current_block.need_update then
+ if i < (self.n_expr.length-1) then
+ # Current_block must be filled
+ current_block.first = self.n_expr[i+1]
+ current_block.last = self.n_expr[i+1]
+ current_block.need_update = false
+ else
+ # Put the current block at the end of the block
+ current_block.first = last_block.last
+ current_block.last = last_block.last
+ end
+ end
+
+ if not current_block.last isa AEscapeExpr or current_block.last isa AReturnExpr then
+ # Re-affected the last block
+ current_block.last = self.n_expr[i]
+ end
+
+ last_block = current_block
+ end
+
+ return last_block
+ end
+end
+
+redef class AIfExpr
+ redef fun generate_basic_blocks(ssa, old_block)
+ do
+ # Terminate the previous block
+ old_block.last = self
+
+ # We start two new blocks if the if has two branches
+ var block_then = new BasicBlock
+
+ # Visit the test of the if
+ self.n_expr.generate_basic_blocks(ssa, old_block)
+
+ # Launch the recursion in two successors if they exist
+ if self.n_then != null then
+ old_block.link(block_then)
+
+ block_then.first = self.n_then.as(not null)
+ block_then.last = self.n_then.as(not null)
+ self.n_then.generate_basic_blocks(ssa, block_then)
+ end
+
+ var block_else = new BasicBlock
+
+ if self.n_else != null then
+ old_block.link(block_else)
+
+ block_else.first = self.n_else.as(not null)
+ block_else.last = self.n_else.as(not null)
+ self.n_else.generate_basic_blocks(ssa, block_else)
+ end
+
+ # Create a new BasicBlock to represent the two successor
+ # branches of the if
+ var new_block = new BasicBlock
+ new_block.first = self
+ new_block.last = self
+
+ if self.n_then != null then block_then.link(new_block)
+
+ # The new block needs to be filled by the caller
+ new_block.need_update = true
+
+ if block_else.predecessors.length != 0 then block_else.link(new_block)
+
+ return new_block
+ end
+end
+
+redef class AIfexprExpr
+ redef fun generate_basic_blocks(ssa, old_block)
+ do
+ # Terminate the previous block
+ old_block.last = self
+
+ # We start two new blocks if the if has two branches
+ var block_then = new BasicBlock
+
+ # Visit the test of the if
+ self.n_expr.generate_basic_blocks(ssa, old_block)
+
+ # Launch the recursion in two successors if they exist
+ old_block.link(block_then)
+
+ block_then.first = self.n_then
+ block_then.last = self.n_then
+ self.n_then.generate_basic_blocks(ssa, block_then)
+
+ var block_else = new BasicBlock
+
+ old_block.link(block_else)
+
+ block_else.first = self.n_else
+ block_else.last = self.n_else
+ self.n_else.generate_basic_blocks(ssa, block_else)
+
+ # Create a new BasicBlock to represent the two successor
+ # branches of the if
+ var new_block = new BasicBlock
+ new_block.first = self
+ new_block.last = self
+
+ block_then.link(new_block)
+
+ # The new block needs to be filled by the caller
+ new_block.need_update = true
+
+ block_else.link(new_block)
+
+ return new_block
+ end
+end
+
+redef class ADoExpr
+ redef fun generate_basic_blocks(ssa, old_block)
+ do
+ old_block.last = self
+
+ # The beginning of the block is the first instruction
+ var block = new BasicBlock
+ block.first = self.n_block.as(not null)
+ block.last = self.n_block.as(not null)
+
+ old_block.link(block)
+ return self.n_block.generate_basic_blocks(ssa, block)
+ end
+end
+
+redef class AWhileExpr
+ redef fun generate_basic_blocks(ssa, old_block)
+ do
+ old_block.last = self
+
+ # The beginning of the block is the test of the while
+ var block = new BasicBlock
+ block.first = self.n_expr
+ block.last = self.n_block.as(not null)
+
+ old_block.link(block)
+
+ self.n_expr.generate_basic_blocks(ssa, old_block)
+ var inside_block = self.n_block.generate_basic_blocks(ssa, block)
+
+ # Link the inside of the block to the previous block
+ block.link_special(old_block)
+
+ # Create a new Block after the while
+ var new_block = new BasicBlock
+ new_block.need_update = true
+
+ old_block.link_special(new_block)
+
+ return new_block
+ end
+end
+
+redef class ALoopExpr
+ redef fun generate_basic_blocks(ssa, old_block)
+ do
+ old_block.last = self
+
+ # The beginning of the block is the first instruction
+ var block = new BasicBlock
+ block.first = self.n_block.as(not null)
+ block.last = self.n_block.as(not null)
+
+ old_block.link(block)
+ self.n_block.generate_basic_blocks(ssa, block)
+
+ return block
+ end
+end
+
+redef class AForExpr
+ redef fun generate_basic_blocks(ssa, old_block)
+ do
+ old_block.last = self
+
+ # The beginning of the block is the first instruction
+ var block = new BasicBlock
+ block.first = self.n_expr
+ block.last = self.n_block.as(not null)
+
+ # Visit the test of the if
+ self.n_expr.generate_basic_blocks(ssa, block)
+
+ # Collect the variables declared in the for
+ for v in variables do
+ ssa.propdef.variables.add(v)
+ end
+
+ old_block.link(block)
+
+ block.link(old_block)
+
+ var new_block = new BasicBlock
+ new_block.need_update = true
+
+ return new_block
+ end
+end
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)
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2015 Julien Pagès <julien.pages@lirmm.fr>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# The compilation module of the VirtualMachine
+module compilation
+
+import variables_numbering
+import ssa
+
+redef class VirtualMachine
+
+ # The currently analyzed APropdef
+ var current_propdef: APropdef
+
+ redef fun new_frame(node, mpropdef, args)
+ do
+ # Save the current propdef
+ if node isa APropdef then self.current_propdef = node
+
+ return super
+ end
+end
+
+redef class APropdef
+
+ redef fun compile(vm)
+ do
+ super
+
+ # A new instance of SSA to analyze the self propdef
+ var ssa = new SSA(self)
+
+ # Generate basic_blocks and compute SSA-algorithm for this propdef
+ compute_ssa(ssa)
+ end
+
+ # Redef to add the same position to a new version of a Variable than the original variable
+ redef fun generate_name(v, counter, expr, ssa)
+ do
+ var new_version = super
+
+ # All versions of a variable have the same position in the environment
+ new_version.position = v.original_variable.position
+
+ return new_version
+ end
+end
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)
redef class Variable
# The position in the environment
- var position: Int
+ var position: Int is writable
end
# Implementation of a Frame with numbered variables
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
# 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
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
# 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
import virtual_machine
import vm_optimizations
import variables_numbering
+import compilation
--- /dev/null
+8/4
+8*2
+16+8
t2 = t2.next #alt2# t2 = null
end
#alt3#t2 = t2.next
+ #alt3#exit(0)
end
if i != null then
bar(i)
else
- break #alt4#
+ break #alt4# exit(0)
end
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
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)
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
abstract class A
var x: Int
- var y: Int is abstract
+ var y: Int is abstract, autoinit
end
class B
--- /dev/null
+# 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
--- /dev/null
+# 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
--- /dev/null
+# 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
--- /dev/null
+# 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
--- /dev/null
+# 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
--- /dev/null
+numbers: 8, 4, 8, 8
+numbers: 8, 8, 2
+numbers: 8, 16
+CONGRATULATIONS
-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`.
-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`.
-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'.
--- /dev/null
+i=10
+jj=20
+k=30
+ll=40
+
+i1
+j2
+k3
+l4
--- /dev/null
+i1
+j2
+k3
+l4
-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'.
-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'.
-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'.
-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'.
--- /dev/null
+alt/base_attr_abstract_alt5.nit:19,24--31: Error: `abstract` attributes cannot have an initial value.
--- /dev/null
+alt/base_attr_annot_1alt1.nit:33,9--11: Error: expected 0 argument(s) for `init`; got 1. See introduction at `standard::Object::init`.
--- /dev/null
+alt/base_attr_annot_1alt1_alt2.nit:19,3--12: Error: `noautoinit` attributes cannot have an initial value.
--- /dev/null
+alt/base_attr_annot_1alt1_alt3.nit:19,3--20,10: Error: `autoinit` attributes cannot have an initial value.
--- /dev/null
+alt/base_attr_annot_1alt1_alt6.nit:19,3--23,10: Error: `abstract` attributes cannot have an initial value.
--- /dev/null
+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`.
--- /dev/null
+Runtime error: Uninitialized attribute _a (alt/base_attr_annot_alt2.nit:18)
--- /dev/null
+alt/base_attr_annot_alt3.nit:19,3--20,10: Warning: superfluous `autoinit` on attribute.
+1
--- /dev/null
+alt/base_attr_annot_alt4.nit:19,3--21,6: Error: `lazy` attributes need a value.
--- /dev/null
+alt/base_attr_annot_alt5.nit:19,3--22,10: Error: `readonly` attributes need a value.
--- /dev/null
+Runtime error: Abstract method `a` called on `B` (alt/base_attr_annot_alt6.nit:18)
--- /dev/null
+alt/base_attr_annot_alt7.nit:19,3--24,10: Error: `lateinit` attributes need a value.
--- /dev/null
+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
-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.
+../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`?
-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.
--- /dev/null
+Runtime error: Uninitialized attribute _a (alt/base_attr_annot_alt2.nit:34)
k
2234
12345.0
+0x12
hello world
--- /dev/null
+test_keep_going.nit:15,11--14: Error: class `Fail` not found in module `test_keep_going`.
-../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.
# This file is part of NIT ( http://www.nitlanguage.org ).
#
-# Copyright 2011-2013 Alexis Laferrière <alexis.laf@xymus.net>
-#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# See the License for the specific language governing permissions and
# limitations under the License.
-fun opposite( v : Bool ) : Bool `{
+fun opposite(v: Bool): Bool `{
return v == 0;
`}
-fun plus_10( v : Char ) : Char `{
+
+fun plus_10(v: Char): Char `{
return v + 10;
`}
-fun plus_1000( v : Int ) : Int `{
+
+fun plus_1000(v: Int): Int `{
return v + 1000;
`}
-fun multiply_by_100( v : Float ) : Float `{
+
+fun multiply_by_100(v: Float): Float `{
return v * 100;
`}
-fun print_ns( s : NativeString ) `{
- printf( "%s\n", s );
+
+fun plus_0x10(v: Byte): Byte `{
+ return v + 0x10;
+`}
+
+fun print_ns(s: NativeString) `{
+ printf("%s\n", s);
`}
-print opposite( true )
-print opposite( false )
+print opposite(true)
+print opposite(false)
+
+print plus_10('a')
-print plus_10( 'a' )
+print plus_1000(1234)
-print plus_1000( 1234 )
+print multiply_by_100(123.45)
-print multiply_by_100( 123.45 )
+print plus_0x10(0x2u8)
-print_ns( "hello world".to_cstring )
+print_ns("hello world".to_cstring)
--- /dev/null
+# 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