+"""
+ end
+
+end
+
+# Footer for a Opportunity page
+class OpportunityFooter
+ super Template
+
+ redef fun rendering do
+ add """
+
+
+
+
+"""
+ end
+
+end
+
+# Any Opportunity page that contains the header, body and footer.
+class OpportunityPage
+ super Template
+
+ var header = new OpportunityHeader
+
+ var body: Streamable = "" is writable
+
+ var footer = new OpportunityFooter
+
+ redef fun rendering do
+ add header
+ add body
+ add footer
+ end
+
+end
diff --git a/contrib/opportunity/src/templates/meetup.nit b/contrib/opportunity/src/templates/meetup.nit
new file mode 100644
index 0000000..d9af51d
--- /dev/null
+++ b/contrib/opportunity/src/templates/meetup.nit
@@ -0,0 +1,193 @@
+# 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
+
+# Shows a meetup and allows to modify its participants
+module meetup
+
+import opportunity_model
+import boilerplate
+import welcome
+import template
+
+# Shows a meetup and allows to modify its participants
+class OpportunityMeetupPage
+ super OpportunityPage
+
+ # Meetup the page is supposed to show
+ var meetup: nullable Meetup = null
+
+ init from_id(id: String) do
+ var db = new OpportunityDB.open("opportunity")
+ meetup = db.find_meetup_by_id(id)
+ db.close
+ end
+
+ init do
+ header.page_js = """
+ function change_answer(ele){
+ var e = document.getElementById(ele.id);
+ var i = e.innerHTML;
+ var ans = true;
+ if(i === "
";
+ e.style.color = "green";
+ }
+ }
+ function add_part(ele){
+ var e = document.getElementById(ele.id);
+ var pname = document.getElementById("new_name").value;
+ var arr = e.id.split("_");
+ var mid = arr[1];
+ var ans = $('#' + ele.id).parent().parent().parent().children(".answer");
+ ansmap = {};
+ for(i=0;i
+
{{{name}}}
+
When : {{{date}}}
+
Where : {{{place}}}
+
+
+"""
+ t.add "
"
+ t.add "
Participating
"
+ for i in answers(db) do
+ t.add "
"
+ t.add i.to_s
+ t.add "
"
+ end
+ t.add ""
+ for i in participants(db) do
+ t.add "
"
+ t.add """
â
"""
+ i.load_answers(db, self)
+ t.add "
"
+ t.add i.to_s
+ t.add "
"
+ for j,k in i.answers do
+ t.add """
"
+ if k then
+ t.add "â"
+ else
+ t.add "â"
+ end
+ t.add "
"
+ end
+ t.add "
"
+ end
+ t.add """
+
+
+
+
+ """
+ for i in answers(db) do
+ t.add "
â
"
+ end
+ t.add "
"
+ t.add "
"
+ return t
+ end
+end
diff --git a/contrib/opportunity/src/templates/meetup_confirmation.nit b/contrib/opportunity/src/templates/meetup_confirmation.nit
new file mode 100644
index 0000000..0752a37
--- /dev/null
+++ b/contrib/opportunity/src/templates/meetup_confirmation.nit
@@ -0,0 +1,44 @@
+# 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
+
+# Page to show when the creation of a Meetup is successful
+module meetup_confirmation
+
+import boilerplate
+import opportunity_model
+
+# Show this page when a `Meetup` is sucessfully created.
+class MeetupConfirmation
+ super OpportunityPage
+
+ var meetup: Meetup
+
+ init do
+ body = """
+
+
Congratulations !
+
+
+
Your meetup was successfully created.
+
+ You can invite people to participate to your event by sharing them this link : {{{meetup.name}}}
+
+
+ See you soon for more Opportunities !
+
+
+ """
+ end
+
+end
diff --git a/contrib/opportunity/src/templates/meetup_creation.nit b/contrib/opportunity/src/templates/meetup_creation.nit
new file mode 100644
index 0000000..8cd364a
--- /dev/null
+++ b/contrib/opportunity/src/templates/meetup_creation.nit
@@ -0,0 +1,66 @@
+# 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
+
+module meetup_creation
+
+import boilerplate
+
+class MeetupCreationPage
+ super OpportunityPage
+
+ init do
+ header.page_js = """
+ function new_answer(sender){
+ var ansdiv = $('#answers');
+ var nb = ansdiv.children()
+ var s = nb.last();
+ var ss = s.attr("id").split('_');
+ var l = ss[ss.length - 1];
+ nb = parseInt(l) + 1;
+ var ch = ansdiv.children();
+ ch.last().after('')
+ ch.last().after('');
+ }
+ """
+ body = """
+
+
New meetup
+
+
+
+
+"""
+ end
+
+end
diff --git a/contrib/opportunity/src/templates/templates.nit b/contrib/opportunity/src/templates/templates.nit
new file mode 100644
index 0000000..d2dfd9c
--- /dev/null
+++ b/contrib/opportunity/src/templates/templates.nit
@@ -0,0 +1,22 @@
+# 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
+
+# All the templates used for the view are to be declared here
+module templates
+
+import boilerplate
+import welcome
+import meetup_creation
+import meetup
+import meetup_confirmation
diff --git a/contrib/opportunity/src/templates/welcome.nit b/contrib/opportunity/src/templates/welcome.nit
new file mode 100644
index 0000000..eaae527
--- /dev/null
+++ b/contrib/opportunity/src/templates/welcome.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
+
+# Welcome page for Opportunity
+module welcome
+
+import boilerplate
+
+# Welcome page for Opportunity
+class OpportunityHomePage
+ super OpportunityPage
+
+ init do
+ body = """
+
+
Welcome to opportunity !
+
+
+
Opportunity is a free (as in free software), easy-to-use, meetup planifier.
+
You can start using it right now by creating a new Meetup and sharing it with your friends!
+
+
+
+
+"""
+ end
+
+end
diff --git a/contrib/opportunity/tests/db_tests.nit b/contrib/opportunity/tests/db_tests.nit
new file mode 100644
index 0000000..cbec6f7
--- /dev/null
+++ b/contrib/opportunity/tests/db_tests.nit
@@ -0,0 +1,99 @@
+# 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
+
+# Tests for the model of Opportunity
+module db_tests
+
+import opportunity_model
+
+redef class OpportunityDB
+
+ fun wipe do
+ execute("DROP TABLE people;")
+ execute("DROP TABLE meetups;")
+ execute("DROP TABLE answers;")
+ execute("DROP TABLE part_answers;")
+ execute("DROP INDEX answers_clean;")
+ execute("DROP INDEX ans_clean;")
+ execute("DROP INDEX ppl_clean;")
+ end
+
+end
+
+print "Opening DB"
+
+var db = new OpportunityDB.open("opportunity")
+
+print "DB opened"
+
+db.wipe
+
+print "Wiped"
+
+db.close
+
+db = new OpportunityDB.open("opportunity")
+
+var hj = new People("Jack", "Handsome")
+
+var m = new Meetup("Awaken the warrior", "2024/05/28", "Vault of the Warrior")
+assert m.commit(db)
+
+var vh = new People("Hunter", "Vault")
+
+var ll = new People("", "Lilith")
+
+var y = new Answer("Yes")
+y.meetup = m
+y.commit(db)
+
+var n = new Answer("No")
+n.meetup = m
+n.commit(db)
+
+var h = new Answer("I have no choice, I'm a hostage")
+h.meetup = m
+h.commit(db)
+
+hj.answer(y) = true
+hj.answer(n) = false
+hj.answer(h) = false
+
+vh.answer(y) = true
+vh.answer(n) = false
+vh.answer(h) = false
+
+ll.answer(y) = true
+ll.answer(n) = false
+ll.answer(h) = true
+
+hj.commit db
+vh.commit db
+ll.commit db
+
+assert hj.commit(db)
+assert vh.commit(db)
+assert ll.commit(db)
+
+print db.find_meetup_by_id(m.id) or else "null"
+
+for i in m.participants(db) do
+ print "Answers for {i.to_s.trim}"
+ i.load_answers(db, m)
+ for k,v in i.answers do
+ print "{k.to_s.trim} => {v.to_s.trim}"
+ end
+end
+
+db.close
diff --git a/contrib/opportunity/tests/sav/db_tests.res b/contrib/opportunity/tests/sav/db_tests.res
new file mode 100644
index 0000000..1667896
--- /dev/null
+++ b/contrib/opportunity/tests/sav/db_tests.res
@@ -0,0 +1,18 @@
+Opening DB
+DB opened
+Wiped
+Event : Awaken the warrior
+When : 2024/05/28
+Where : Vault of the Warrior
+Answers for Handsome Jack
+Yes => true
+No => false
+I have no choice, I'm a hostage => false
+Answers for Vault Hunter
+Yes => true
+No => false
+I have no choice, I'm a hostage => false
+Answers for Lilith
+Yes => true
+No => false
+I have no choice, I'm a hostage => true
diff --git a/contrib/pep8analysis/src/pep8analysis_web.nit b/contrib/pep8analysis/src/pep8analysis_web.nit
index 259fd09..18ee374 100644
--- a/contrib/pep8analysis/src/pep8analysis_web.nit
+++ b/contrib/pep8analysis/src/pep8analysis_web.nit
@@ -108,15 +108,6 @@ redef class AnalysisManager
fun show_graph(content: String) do "show_graph('{content.escape_to_c}');".run_js
end
-class StringIStream
- super BufferedIStream
-
- init(str: String) do _buffer = new FlatBuffer.from(str)
-
- redef fun fill_buffer do end_reached = true
- redef var end_reached: Bool = false
-end
-
redef class NativeString
fun run_analysis do manager.run to_s
end
diff --git a/examples/mnit_dino/src/game_logic.nit b/examples/mnit_dino/src/game_logic.nit
index 1df0119..8d1a849 100644
--- a/examples/mnit_dino/src/game_logic.nit
+++ b/examples/mnit_dino/src/game_logic.nit
@@ -386,7 +386,8 @@ class Bush super Entity end
# Sort entities on screen in order of Y, entities in the back are drawn first
class EntitiesSorter
- super AbstractSorter[Entity]
+ super Comparator
+ redef type COMPARED: Entity
redef fun compare(a, b) do return b.pos.y <=> a.pos.y
end
diff --git a/lib/ai/search.nit b/lib/ai/search.nit
index f279d4f..21a349d 100644
--- a/lib/ai/search.nit
+++ b/lib/ai/search.nit
@@ -608,7 +608,8 @@ end
# Used to compare nodes with their score.
# Smaller is score, smaller is the node.
private class NodeComparator[S: Object, A]
- super Comparator[SearchNode[S, A]]
+ super Comparator
+ redef type COMPARED: SearchNode[S, A]
redef fun compare(a,b) do return a.score <=> b.score
end
diff --git a/lib/console.nit b/lib/console.nit
index e6a129f..04dcb6e 100644
--- a/lib/console.nit
+++ b/lib/console.nit
@@ -12,25 +12,185 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-# Simple numerical statistical analysis and presentation
+# Defines some ANSI Terminal Control Escape Sequences.
module console
-# Redef String class to add a function to color the string
-redef class String
- private fun add_escape_char(escapechar: String): String do
- return "{escapechar}{self}{esc}[0m"
+# A ANSI/VT100 escape sequence.
+abstract class TermEscape
+ # The US-ASCII ESC character.
+ protected fun esc: Char do return 27.ascii
+end
+
+# ANSI/VT100 code to switch character attributes (SGR).
+#
+# By default, resets everything to the terminalâs defaults.
+#
+# Note:
+#
+# The escape sequence inserted at the end of the string by terminal-related
+# methods of `String` resets all character attributes to the terminalâs
+# defaults. So, when combining format `a` and `b`, something like
+# `("foo".a + " bar").b` will not work as expected, but `"foo".a.b + " bar".b`
+# will. You may also use `TermCharFormat` (this class).
+#
+# Usage example:
+#
+# print "{(new TermCharFormat).yellow_fg.bold}a{(new TermCharFormat).yellow_fg}b{new TermCharFormat}"
+class TermCharFormat
+ super TermEscape
+
+ private var attributes: Array[String] = new Array[String]
+
+ # Copies the attributes from the specified format.
+ init from(format: TermCharFormat) do
+ attributes.add_all(format.attributes)
end
- private fun esc: Char do return 27.ascii
- fun gray: String do return add_escape_char("{esc}[30m")
- fun red: String do return add_escape_char("{esc}[31m")
- fun green: String do return add_escape_char("{esc}[32m")
- fun yellow: String do return add_escape_char("{esc}[33m")
- fun blue: String do return add_escape_char("{esc}[34m")
- fun purple: String do return add_escape_char("{esc}[35m")
- fun cyan: String do return add_escape_char("{esc}[36m")
- fun light_gray: String do return add_escape_char("{esc}[37m")
- fun bold: String do return add_escape_char("{esc}[1m")
- fun underline: String do return add_escape_char("{esc}[4m")
+ redef fun to_s: String do return "{esc}[{attributes.join(";")}m"
+
+ # Apply the specified SGR and return `self`.
+ private fun apply(sgr: String): TermCharFormat do
+ attributes.add(sgr)
+ return self
+ end
+
+ # Apply normal (default) format and return `self`.
+ fun default: TermCharFormat do return apply("0")
+
+ # Apply bold weight and return `self`.
+ fun bold: TermCharFormat do return apply("1")
+
+ # Apply underlining and return `self`.
+ fun underline: TermCharFormat do return apply("4")
+
+ # Apply blinking or bold weight and return `self`.
+ fun blink: TermCharFormat do return apply("5")
+
+ # Apply reverse video and return `self`.
+ fun inverse: TermCharFormat do return apply("7")
+
+ # Apply normal weight and return `self`.
+ fun normal_weight: TermCharFormat do return apply("22")
+
+ # Add the attribute that disable inderlining and return `self`.
+ fun not_underlined: TermCharFormat do return apply("24")
+
+ # Add the attribute that disable blinking and return `self`.
+ fun steady: TermCharFormat do return apply("25")
+
+ # Add the attribute that disable reverse video and return `self`.
+ fun positive: TermCharFormat do return apply("27")
+
+ # Apply a black foreground and return `self`.
+ fun black_fg: TermCharFormat do return apply("30")
+
+ # Apply a red foreground and return `self`.
+ fun red_fg: TermCharFormat do return apply("31")
+
+ # Apply a green foreground and return `self`.
+ fun green_fg: TermCharFormat do return apply("32")
+
+ # Apply a yellow foreground and return `self`.
+ fun yellow_fg: TermCharFormat do return apply("33")
+
+ # Apply a blue foreground and return `self`.
+ fun blue_fg: TermCharFormat do return apply("34")
+
+ # Apply a mangenta foreground and return `self`.
+ fun magenta_fg: TermCharFormat do return apply("35")
+
+ # Apply a cyan foreground and return `self`.
+ fun cyan_fg: TermCharFormat do return apply("36")
+
+ # Apply a white foreground and return `self`.
+ fun white_fg: TermCharFormat do return apply("37")
+
+ # Apply the default foreground and return `self`.
+ fun default_fg: TermCharFormat do return apply("39")
+
+ # Apply a black backgroud and return `self`.
+ fun black_bg: TermCharFormat do return apply("40")
+
+ # Apply a red backgroud and return `self`.
+ fun red_bg: TermCharFormat do return apply("41")
+
+ # Apply a green backgroud and return `self`.
+ fun green_bg: TermCharFormat do return apply("42")
+
+ # Apply a yellow backgroud and return `self`.
+ fun yellow_bg: TermCharFormat do return apply("43")
+
+ # Apply a blue backgroud and return `self`.
+ fun blue_bg: TermCharFormat do return apply("44")
+
+ # Apply a mangenta backgroud and return `self`.
+ fun magenta_bg: TermCharFormat do return apply("45")
+
+ # Apply a cyan backgroud and return `self`.
+ fun cyan_bg: TermCharFormat do return apply("46")
+
+ # Apply a white backgroud and return `self`.
+ fun white_bg: TermCharFormat do return apply("47")
+
+ # Apply the default backgroud and return `self`.
+ fun default_bg: TermCharFormat do return apply("49")
end
+# Redefine the `String` class to add functions to color the string.
+redef class String
+ private fun apply_format(f: TermCharFormat): String do
+ return "{f}{self}{normal}"
+ end
+
+ private fun normal: TermCharFormat do return new TermCharFormat
+
+ # Make the text appear in dark gray (or black) in a ANSI/VT100 terminal.
+ #
+ # WARNING: SEE: `TermCharFormat`
+ fun gray: String do return apply_format(normal.black_fg)
+
+ # Make the text appear in red in a ANSI/VT100 terminal.
+ #
+ # WARNING: SEE: `TermCharFormat`
+ fun red: String do return apply_format(normal.red_fg)
+
+ # Make the text appear in green in a ANSI/VT100 terminal.
+ #
+ # WARNING: SEE: `TermCharFormat`
+ fun green: String do return apply_format(normal.green_fg)
+
+ # Make the text appear in yellow in a ANSI/VT100 terminal.
+ #
+ # WARNING: SEE: `TermCharFormat`
+ fun yellow: String do return apply_format(normal.yellow_fg)
+
+ # Make the text appear in blue in a ANSI/VT100 terminal.
+ #
+ # WARNING: SEE: `TermCharFormat`
+ fun blue: String do return apply_format(normal.blue_fg)
+
+ # Make the text appear in mangenta in a ANSI/VT100 terminal.
+ #
+ # WARNING: SEE: `TermCharFormat`
+ fun purple: String do return apply_format(normal.magenta_fg)
+
+ # Make the text appear in cyan in a ANSI/VT100 terminal.
+ #
+ # WARNING: SEE: `TermCharFormat`
+ fun cyan: String do return apply_format(normal.cyan_fg)
+
+ # Make the text appear in light gray (or white) in a ANSI/VT100 terminal.
+ #
+ # WARNING: SEE: `TermCharFormat`
+ fun light_gray: String do return apply_format(normal.white_fg)
+
+ # Make the text appear in bold in a ANSI/VT100 terminal.
+ #
+ # WARNING: SEE: `TermCharFormat`
+ fun bold: String do return apply_format(normal.bold)
+
+ # Make the text underlined in a ANSI/VT100 terminal.
+ #
+ # WARNING: SEE: `TermCharFormat`
+ fun underline: String do return apply_format(normal.underline)
+end
diff --git a/lib/counter.nit b/lib/counter.nit
index 75278d2..670fc59 100644
--- a/lib/counter.nit
+++ b/lib/counter.nit
@@ -174,7 +174,8 @@ class Counter[E: Object]
end
private class CounterComparator[E: Object]
- super Comparator[E]
+ super Comparator
+ redef type COMPARED: E
var counter: Counter[E]
redef fun compare(a,b) do return self.counter.map[a] <=> self.counter.map[b]
end
diff --git a/lib/io/io.nit b/lib/io/io.nit
new file mode 100644
index 0000000..c48b171
--- /dev/null
+++ b/lib/io/io.nit
@@ -0,0 +1,14 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# This file is free software, which comes along with NIT. This software is
+# distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE. You can modify it is you want, provided this header
+# is kept unaltered, and a notification of the changes is added.
+# You are allowed to redistribute it and sell it, alone or is a part of
+# another product.
+
+# Additional services for streams.
+module io
+
+import push_back_reader
diff --git a/lib/io/push_back_reader.nit b/lib/io/push_back_reader.nit
new file mode 100644
index 0000000..257c662
--- /dev/null
+++ b/lib/io/push_back_reader.nit
@@ -0,0 +1,110 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# This file is free software, which comes along with NIT. This software is
+# distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE. You can modify it is you want, provided this header
+# is kept unaltered, and a notification of the changes is added.
+# You are allowed to redistribute it and sell it, alone or is a part of
+# another product.
+
+# Input stream that permits to push bytes back to the stream.
+module io::push_back_reader
+
+# Input stream that permits to push bytes back to the stream.
+interface PushBackReader
+ super IStream
+
+ # Push the specified byte back to the stream.
+ #
+ # The specified byte is usually the last read byte that is not
+ # âunreadâ already.
+ fun unread_char(c: Char) is abstract
+
+ # Push the specified string back to the stream.
+ #
+ # The specified string is usually the last read string that is not
+ # âunreadâ already.
+ fun unread(s: String) do
+ for c in s.chars.reverse_iterator do unread_char(c)
+ end
+end
+
+# Decorates an input stream to permit to push bytes back to the input stream.
+class PushBackDecorator
+ super PushBackReader
+
+ # The parent stream.
+ var parent: IStream
+
+ # The stack of the pushed-back bytes.
+ #
+ # Bytes are in the reverse order they will reappear in the stream.
+ # `unread` pushes bytes after already pushed-back bytes.
+ #
+ # TODO: With optimized bulk array copy operations, a reversed stack (like in
+ # OpenJDK) would be more efficient.
+ private var buf: Sequence[Char] = new Array[Char]
+
+ redef fun read_char: Int do
+ if buf.length <= 0 then return parent.read_char
+ return buf.pop.ascii
+ end
+
+ redef fun read(i: Int): String do
+ if i <= 0 then return ""
+ if buf.length <= 0 then return parent.read(i)
+ var s = new FlatBuffer.with_capacity(i)
+
+ loop
+ s.chars.push(buf.pop)
+ i -= 1
+ if i <= 0 then
+ return s.to_s
+ else if buf.length <= 0 then
+ s.append(parent.read(i))
+ return s.to_s
+ end
+ end
+ end
+
+ redef fun read_all: String do
+ if buf.length <= 0 then return parent.read_all
+ var s = new FlatBuffer
+
+ loop
+ s.chars.push(buf.pop)
+ if buf.length <= 0 then
+ s.append(parent.read_all)
+ return s.to_s
+ end
+ end
+ end
+
+ redef fun append_line_to(s: Buffer) do
+ if buf.length > 0 then
+ var c: Char
+
+ loop
+ c = buf.pop
+ s.chars.push(c)
+ if c == '\n' then return
+ if buf.length <= 0 then break
+ end
+ end
+ parent.append_line_to(s)
+ end
+
+ redef fun eof: Bool do return buf.length <= 0 and parent.eof
+
+ redef fun close do
+ buf.clear
+ parent.close
+ end
+
+ redef fun unread_char(c: Char) do buf.push(c)
+
+ redef fun unread(s: String) do
+ for c in s.chars.reverse_iterator do buf.push(c)
+ end
+end
diff --git a/lib/io/test_push_back_reader.nit b/lib/io/test_push_back_reader.nit
new file mode 100644
index 0000000..5bace8f
--- /dev/null
+++ b/lib/io/test_push_back_reader.nit
@@ -0,0 +1,158 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# This file is free software, which comes along with NIT. This software is
+# distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE. You can modify it is you want, provided this header
+# is kept unaltered, and a notification of the changes is added.
+# You are allowed to redistribute it and sell it, alone or is a part of
+# another product.
+
+# Test suites for module `push_back_reader`
+module test_push_back_reader is test_suite
+
+import test_suite
+import io::push_back_reader
+
+class TestPushBackDecorator
+ super TestSuite
+
+ private fun sample: PushBackDecorator do
+ return new PushBackDecorator(new StringIStream("""
+abcd
+
+efg
+"""))
+ end
+
+ fun test_read_char do
+ var subject = sample
+
+ assert 'a' == subject.read_char.ascii
+ end
+
+ fun test_read_char_eof do
+ var subject = new PushBackDecorator(new StringIStream(""))
+
+ assert -1 == subject.read_char
+ end
+
+ fun test_unread_read_char do
+ var subject = sample
+
+ subject.unread_char('z')
+ assert 'z' == subject.read_char.ascii
+ assert 'a' == subject.read_char.ascii
+ end
+
+ fun test_read_partial do
+ var subject = sample
+
+ assert "abcd" == subject.read(4)
+ end
+
+ fun test_read_too_much do
+ var subject = sample
+ var exp = """
+abcd
+
+efg
+"""
+ assert exp == subject.read(100)
+ end
+
+ fun test_unread_read do
+ var subject = sample
+
+ subject.unread("a")
+ assert "aab" == subject.read(3)
+ end
+
+ fun test_unread_read_mixed do
+ var subject = sample
+
+ subject.unread("a")
+ assert "aab" == subject.read(3)
+ end
+
+ fun test_read_all do
+ var subject = sample
+ var exp = """
+abcd
+
+efg
+"""
+ assert exp == subject.read_all
+ end
+
+ fun test_unread_read_all do
+ var subject = sample
+ var exp = """
+fooabcd
+
+efg
+"""
+ subject.unread("foo")
+ assert exp == subject.read_all
+ end
+
+ fun test_read_line do
+ var subject = sample
+
+ assert "abcd\n" == subject.read_line
+ assert "\n" == subject.read_line
+ end
+
+ fun test_unread_read_line do
+ var subject = sample
+
+ subject.unread("a\nb")
+ assert "a\n" == subject.read_line
+ assert "babcd\n" == subject.read_line
+ end
+
+ fun test_eof do
+ var subject = sample
+
+ assert not subject.eof
+ subject.read_all
+ assert subject.eof
+ end
+
+ fun test_eof_empty do
+ var subject = new PushBackDecorator(new StringIStream(""))
+
+ assert subject.eof
+ end
+
+ fun test_close do
+ var subject = sample
+
+ subject.close
+ assert subject.eof
+ end
+
+ fun test_unread_close do
+ var subject = sample
+
+ subject.unread("foo")
+ subject.close
+ assert subject.eof
+ end
+
+ fun test_unread_char_order do
+ var subject = sample
+
+ subject.unread_char('z')
+ subject.unread_char('y')
+ assert "yzab" == subject.read(4)
+ end
+
+ fun test_unread_order do
+ var subject = sample
+
+ subject.unread("bar")
+ subject.unread("foo")
+ assert "foobarab" == subject.read(8)
+ end
+end
diff --git a/lib/mnit/mnit_injected_input.nit b/lib/mnit/mnit_injected_input.nit
index c590a85..4ed9664 100644
--- a/lib/mnit/mnit_injected_input.nit
+++ b/lib/mnit/mnit_injected_input.nit
@@ -76,12 +76,12 @@ redef class App
redef fun setup
do
var env = "MNIT_SRAND".environ
- if env != null and env != "" then
+ if env != "" then
srand_from(env.to_i)
end
var input = "MNIT_READ_INPUT".environ
- if input != null and input != "" then
+ if input != "" then
injected_input_stream = new IFStream.open(input)
print "GET injected_input_stream {input}"
end
diff --git a/lib/nitcorn/http_request.nit b/lib/nitcorn/http_request.nit
index 07b91ad..47e6823 100644
--- a/lib/nitcorn/http_request.nit
+++ b/lib/nitcorn/http_request.nit
@@ -57,6 +57,41 @@ class HttpRequest
# The arguments passed with the POST or GET method (with a priority on POST)
var all_args = new HashMap[String, String]
+
+ # Returns argument `arg_name` in the request as a String
+ # or null if it was not found.
+ # Also cleans the String by trimming it.
+ # If the Strings happens to be empty after trimming,
+ # the method will return `null`
+ #
+ # NOTE: Prioritizes POST before GET
+ fun string_arg(arg_name: String): nullable String do
+ if not all_args.has_key(arg_name) then return null
+ var s = all_args[arg_name].trim
+ if s.is_empty then return null
+ return s
+ end
+
+ # Returns argument `arg_name` as an Int or `null` if not found or not a number.
+ #
+ # NOTE: Prioritizes POST before GET
+ fun int_arg(arg_name: String): nullable Int do
+ if not all_args.has_key(arg_name) then return null
+ var i = all_args[arg_name]
+ if not i.is_numeric then return null
+ return i.to_i
+ end
+
+ # Returns argument `arg_name` as a Bool or `null` if not found or not a boolean.
+ #
+ # NOTE: Prioritizes POST before GET
+ fun bool_arg(arg_name: String): nullable Bool do
+ if not all_args.has_key(arg_name) then return null
+ var i = all_args[arg_name]
+ if i == "true" then return true
+ if i == "false" then return false
+ return null
+ end
end
# Utility class to parse a request string and build a `HttpRequest`
@@ -114,10 +149,6 @@ class HttpRequestParser
var parts = line.split_once_on('=')
if parts.length > 1 then
var decoded = parts[1].replace('+', " ").from_percent_encoding
- if decoded == null then
- print "decode error"
- continue
- end
http_request.post_args[parts[0]] = decoded
http_request.all_args[parts[0]] = decoded
else
diff --git a/lib/opts.nit b/lib/opts.nit
index a1bffc1..c088325 100644
--- a/lib/opts.nit
+++ b/lib/opts.nit
@@ -194,11 +194,7 @@ class OptionEnum
redef fun pretty_default
do
- if default_value != null then
- return " ({values[default_value]})"
- else
- return ""
- end
+ return " ({values[default_value]})"
end
end
diff --git a/lib/ordered_tree.nit b/lib/ordered_tree.nit
index f6cd69a..91f8e63 100644
--- a/lib/ordered_tree.nit
+++ b/lib/ordered_tree.nit
@@ -80,7 +80,7 @@ class OrderedTree[E: Object]
# Sort roots and other elements using a comparator method
# This method basically sorts roots then each group of children
- fun sort_with(comparator: Comparator[E])
+ fun sort_with(comparator: Comparator)
do
comparator.sort(roots)
for a in sub.values do
diff --git a/lib/pipeline.nit b/lib/pipeline.nit
index da1b4c4..31d007b 100644
--- a/lib/pipeline.nit
+++ b/lib/pipeline.nit
@@ -35,7 +35,7 @@ redef interface Iterator[E]
# Filter: sort with a given `comparator`.
# Important: require O(n) memory.
- fun sort_with(comparator: Comparator[E]): Iterator[E]
+ fun sort_with(comparator: Comparator): Iterator[E]
do
var a = self.to_a
comparator.sort(a)
diff --git a/lib/poset.nit b/lib/poset.nit
index 3149b21..7a26f90 100644
--- a/lib/poset.nit
+++ b/lib/poset.nit
@@ -24,7 +24,9 @@ module poset
# * transitivity: `(self.has_edge(e,f) and self.has_edge(f,g)) implies self.has_edge(e,g)`
class POSet[E: Object]
super Collection[E]
- super Comparator[E]
+ super Comparator
+
+ redef type COMPARED: E is fixed
redef fun iterator do return elements.keys.iterator
diff --git a/lib/signals.nit b/lib/signals.nit
index 89f4a1b..f1044e8 100644
--- a/lib/signals.nit
+++ b/lib/signals.nit
@@ -15,6 +15,48 @@
# limitations under the License.
# Module to manage standard C signals
+#
+# Common usage imply 5 steps:
+#
+# 1. Implement the `SignalHandler` interface
+# 2. `redef receive_signal_unsafe` to handle `sigsegv`
+# 3. `redef receive_signal` to handle other signals safely
+# 4, Notify what signals to handle with `handle_signal`
+# 5. If using the safe handler method, routinely call `check_signals`
+#
+# Usage example:
+#
+# ~~~~
+# class MyReceiver
+# super SignalHandler
+#
+# redef fun receive_signal(signal)
+# do
+# print "received safely {signal}"
+# if signal == sigalarm then print "Alarm!"
+# end
+# redef fun receive_signal_unsafe( signal ) do print "received unsafely {signal}"
+# end
+#
+# var r = new MyReceiver
+#
+# # Handle `sigsegv` signal unsafely (the only way for this one)
+# r.handle_signal(sigsegv, false)
+#
+# # Handle `sigint` and `sigalarm` safely
+# r.handle_signal(sigint, true)
+# r.handle_signal(sigalarm, true)
+#
+# Ask system to receive a `sigalarm` signal in 1 second
+# set_alarm(1)
+#
+# loop
+# # Check signals and callback `receive_signal`
+# var hit = check_signals
+#
+# if hit then break
+# end
+# ~~~~
module signals
`{
diff --git a/lib/sqlite3/sqlite3.nit b/lib/sqlite3/sqlite3.nit
index d016a4c..05cbed0 100644
--- a/lib/sqlite3/sqlite3.nit
+++ b/lib/sqlite3/sqlite3.nit
@@ -105,6 +105,9 @@ class Sqlite3DB
if err.is_ok then return null
return err.to_s
end
+
+ # Returns the id for the last successful insert on the current connection.
+ fun last_insert_rowid: Int do return native_connection.last_insert_rowid
end
# A prepared Sqlite3 statement, created from `Sqlite3DB::prepare` or `Sqlite3DB::select`
diff --git a/lib/standard/collection/abstract_collection.nit b/lib/standard/collection/abstract_collection.nit
index d2cdb2c..843f8eb 100644
--- a/lib/standard/collection/abstract_collection.nit
+++ b/lib/standard/collection/abstract_collection.nit
@@ -152,6 +152,16 @@ interface Iterator[E]
# Iterate over `self`
fun iterator: Iterator[E] do return self
+
+ # Post-iteration hook.
+ #
+ # Used to inform `self` that the iteration is over.
+ # Specific iterators can use this to free some resources.
+ #
+ # Is automatically invoked at the end of `for` structures.
+ #
+ # Do nothing by default.
+ fun finish do end
end
# A collection that contains only one item.
@@ -526,6 +536,16 @@ interface MapIterator[K: Object, V]
# Set a new `item` at `key`.
#fun item=(item: E) is abstract
+
+ # Post-iteration hook.
+ #
+ # Used to inform `self` that the iteration is over.
+ # Specific iterators can use this to free some resources.
+ #
+ # Is automatically invoked at the end of `for` structures.
+ #
+ # Do nothing by default.
+ fun finish do end
end
# Iterator on a 'keys' point of view of a map
diff --git a/lib/standard/collection/sorter.nit b/lib/standard/collection/sorter.nit
index b6319e1..cfcc376 100644
--- a/lib/standard/collection/sorter.nit
+++ b/lib/standard/collection/sorter.nit
@@ -10,33 +10,84 @@
# You are allowed to redistribute it and sell it, alone or is a part of
# another product.
-# This module contains classes used to sorts arrays.
+# This module contains classes used to compare things and sorts arrays.
+#
# In order to provide your own sort class you should define a subclass of `Comparator` with
-# a custom `Comparator::compare` function.
+# a custom `Comparator::compare` function and a specific `COMPARED` virtual type.
module sorter
import range
import array
# This abstract class generalizes ways to sort an array
-interface Comparator[E]
+interface Comparator
+ # What to compare to
+ type COMPARED: nullable Object
+
# Compare `a` and `b`.
# Returns:
# -1 if a < b
# 0 if a = b
# 1 if a > b
- fun compare(a: E, b: E): Int is abstract
+ fun compare(a: COMPARED, b: COMPARED): Int is abstract
+
+ # Is `seq` sorted?
+ #
+ # assert default_comparator.is_sorted([1,2,2,3]) == true
+ # assert default_comparator.is_sorted([1,10,2,3]) == false
+ # assert alpha_comparator.is_sorted([1,10,2,3]) == true
+ fun is_sorted(seq: SequenceRead[COMPARED]): Bool
+ do
+ if seq.length <= 1 then return true
+ var prev = seq.first
+ for e in seq do
+ if compare(prev, e) > 0 then return false
+ prev = e
+ end
+ return true
+ end
+
+ # Returns the minimum between `a` and `b`.
+ #
+ # assert default_comparator.min(2,10) == 2
+ # assert alpha_comparator.min(2,10) == 10
+ #
+ # If both are equivalent, then returns `a`.
+ #
+ # var m = alpha_comparator.min(1, "1")
+ # assert m == 1
+ # assert m != "1"
+ fun min(a,b: COMPARED): COMPARED
+ do
+ if compare(a,b) > 0 then return b else return a
+ end
+
+ # Returns the maximum between `a` and `b`.
+ #
+ # assert default_comparator.max(2,10) == 10
+ # assert alpha_comparator.max(2,10) == 2
+ #
+ # If both are equivalent, then returns `a`.
+ #
+ # var m = alpha_comparator.max(1, "1")
+ # assert m == 1
+ # assert m != "1"
+ fun max(a,b: COMPARED): COMPARED
+ do
+ if compare(a,b) < 0 then return b else return a
+ end
# Sort `array` using the `compare` function.
#
- # var s = new DefaultComparator[Int]
- # var a = [5, 2, 3, 1, 4]
- # s.sort(a)
- # assert a == [1, 2, 3, 4, 5]
- fun sort(array: Array[E]) do sub_sort(array, 0, array.length-1)
+ # var a = [10, 2, 3, 1, 4]
+ # default_comparator.sort(a)
+ # assert a == [1, 2, 3, 4, 10]
+ # alpha_comparator.sort(a)
+ # assert a == [1, 10, 2, 3, 4]
+ fun sort(array: Array[COMPARED]) do sub_sort(array, 0, array.length-1)
# Sort `array` between `from` and `to` indices
- private fun sub_sort(array: Array[E], from: Int, to: Int)
+ private fun sub_sort(array: Array[COMPARED], from: Int, to: Int)
do
if from >= to then
return
@@ -50,11 +101,10 @@ interface Comparator[E]
# Quick-sort `array` between `from` and `to` indices
# Worst case: O(n^2), Average case: O(n lg n)
#
- # var s = new DefaultComparator[Int]
# var a = [5, 2, 3, 1, 4]
- # s.quick_sort(a, 0, a.length - 1)
+ # default_comparator.quick_sort(a, 0, a.length - 1)
# assert a == [1, 2, 3, 4, 5]
- fun quick_sort(array: Array[E], from: Int, to: Int) do
+ fun quick_sort(array: Array[COMPARED], from: Int, to: Int) do
var pivot = array[from]
var i = from
var j = to
@@ -76,11 +126,10 @@ interface Comparator[E]
# Bubble-sort `array` between `from` and `to` indices
# Worst case: O(n^2), average case: O(n^2)
#
- # var s = new DefaultComparator[Int]
# var a = [5, 2, 3, 1, 4]
- # s.bubble_sort(a, 0, a.length - 1)
+ # default_comparator.bubble_sort(a, 0, a.length - 1)
# assert a == [1, 2, 3, 4, 5]
- fun bubble_sort(array: Array[E], from: Int, to: Int)
+ fun bubble_sort(array: Array[COMPARED], from: Int, to: Int)
do
var i = from
while i < to do
@@ -105,12 +154,10 @@ interface Comparator[E]
# Insertion-sort `array` between `from` and `to` indices
# Worst case: O(n^2), average case: O(n^2)
#
- # var s = new DefaultComparator[Int]
# var a = [5, 2, 3, 1, 4]
- # s.insertion_sort(a, 0, a.length - 1)
+ # default_comparator.insertion_sort(a, 0, a.length - 1)
# assert a == [1, 2, 3, 4, 5]
- fun insertion_sort(array: Array[E], from: Int, to: Int) do
- var last = array.length
+ fun insertion_sort(array: Array[COMPARED], from: Int, to: Int) do
for i in [from..to] do
var j = i
while j > 0 and compare(array[j], array[j - 1]) < 0 do
@@ -123,11 +170,10 @@ interface Comparator[E]
# Merge-sort `array` between `from` and `to` indices
# Worst case: O(n lg n), average: O(n lg n)
#
- # var s = new DefaultComparator[Int]
# var a = [5, 2, 3, 1, 4]
- # s.merge_sort(a, 0, a.length - 1)
+ # default_comparator.merge_sort(a, 0, a.length - 1)
# assert a == [1, 2, 3, 4, 5]
- fun merge_sort(array: Array[E], from, to: Int) do
+ fun merge_sort(array: Array[COMPARED], from, to: Int) do
if from >= to then return
var mid = (to + from) / 2
merge_sort(array, from, mid)
@@ -135,10 +181,10 @@ interface Comparator[E]
merge(array, from, mid, to)
end
- private fun merge(array: Array[E], from, mid, to: Int) do
- var l = new Array[E]
+ private fun merge(array: Array[COMPARED], from, mid, to: Int) do
+ var l = new Array[COMPARED]
for i in [from..mid] do l.add array[i]
- var r = new Array[E]
+ var r = new Array[COMPARED]
for i in [mid + 1..to] do r.add array[i]
var i = 0
var j = 0
@@ -162,11 +208,10 @@ interface Comparator[E]
# Heap-sort `array` between `from` and `to` indices
# Worst case: O(n lg n), average: O(n lg n)
#
- # var s = new DefaultComparator[Int]
# var a = [5, 2, 3, 1, 4]
- # s.heap_sort(a, 0, a.length - 1)
+ # default_comparator.heap_sort(a, 0, a.length - 1)
# assert a == [1, 2, 3, 4, 5]
- fun heap_sort(array: Array[E], from, to: Int) do
+ fun heap_sort(array: Array[COMPARED], from, to: Int) do
var size = build_heap(array)
for j in [from..to[ do
array.swap_at(0, size)
@@ -175,7 +220,7 @@ interface Comparator[E]
end
end
- private fun build_heap(array: Array[E]): Int do
+ private fun build_heap(array: Array[COMPARED]): Int do
var size = array.length - 1
var i = size / 2
while i >= 0 do
@@ -185,7 +230,7 @@ interface Comparator[E]
return size
end
- private fun heapify(array: Array[E], from, to: Int) do
+ private fun heapify(array: Array[COMPARED], from, to: Int) do
var l = from * 2
var r = l + 1
var largest: Int
@@ -205,25 +250,14 @@ interface Comparator[E]
end
-# Deprecated class, use `Comparator` instead
-interface AbstractSorter[E]
- super Comparator[E]
-end
-
# This comparator uses the operator `<=>` to compare objects.
# see `default_comparator` for an easy-to-use general stateless default comparator.
-class DefaultComparator[E: Comparable]
- super Comparator[E]
+class DefaultComparator
+ super Comparator
+ redef type COMPARED: Comparable
# Return a <=> b
redef fun compare(a, b) do return a <=> b
-
- init do end
-end
-
-# Deprecated class, use `DefaultComparator` instead
-class ComparableSorter[E: Comparable]
- super DefaultComparator[E]
end
# Easy-to-use general stateless default comparator that uses `<=>` to compare things.
-fun default_comparator: Comparator[Comparable] do return once new DefaultComparator[Comparable]
+fun default_comparator: DefaultComparator do return once new DefaultComparator
diff --git a/lib/standard/file.nit b/lib/standard/file.nit
index 36878e5..30e48e3 100644
--- a/lib/standard/file.nit
+++ b/lib/standard/file.nit
@@ -65,6 +65,7 @@ class IFStream
redef fun close
do
var i = _file.io_close
+ _buffer.clear
end_reached = true
end
@@ -327,27 +328,49 @@ redef class String
# Correctly join two path using the directory separator.
#
- # Using a standard "{self}/{path}" does not work when `self` is the empty string.
- # This method ensure that the join is valid.
+ # Using a standard "{self}/{path}" does not work in the following cases:
+ #
+ # * `self` is empty.
+ # * `path` ends with `'/'`.
+ # * `path` starts with `'/'`.
#
- # assert "hello".join_path("world") == "hello/world"
- # assert "hel/lo".join_path("wor/ld") == "hel/lo/wor/ld"
- # assert "".join_path("world") == "world"
- # assert "/hello".join_path("/world") == "/world"
+ # This method ensures that the join is valid.
#
- # Note: you may want to use `simplify_path` on the result
+ # assert "hello".join_path("world") == "hello/world"
+ # assert "hel/lo".join_path("wor/ld") == "hel/lo/wor/ld"
+ # assert "".join_path("world") == "world"
+ # assert "hello".join_path("/world") == "/world"
+ # assert "hello/".join_path("world") == "hello/world"
+ # assert "hello/".join_path("/world") == "/world"
#
- # Note: I you want to join a great number of path, you can write
+ # Note: You may want to use `simplify_path` on the result.
#
- # [p1, p2, p3, p4].join("/")
+ # Note: This method works only with POSIX paths.
fun join_path(path: String): String
do
if path.is_empty then return self
if self.is_empty then return path
if path.chars[0] == '/' then return path
+ if self.last == '/' then return "{self}{path}"
return "{self}/{path}"
end
+ # Convert the path (`self`) to a program name.
+ #
+ # Ensure the path (`self`) will be treated as-is by POSIX shells when it is
+ # used as a program name. In order to do that, prepend `./` if needed.
+ #
+ # assert "foo".to_program_name == "./foo"
+ # assert "/foo".to_program_name == "/foo"
+ # assert "".to_program_name == "./" # At least, your shell will detect the error.
+ fun to_program_name: String do
+ if self.has_prefix("/") then
+ return self
+ else
+ return "./{self}"
+ end
+ end
+
# Alias for `join_path`
#
# assert "hello" / "world" == "hello/world"
diff --git a/lib/standard/math.nit b/lib/standard/math.nit
index ba4db63..a2e0966 100644
--- a/lib/standard/math.nit
+++ b/lib/standard/math.nit
@@ -23,10 +23,32 @@ in "C header" `{
redef class Int
# Returns a random `Int` in `[0 .. self[`.
fun rand: Int is extern "kernel_Int_Int_rand_0"
+
+ # Returns the result of a binary AND operation on `self` and `i`
+ #
+ # assert 0x10.bin_and(0x01) == 0
fun bin_and(i: Int): Int is extern "kernel_Int_Int_binand_0"
+
+ # Returns the result of a binary OR operation on `self` and `i`
+ #
+ # assert 0x10.bin_or(0x01) == 0x11
fun bin_or(i: Int): Int is extern "kernel_Int_Int_binor_0"
+
+ # Returns the result of a binary XOR operation on `self` and `i`
+ #
+ # assert 0x101.bin_xor(0x110) == 0x11
fun bin_xor(i: Int): Int is extern "kernel_Int_Int_binxor_0"
+
+ # Returns the 1's complement of `self`
+ #
+ # assert 0x2F.bin_not == -48
+ fun bin_not: Int is extern "kernel_Int_Int_binnot_0"
+
+ # Returns the square root of `self`
+ #
+ # assert 16.sqrt == 4
fun sqrt: Int `{ return sqrt(recv); `}
+
# Returns the greatest common divisor of `self` and `o`
#
# assert 54.gcd(24) == 6
diff --git a/lib/standard/math_nit.h b/lib/standard/math_nit.h
index 466a443..e13aac3 100644
--- a/lib/standard/math_nit.h
+++ b/lib/standard/math_nit.h
@@ -21,6 +21,7 @@
#define kernel_Int_Int_binand_0(self, p0) (self & p0)
#define kernel_Int_Int_binor_0(self, p0) (self | p0)
#define kernel_Int_Int_binxor_0(self, p0) (self ^ p0)
+#define kernel_Int_Int_binnot_0(self) (~self)
#define kernel_Float_Float_sqrt_0(self) sqrt(self)
#define kernel_Float_Float_cos_0(self) cos(self)
#define kernel_Float_Float_sin_0(self) sin(self)
diff --git a/lib/standard/queue.nit b/lib/standard/queue.nit
index c4cce96..ceab407 100644
--- a/lib/standard/queue.nit
+++ b/lib/standard/queue.nit
@@ -47,7 +47,7 @@ interface Queue[E]
# assert a.take == 2
# assert a.take == 1
#
- # var h = new MinHeapCmp[Int]
+ # var h = new MinHeap[Int].default
# h.add 2
# h.add 1
# h.add 10
@@ -206,11 +206,10 @@ end
# A min-heap implemented over an array
#
# The order is given by the `comparator`.
-# If `E` is Comparable, then the subclass `MinHeapCmp` can be used instead.
#
# ~~~
# var a = [3,4,1,2]
-# var h = new MinHeap[Int](new DefaultComparator[Int])
+# var h = new MinHeap[Int].default
# h.add_all(a)
# assert h.peek == 1
# var b = h.take_all
@@ -220,7 +219,20 @@ class MinHeap[E: Object]
super Queue[E]
private var items = new Array[E]
- var comparator: Comparator[E]
+
+ # The comparator used to order the Heap
+ var comparator: Comparator
+
+ # Use the `default_comparator` on Comparable elements
+ #
+ # Require self isa MinHeap[Comparable]
+ init default
+ do
+ assert self isa MinHeap[Comparable]
+ init(default_comparator)
+ end
+
+ init(comparator: Comparator) do self.comparator = comparator
redef fun is_empty do return items.is_empty
redef fun length do return items.length
@@ -307,18 +319,3 @@ class MinHeap[E: Object]
return true
end
end
-
-# A `MinHeap` for `Comparable` that does not need a specific `Comparator`
-#
-# ~~~
-# var a = [3,4,1,2]
-# var h = new MinHeapCmp[Int]
-# h.add_all(a)
-# assert h.peek == 1
-# var b = h.take_all
-# assert b == [1, 2, 3, 4]
-# ~~~
-class MinHeapCmp[E: Comparable]
- super MinHeap[E]
- init is old_style_init do super(new DefaultComparator[E])
-end
diff --git a/lib/standard/stream.nit b/lib/standard/stream.nit
index 6b70e21..6765305 100644
--- a/lib/standard/stream.nit
+++ b/lib/standard/stream.nit
@@ -1,13 +1,11 @@
# This file is part of NIT ( http://www.nitlanguage.org ).
#
-# Copyright 2004-2008 Jean Privat
-#
-# This file is free software, which comes along with NIT. This software is
+# This file is free software, which comes along with NIT. This software is
# distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
-# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
-# PARTICULAR PURPOSE. You can modify it is you want, provided this header
+# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE. You can modify it is you want, provided this header
# is kept unaltered, and a notification of the changes is added.
-# You are allowed to redistribute it and sell it, alone or is a part of
+# You are allowed to redistribute it and sell it, alone or is a part of
# another product.
# Input and output streams of characters
@@ -209,7 +207,7 @@ abstract class BufferedIStream
fill_buffer
end
return s.to_s
- end
+ end
redef fun append_line_to(s)
do
@@ -258,7 +256,7 @@ abstract class BufferedIStream
# Fill the buffer
protected fun fill_buffer is abstract
- # Is the last fill_buffer reach the end
+ # Is the last fill_buffer reach the end
protected fun end_reached: Bool is abstract
# Allocate a `_buffer` for a given `capacity`.
@@ -399,7 +397,9 @@ redef interface Object
`}
end
-# Stream to a String. Mainly used for compatibility with OStream type and tests.
+# Stream to a String.
+#
+# Mainly used for compatibility with OStream type and tests.
class StringOStream
super OStream
@@ -415,3 +415,33 @@ class StringOStream
protected var closed = false
redef fun close do closed = true
end
+
+# Stream from a String.
+#
+# Mainly used for compatibility with IStream type and tests.
+class StringIStream
+ super IStream
+
+ # The string to read from.
+ var source: String
+
+ # The current position in the string.
+ private var cursor: Int = 0
+
+ redef fun read_char do
+ if cursor < source.length then
+ var c = source[cursor].ascii
+
+ cursor += 1
+ return c
+ else
+ return -1
+ end
+ end
+
+ redef fun close do
+ source = ""
+ end
+
+ redef fun eof do return cursor >= source.length
+end
diff --git a/lib/standard/string.nit b/lib/standard/string.nit
index 3eede86..f78c0ac 100644
--- a/lib/standard/string.nit
+++ b/lib/standard/string.nit
@@ -1775,12 +1775,12 @@ redef class Int
end
redef class Float
- # Pretty print self, print needoed decimals up to a max of 3.
+ # Pretty representation of `self`, with decimals as needed from 1 to a maximum of 3
#
- # assert 12.34.to_s == "12.34"
- # assert (-0120.03450).to_s == "-120.035"
+ # assert 12.34.to_s == "12.34"
+ # assert (-0120.030).to_s == "-120.03"
#
- # see `to_precision` for a different precision.
+ # see `to_precision` for a custom precision.
redef fun to_s do
var str = to_precision( 3 )
if is_inf != 0 or is_nan then return str
@@ -1799,13 +1799,15 @@ redef class Float
return str
end
- # `self` representation with `nb` digits after the '.'.
+ # `String` representation of `self` with the given number of `decimals`
#
- # assert 12.345.to_precision(1) == "12.3"
- # assert 12.345.to_precision(2) == "12.35"
- # assert 12.345.to_precision(3) == "12.345"
- # assert 12.345.to_precision(4) == "12.3450"
- fun to_precision(nb: Int): String
+ # assert 12.345.to_precision(0) == "12"
+ # assert 12.345.to_precision(3) == "12.345"
+ # assert (-12.345).to_precision(3) == "-12.345"
+ # assert (-0.123).to_precision(3) == "-0.123"
+ # assert 0.999.to_precision(2) == "1.00"
+ # assert 0.999.to_precision(4) == "0.9990"
+ fun to_precision(decimals: Int): String
do
if is_nan then return "nan"
@@ -1816,25 +1818,34 @@ redef class Float
return "-inf"
end
- if nb == 0 then return self.to_i.to_s
+ if decimals == 0 then return self.to_i.to_s
var f = self
- for i in [0..nb[ do f = f * 10.0
+ for i in [0..decimals[ do f = f * 10.0
if self > 0.0 then
f = f + 0.5
else
f = f - 0.5
end
var i = f.to_i
- if i == 0 then return "0.0"
- var s = i.to_s
+ if i == 0 then return "0." + "0"*decimals
+
+ # Prepare both parts of the float, before and after the "."
+ var s = i.abs.to_s
var sl = s.length
- if sl > nb then
- var p1 = s.substring(0, s.length-nb)
- var p2 = s.substring(s.length-nb, nb)
- return p1 + "." + p2
+ var p1
+ var p2
+ if sl > decimals then
+ # Has something before the "."
+ p1 = s.substring(0, sl-decimals)
+ p2 = s.substring(sl-decimals, decimals)
else
- return "0." + ("0"*(nb-sl)) + s
+ p1 = "0"
+ p2 = "0"*(decimals-sl) + s
end
+
+ if i < 0 then p1 = "-" + p1
+
+ return p1 + "." + p2
end
# `self` representation with `nb` digits after the '.'.
@@ -2119,7 +2130,8 @@ end
#
# Note: it caching is not usefull, see `alpha_comparator`
class CachedAlphaComparator
- super Comparator[Object]
+ super Comparator
+ redef type COMPARED: Object
private var cache = new HashMap[Object, String]
@@ -2137,7 +2149,7 @@ end
# see `alpha_comparator`
private class AlphaComparator
- super Comparator[Object]
+ super Comparator
redef fun compare(a, b) do return a.to_s <=> b.to_s
end
@@ -2149,7 +2161,7 @@ end
# var a = [1, 2, 3, 10, 20]
# alpha_comparator.sort(a)
# assert a == [1, 10, 2, 20, 3]
-fun alpha_comparator: Comparator[Object] do return once new AlphaComparator
+fun alpha_comparator: Comparator do return once new AlphaComparator
# The arguments of the program as given by the OS
fun args: Sequence[String]
diff --git a/misc/jenkins/listnit.sh b/misc/jenkins/listnit.sh
index 2d38c2f..d0f1ac8 100755
--- a/misc/jenkins/listnit.sh
+++ b/misc/jenkins/listnit.sh
@@ -26,7 +26,7 @@
exclude="parser_abs.nit\|nitcc_lexer0"
# Directories needed for explicit -I options.
-includedirs="src contrib/tnitter/src/ contrib/benitlux/src/ examples/ contrib/wiringPi/lib/"
+includedirs="src contrib/tnitter/src/ contrib/benitlux/src/ examples/ contrib/wiringPi/lib/ contrib/opportunity/src/"
# Flag -I
incl=""
diff --git a/share/man/Makefile b/share/man/Makefile
new file mode 100644
index 0000000..3eeeb03
--- /dev/null
+++ b/share/man/Makefile
@@ -0,0 +1,21 @@
+# 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.
+
+IN=$(wildcard nit*.md)
+OUT=$(patsubst %.md,man1/%.1,$(IN))
+
+all: $(OUT)
+
+man1/%.1: %.md
+ pandoc $< -t man -s -o $@
diff --git a/share/man/README.md b/share/man/README.md
new file mode 100644
index 0000000..a167029
--- /dev/null
+++ b/share/man/README.md
@@ -0,0 +1,21 @@
+# Manual pages for nit commands
+
+Pages, in markdown, in this directory where initially generated thanks to the `--stub-man` options of the commands.
+
+Transformation to real man pages (troff) are done with `pandoc -t man -s` command.
+See the `Makefile`.
+
+
+Once generated, manpages can then be checked individually with `man -l`
+
+~~~
+man -l man1/nitg.1
+~~~
+
+For global access, one can set the `MANPATH` environment variable to this `man` directory (not the `man1` subdirectory).
+Do not forget to append a trailing column (`:`) to keep existing manpages accessible.
+
+~~~
+export MANPATH=/path/to/nit/share/man:
+man nitg
+~~~
diff --git a/share/man/nit.md b/share/man/nit.md
new file mode 100644
index 0000000..26b2adb
--- /dev/null
+++ b/share/man/nit.md
@@ -0,0 +1,99 @@
+% NIT(1)
+
+# NAME
+
+Interprets and debugs Nit programs.
+
+# SYNOPSYS
+
+nit [*options*]...
+
+# OPTIONS
+
+`-W`, `--warn`
+: Show more warnings
+
+`-w`, `--warning`
+: Show/hide a specific warning
+
+`-q`, `--quiet`
+: Do not show warnings
+
+`--stop-on-first-error`
+: Stop on first error
+
+`--no-color`
+: Do not use color to display errors and warnings
+
+`--log`
+: Generate various log files
+
+`--log-dir`
+: Directory where to generate log files
+
+`-h`, `-?`, `--help`
+: Show Help (This screen)
+
+`--version`
+: Show version and exit
+
+`--set-dummy-tool`
+: Set toolname and version to DUMMY. Useful for testing
+
+`-v`, `--verbose`
+: Verbose
+
+`--bash-completion`
+: Generate bash_completion file for this program
+
+`--stub-man`
+: Generate a stub manpage in pandoc markdown format
+
+`--disable-phase`
+: DEBUG: Disable a specific phase; use `list` to get the list.
+
+`-I`, `--path`
+: Set include path for loaders (may be used more than once)
+
+`--only-parse`
+: Only proceed to parse step of loaders
+
+`--only-metamodel`
+: Stop after meta-model processing
+
+`--ignore-visibility`
+: Do not check, and produce errors, on visibility issues.
+
+`--discover-call-trace`
+: Trace calls of the first invocation of a method
+
+`-d`
+: Launches the target program with the debugger attached to it
+
+`-c`
+: Launches the target program with the interpreter, such as when the program fails, the debugging prompt is summoned
+
+`--socket`
+: Launches the target program with raw output on the network via sockets
+
+`--websocket`
+: Launches the target program with output on the network via websockets
+
+`--port`
+: Sets the debug port (Defaults to 22125) - Must be contained between 0 and 65535
+
+`-o`
+: compatibility (does noting)
+
+`-m`
+: Additionals module to min-in
+
+`-e`
+: Specifies the program from command-line
+
+`-n`
+: Repeatedly run the program for each line in file-name arguments
+
+# SEE ALSO
+
+The Nit language documentation and the source code of its tools and libraries may be downloaded from
diff --git a/share/man/nitdoc.md b/share/man/nitdoc.md
new file mode 100644
index 0000000..d39c076
--- /dev/null
+++ b/share/man/nitdoc.md
@@ -0,0 +1,114 @@
+% NITDOC(1)
+
+# NAME
+
+Generates HTML pages of API documentation from Nit source files.
+
+# SYNOPSYS
+
+nitdoc [*options*]...
+
+# OPTIONS
+
+`-W`, `--warn`
+: Show more warnings
+
+`-w`, `--warning`
+: Show/hide a specific warning
+
+`-q`, `--quiet`
+: Do not show warnings
+
+`--stop-on-first-error`
+: Stop on first error
+
+`--no-color`
+: Do not use color to display errors and warnings
+
+`--log`
+: Generate various log files
+
+`--log-dir`
+: Directory where to generate log files
+
+`-h`, `-?`, `--help`
+: Show Help (This screen)
+
+`--version`
+: Show version and exit
+
+`--set-dummy-tool`
+: Set toolname and version to DUMMY. Useful for testing
+
+`-v`, `--verbose`
+: Verbose
+
+`--bash-completion`
+: Generate bash_completion file for this program
+
+`--stub-man`
+: Generate a stub manpage in pandoc markdown format
+
+`--disable-phase`
+: DEBUG: Disable a specific phase; use `list` to get the list.
+
+`-I`, `--path`
+: Set include path for loaders (may be used more than once)
+
+`--only-parse`
+: Only proceed to parse step of loaders
+
+`--only-metamodel`
+: Stop after meta-model processing
+
+`--ignore-visibility`
+: Do not check, and produce errors, on visibility issues.
+
+`-d`, `--dir`
+: output directory
+
+`--source`
+: link for source (%f for filename, %l for first line, %L for last line)
+
+`--sharedir`
+: directory containing nitdoc assets
+
+`--shareurl`
+: use shareurl instead of copy shared files
+
+`--no-dot`
+: do not generate graphes with graphviz
+
+`--private`
+: also generate private API
+
+`--custom-title`
+: custom title for homepage
+
+`--custom-footer-text`
+: custom footer text
+
+`--custom-overview-text`
+: custom intro text for homepage
+
+`--custom-brand`
+: custom link to external site
+
+`--github-upstream`
+: Git branch where edited commits will be pulled into (ex: user:repo:branch)
+
+`--github-base-sha1`
+: Git sha1 of base commit used to create pull request
+
+`--github-gitdir`
+: Git working directory used to resolve path name (ex: /home/me/myproject/)
+
+`--piwik-tracker`
+: Piwik tracker URL (ex: nitlanguage.org/piwik/)
+
+`--piwik-site-id`
+: Piwik site ID
+
+# SEE ALSO
+
+The Nit language documentation and the source code of its tools and libraries may be downloaded from
diff --git a/share/man/nitg.md b/share/man/nitg.md
new file mode 100644
index 0000000..1c45f1d
--- /dev/null
+++ b/share/man/nitg.md
@@ -0,0 +1,177 @@
+% NITG(1)
+
+# NAME
+
+Compiles Nit programs.
+
+# SYNOPSYS
+
+nitg [*options*]...
+
+# OPTIONS
+
+`-W`, `--warn`
+: Show more warnings
+
+`-w`, `--warning`
+: Show/hide a specific warning
+
+`-q`, `--quiet`
+: Do not show warnings
+
+`--stop-on-first-error`
+: Stop on first error
+
+`--no-color`
+: Do not use color to display errors and warnings
+
+`--log`
+: Generate various log files
+
+`--log-dir`
+: Directory where to generate log files
+
+`-h`, `-?`, `--help`
+: Show Help (This screen)
+
+`--version`
+: Show version and exit
+
+`--set-dummy-tool`
+: Set toolname and version to DUMMY. Useful for testing
+
+`-v`, `--verbose`
+: Verbose
+
+`--bash-completion`
+: Generate bash_completion file for this program
+
+`--stub-man`
+: Generate a stub manpage in pandoc markdown format
+
+`--disable-phase`
+: DEBUG: Disable a specific phase; use `list` to get the list.
+
+`-I`, `--path`
+: Set include path for loaders (may be used more than once)
+
+`--only-parse`
+: Only proceed to parse step of loaders
+
+`--only-metamodel`
+: Stop after meta-model processing
+
+`--ignore-visibility`
+: Do not check, and produce errors, on visibility issues.
+
+`-o`, `--output`
+: Output file
+
+`--dir`
+: Output directory
+
+`--no-cc`
+: Do not invoke C compiler
+
+`--no-main`
+: Do not generate main entry point
+
+`--make-flags`
+: Additional options to make
+
+`--compile-dir`
+: Directory used to generate temporary files
+
+`--hardening`
+: Generate contracts in the C code against bugs in the compiler
+
+`--no-shortcut-range`
+: Always insantiate a range and its iterator on 'for' loops
+
+`--no-check-covariance`
+: Disable type tests of covariant parameters (dangerous)
+
+`--no-check-attr-isset`
+: Disable isset tests before each attribute access (dangerous)
+
+`--no-check-assert`
+: Disable the evaluation of explicit 'assert' and 'as' (dangerous)
+
+`--no-check-autocast`
+: Disable implicit casts on unsafe expression usage (dangerous)
+
+`--no-check-null`
+: Disable tests of null receiver (dangerous)
+
+`--no-check-all`
+: Disable all tests (dangerous)
+
+`--typing-test-metrics`
+: Enable static and dynamic count of all type tests
+
+`--invocation-metrics`
+: Enable static and dynamic count of all method invocations
+
+`--isset-checks-metrics`
+: Enable static and dynamic count of isset checks before attributes access
+
+`--stacktrace`
+: Control the generation of stack traces
+
+`--no-gcc-directive`
+: Disable a advanced gcc directives for optimization
+
+`--release`
+: Compile in release mode and finalize application
+
+`--global`
+: Use global compilation
+
+`--separate`
+: Use separate compilation
+
+`--no-inline-intern`
+: Do not inline call to intern methods
+
+`--no-union-attribute`
+: Put primitive attibutes in a box instead of an union
+
+`--no-shortcut-equal`
+: Always call == in a polymorphic way
+
+`--inline-coloring-numbers`
+: Inline colors and ids (semi-global)
+
+`--inline-some-methods`
+: Allow the separate compiler to inline some methods (semi-global)
+
+`--direct-call-monomorph`
+: Allow the separate compiler to direct call monomorph sites (semi-global)
+
+`--skip-dead-methods`
+: Do not compile dead methods (semi-global)
+
+`--semi-global`
+: Enable all semi-global optimizations
+
+`--colo-dead-methods`
+: Force colorization of dead methods
+
+`--tables-metrics`
+: Enable static size measuring of tables used for vft, typing and resolution
+
+`--erasure`
+: Erase generic types
+
+`--no-check-erasure-cast`
+: Disable implicit casts on unsafe return with erasure-typing policy (dangerous)
+
+`--rta`
+: Activate RTA (implicit with --global and --separate)
+
+`-m`
+: Additionals module to min-in
+
+# SEE ALSO
+
+The Nit language documentation and the source code of its tools and libraries may be downloaded from
diff --git a/share/man/nitlight.md b/share/man/nitlight.md
new file mode 100644
index 0000000..54b2896
--- /dev/null
+++ b/share/man/nitlight.md
@@ -0,0 +1,84 @@
+% NITLIGHT(1)
+
+# NAME
+
+Generates HTML of highlited code from Nit source files.
+
+# SYNOPSYS
+
+nitlight [*options*]...
+
+# OPTIONS
+
+`-W`, `--warn`
+: Show more warnings
+
+`-w`, `--warning`
+: Show/hide a specific warning
+
+`-q`, `--quiet`
+: Do not show warnings
+
+`--stop-on-first-error`
+: Stop on first error
+
+`--no-color`
+: Do not use color to display errors and warnings
+
+`--log`
+: Generate various log files
+
+`--log-dir`
+: Directory where to generate log files
+
+`-h`, `-?`, `--help`
+: Show Help (This screen)
+
+`--version`
+: Show version and exit
+
+`--set-dummy-tool`
+: Set toolname and version to DUMMY. Useful for testing
+
+`-v`, `--verbose`
+: Verbose
+
+`--bash-completion`
+: Generate bash_completion file for this program
+
+`--stub-man`
+: Generate a stub manpage in pandoc markdown format
+
+`--disable-phase`
+: DEBUG: Disable a specific phase; use `list` to get the list.
+
+`-I`, `--path`
+: Set include path for loaders (may be used more than once)
+
+`--only-parse`
+: Only proceed to parse step of loaders
+
+`--only-metamodel`
+: Stop after meta-model processing
+
+`--ignore-visibility`
+: Do not check, and produce errors, on visibility issues.
+
+`-f`, `--fragment`
+: Omit document header and footer
+
+`--first-line`
+: Start the source file at this line (default: 1)
+
+`--last-line`
+: End the source file at this line (default: to the end)
+
+`-d`, `--dir`
+: Output html files in a specific directory (required if more than one module)
+
+`--full`
+: Process also imported modules
+
+# SEE ALSO
+
+The Nit language documentation and the source code of its tools and libraries may be downloaded from
diff --git a/share/man/nitls.md b/share/man/nitls.md
new file mode 100644
index 0000000..705a099
--- /dev/null
+++ b/share/man/nitls.md
@@ -0,0 +1,93 @@
+% NITLS(1)
+
+# NAME
+
+Lists the projects and/or paths of Nit sources files.
+
+# SYNOPSYS
+
+nitls [*options*]...
+
+# OPTIONS
+
+`-W`, `--warn`
+: Show more warnings
+
+`-w`, `--warning`
+: Show/hide a specific warning
+
+`-q`, `--quiet`
+: Do not show warnings
+
+`--stop-on-first-error`
+: Stop on first error
+
+`--no-color`
+: Do not use color to display errors and warnings
+
+`--log`
+: Generate various log files
+
+`--log-dir`
+: Directory where to generate log files
+
+`-h`, `-?`, `--help`
+: Show Help (This screen)
+
+`--version`
+: Show version and exit
+
+`--set-dummy-tool`
+: Set toolname and version to DUMMY. Useful for testing
+
+`-v`, `--verbose`
+: Verbose
+
+`--bash-completion`
+: Generate bash_completion file for this program
+
+`--stub-man`
+: Generate a stub manpage in pandoc markdown format
+
+`--disable-phase`
+: DEBUG: Disable a specific phase; use `list` to get the list.
+
+`-I`, `--path`
+: Set include path for loaders (may be used more than once)
+
+`--only-parse`
+: Only proceed to parse step of loaders
+
+`--only-metamodel`
+: Stop after meta-model processing
+
+`--ignore-visibility`
+: Do not check, and produce errors, on visibility issues.
+
+`-k`, `--keep`
+: Ignore errors and files that are not a Nit source file
+
+`-r`, `--recursive`
+: Process directories recussively
+
+`-t`, `--tree`
+: List source files in their groups and projects
+
+`-s`, `--source`
+: List source files
+
+`-P`, `--project`
+: List projects paths (default)
+
+`-d`, `--depends`
+: List dependencies of given modules
+
+`-p`, `--path`
+: List only path (instead of name + path)
+
+`-M`
+: List dependencies suitable for a rule in a Makefile. Alias for -d, -p and -s
+
+# SEE ALSO
+
+The Nit language documentation and the source code of its tools and libraries may be downloaded from
diff --git a/share/man/nitmetrics.md b/share/man/nitmetrics.md
new file mode 100644
index 0000000..5aeb779
--- /dev/null
+++ b/share/man/nitmetrics.md
@@ -0,0 +1,120 @@
+% NITMETRICS(1)
+
+# NAME
+
+Computes various metrics on Nit programs.
+
+# SYNOPSYS
+
+nitmetrics [*options*]...
+
+# OPTIONS
+
+`-W`, `--warn`
+: Show more warnings
+
+`-w`, `--warning`
+: Show/hide a specific warning
+
+`-q`, `--quiet`
+: Do not show warnings
+
+`--stop-on-first-error`
+: Stop on first error
+
+`--no-color`
+: Do not use color to display errors and warnings
+
+`--log`
+: Generate various log files
+
+`--log-dir`
+: Directory where to generate log files
+
+`-h`, `-?`, `--help`
+: Show Help (This screen)
+
+`--version`
+: Show version and exit
+
+`--set-dummy-tool`
+: Set toolname and version to DUMMY. Useful for testing
+
+`-v`, `--verbose`
+: Verbose
+
+`--bash-completion`
+: Generate bash_completion file for this program
+
+`--stub-man`
+: Generate a stub manpage in pandoc markdown format
+
+`--disable-phase`
+: DEBUG: Disable a specific phase; use `list` to get the list.
+
+`-I`, `--path`
+: Set include path for loaders (may be used more than once)
+
+`--only-parse`
+: Only proceed to parse step of loaders
+
+`--only-metamodel`
+: Stop after meta-model processing
+
+`--ignore-visibility`
+: Do not check, and produce errors, on visibility issues.
+
+`--all`
+: Compute all metrics
+
+`--mmodules`
+: Compute metrics about mmodules
+
+`--mclasses`
+: Compute metrics about mclasses
+
+`--mendel`
+: Compute mendel metrics
+
+`--inheritance`
+: Compute metrics about inheritance usage
+
+`--refinement`
+: Compute metrics about refinement usage
+
+`--self`
+: Compute metrics about the usage of explicit and implicit self
+
+`--ast`
+: Compute metrics about the usage of nodes and identifiers in the AST
+
+`--nullables`
+: Compute metrics on nullables send
+
+`--static-types`
+: Compute explicit static types metrics
+
+`--tables`
+: Compute tables metrics
+
+`--rta`
+: Compute RTA metrics
+
+`--csv`
+: Export metrics in CSV format
+
+`--generate_hyperdoc`
+: Generate Hyperdoc
+
+`--poset`
+: Complete metrics on posets
+
+`-d`, `--dir`
+: Directory where some statistics files are generated
+
+`--no-colors`
+: Disable colors in console outputs
+
+# SEE ALSO
+
+The Nit language documentation and the source code of its tools and libraries may be downloaded from
diff --git a/share/man/nitpick.md b/share/man/nitpick.md
new file mode 100644
index 0000000..f852d27
--- /dev/null
+++ b/share/man/nitpick.md
@@ -0,0 +1,69 @@
+% NITPICK(1)
+
+# NAME
+
+Collect potential style and code issues.
+
+# SYNOPSYS
+
+nitpick [*options*]...
+
+# OPTIONS
+
+`-W`, `--warn`
+: Show more warnings
+
+`-w`, `--warning`
+: Show/hide a specific warning
+
+`-q`, `--quiet`
+: Do not show warnings
+
+`--stop-on-first-error`
+: Stop on first error
+
+`--no-color`
+: Do not use color to display errors and warnings
+
+`--log`
+: Generate various log files
+
+`--log-dir`
+: Directory where to generate log files
+
+`-h`, `-?`, `--help`
+: Show Help (This screen)
+
+`--version`
+: Show version and exit
+
+`--set-dummy-tool`
+: Set toolname and version to DUMMY. Useful for testing
+
+`-v`, `--verbose`
+: Verbose
+
+`--bash-completion`
+: Generate bash_completion file for this program
+
+`--stub-man`
+: Generate a stub manpage in pandoc markdown format
+
+`--disable-phase`
+: DEBUG: Disable a specific phase; use `list` to get the list.
+
+`-I`, `--path`
+: Set include path for loaders (may be used more than once)
+
+`--only-parse`
+: Only proceed to parse step of loaders
+
+`--only-metamodel`
+: Stop after meta-model processing
+
+`--ignore-visibility`
+: Do not check, and produce errors, on visibility issues.
+
+# SEE ALSO
+
+The Nit language documentation and the source code of its tools and libraries may be downloaded from
diff --git a/share/man/nitpretty.md b/share/man/nitpretty.md
new file mode 100644
index 0000000..3238ced
--- /dev/null
+++ b/share/man/nitpretty.md
@@ -0,0 +1,84 @@
+% NITPRETTY(1)
+
+# NAME
+
+Pretty print Nit code from Nit source files.
+
+# SYNOPSYS
+
+nitpretty [*options*]...
+
+# OPTIONS
+
+`-W`, `--warn`
+: Show more warnings
+
+`-w`, `--warning`
+: Show/hide a specific warning
+
+`-q`, `--quiet`
+: Do not show warnings
+
+`--stop-on-first-error`
+: Stop on first error
+
+`--no-color`
+: Do not use color to display errors and warnings
+
+`--log`
+: Generate various log files
+
+`--log-dir`
+: Directory where to generate log files
+
+`-h`, `-?`, `--help`
+: Show Help (This screen)
+
+`--version`
+: Show version and exit
+
+`--set-dummy-tool`
+: Set toolname and version to DUMMY. Useful for testing
+
+`-v`, `--verbose`
+: Verbose
+
+`--bash-completion`
+: Generate bash_completion file for this program
+
+`--stub-man`
+: Generate a stub manpage in pandoc markdown format
+
+`--disable-phase`
+: DEBUG: Disable a specific phase; use `list` to get the list.
+
+`-I`, `--path`
+: Set include path for loaders (may be used more than once)
+
+`--only-parse`
+: Only proceed to parse step of loaders
+
+`--only-metamodel`
+: Stop after meta-model processing
+
+`--ignore-visibility`
+: Do not check, and produce errors, on visibility issues.
+
+`--dir`
+: Working directory (default is '.nitpretty')
+
+`-o`, `--output`
+: Output name (default is pretty.nit)
+
+`--diff`
+: Show diff between source and output
+
+`--meld`
+: Show diff between source and output using meld
+
+`--check`
+: Check format of Nit source files
+
+# SEE ALSO
+
+The Nit language documentation and the source code of its tools and libraries may be downloaded from
diff --git a/share/man/nitserial.md b/share/man/nitserial.md
new file mode 100644
index 0000000..056b692
--- /dev/null
+++ b/share/man/nitserial.md
@@ -0,0 +1,75 @@
+% NITSERIAL(1)
+
+# NAME
+
+Generates a serialization support module
+
+# SYNOPSYS
+
+nitserial [*options*]...
+
+# OPTIONS
+
+`-o`, `--output`
+: Output file (can also be 'stdout')
+
+`--dir`
+: Output directory
+
+`-W`, `--warn`
+: Show more warnings
+
+`-w`, `--warning`
+: Show/hide a specific warning
+
+`-q`, `--quiet`
+: Do not show warnings
+
+`--stop-on-first-error`
+: Stop on first error
+
+`--no-color`
+: Do not use color to display errors and warnings
+
+`--log`
+: Generate various log files
+
+`--log-dir`
+: Directory where to generate log files
+
+`-h`, `-?`, `--help`
+: Show Help (This screen)
+
+`--version`
+: Show version and exit
+
+`--set-dummy-tool`
+: Set toolname and version to DUMMY. Useful for testing
+
+`-v`, `--verbose`
+: Verbose
+
+`--bash-completion`
+: Generate bash_completion file for this program
+
+`--stub-man`
+: Generate a stub manpage in pandoc markdown format
+
+`--disable-phase`
+: DEBUG: Disable a specific phase; use `list` to get the list.
+
+`-I`, `--path`
+: Set include path for loaders (may be used more than once)
+
+`--only-parse`
+: Only proceed to parse step of loaders
+
+`--only-metamodel`
+: Stop after meta-model processing
+
+`--ignore-visibility`
+: Do not check, and produce errors, on visibility issues.
+
+# SEE ALSO
+
+The Nit language documentation and the source code of its tools and libraries may be downloaded from
diff --git a/share/man/nitunit.md b/share/man/nitunit.md
new file mode 100644
index 0000000..24d2e1e
--- /dev/null
+++ b/share/man/nitunit.md
@@ -0,0 +1,99 @@
+% NITUNIT(1)
+
+# NAME
+
+Executes the unit tests from Nit source files.
+
+# SYNOPSYS
+
+nitunit [*options*]...
+
+# OPTIONS
+
+`-W`, `--warn`
+: Show more warnings
+
+`-w`, `--warning`
+: Show/hide a specific warning
+
+`-q`, `--quiet`
+: Do not show warnings
+
+`--stop-on-first-error`
+: Stop on first error
+
+`--no-color`
+: Do not use color to display errors and warnings
+
+`--log`
+: Generate various log files
+
+`--log-dir`
+: Directory where to generate log files
+
+`-h`, `-?`, `--help`
+: Show Help (This screen)
+
+`--version`
+: Show version and exit
+
+`--set-dummy-tool`
+: Set toolname and version to DUMMY. Useful for testing
+
+`-v`, `--verbose`
+: Verbose
+
+`--bash-completion`
+: Generate bash_completion file for this program
+
+`--stub-man`
+: Generate a stub manpage in pandoc markdown format
+
+`--disable-phase`
+: DEBUG: Disable a specific phase; use `list` to get the list.
+
+`-I`, `--path`
+: Set include path for loaders (may be used more than once)
+
+`--only-parse`
+: Only proceed to parse step of loaders
+
+`--only-metamodel`
+: Stop after meta-model processing
+
+`--ignore-visibility`
+: Do not check, and produce errors, on visibility issues.
+
+`--full`
+: Process also imported modules
+
+`-o`, `--output`
+: Output name (default is 'nitunit.xml')
+
+`--dir`
+: Working directory (default is '.nitunit')
+
+`--no-act`
+: Does not compile and run tests
+
+`-p`, `--pattern`
+: Only run test case with name that match pattern. Examples: 'TestFoo', 'TestFoo*', 'TestFoo::test_foo', 'TestFoo::test_foo*', 'test_foo', 'test_foo*'
+
+`-t`, `--target-file`
+: Specify test suite location.
+
+`--gen-suite`
+: Generate test suite skeleton for a module
+
+`-f`, `--force`
+: Force test generation even if file exists
+
+`--private`
+: Also generate test case for private methods
+
+`--only-show`
+: Only display skeleton, do not write file
+
+# SEE ALSO
+
+The Nit language documentation and the source code of its tools and libraries may be downloaded from
diff --git a/share/man/nitx.md b/share/man/nitx.md
new file mode 100644
index 0000000..73cee66
--- /dev/null
+++ b/share/man/nitx.md
@@ -0,0 +1,69 @@
+% NITX(1)
+
+# NAME
+
+Displays specific pieces of API information from Nit source files.
+
+# SYNOPSYS
+
+nitx [*options*]...
+
+# OPTIONS
+
+`-W`, `--warn`
+: Show more warnings
+
+`-w`, `--warning`
+: Show/hide a specific warning
+
+`-q`, `--quiet`
+: Do not show warnings
+
+`--stop-on-first-error`
+: Stop on first error
+
+`--no-color`
+: Do not use color to display errors and warnings
+
+`--log`
+: Generate various log files
+
+`--log-dir`
+: Directory where to generate log files
+
+`-h`, `-?`, `--help`
+: Show Help (This screen)
+
+`--version`
+: Show version and exit
+
+`--set-dummy-tool`
+: Set toolname and version to DUMMY. Useful for testing
+
+`-v`, `--verbose`
+: Verbose
+
+`--bash-completion`
+: Generate bash_completion file for this program
+
+`--stub-man`
+: Generate a stub manpage in pandoc markdown format
+
+`--disable-phase`
+: DEBUG: Disable a specific phase; use `list` to get the list.
+
+`-I`, `--path`
+: Set include path for loaders (may be used more than once)
+
+`--only-parse`
+: Only proceed to parse step of loaders
+
+`--only-metamodel`
+: Stop after meta-model processing
+
+`--ignore-visibility`
+: Do not check, and produce errors, on visibility issues.
+
+# SEE ALSO
+
+The Nit language documentation and the source code of its tools and libraries may be downloaded from
diff --git a/src/astbuilder.nit b/src/astbuilder.nit
index 8e17b4e..630c1c0 100644
--- a/src/astbuilder.nit
+++ b/src/astbuilder.nit
@@ -53,6 +53,12 @@ class ASTBuilder
return new ABlockExpr.make
end
+ # Make a new, empty, loop of statements
+ fun make_loop: ALoopExpr
+ do
+ return new ALoopExpr.make
+ end
+
# Make a new variable read
fun make_var_read(variable: Variable, mtype: MType): AVarExpr
do
@@ -84,6 +90,12 @@ class ASTBuilder
return new ADoExpr.make
end
+ # Make a new break for a given escapemark
+ fun make_break(escapemark: EscapeMark): ABreakExpr
+ do
+ return new ABreakExpr.make(escapemark)
+ end
+
# Make a new condinionnal
# `mtype` is the return type of the whole if, in case of a ternary operator.
fun make_if(condition: AExpr, mtype: nullable MType): AIfExpr
@@ -142,6 +154,7 @@ redef class AExpr
# Note: this method, aimed to `ABlockExpr` is promoted to `AExpr` because of the limitations of the hierarchies generated by sablecc3
fun add(expr: AExpr)
do
+ print "add not implemented in {inspect}"
abort
end
end
@@ -172,29 +185,54 @@ redef class ABlockExpr
end
end
+redef class ALoopExpr
+ private init make
+ do
+ _n_kwloop = new TKwloop
+ self.is_typed = true
+ n_block = new ABlockExpr
+ n_block.is_typed = true
+ end
+
+ redef fun add(expr: AExpr)
+ do
+ n_block.add expr
+ end
+end
+
redef class ADoExpr
private init make
do
_n_kwdo = new TKwdo
- escapemark = new EscapeMark(null, false)
+ self.is_typed = true
+ n_block = new ABlockExpr
+ n_block.is_typed = true
end
# Make a new break expression of the given do
fun make_break: ABreakExpr
do
- var escapemark = self.escapemark
+ var escapemark = self.break_mark
if escapemark == null then
- escapemark = new EscapeMark(null, false)
- self.escapemark = escapemark
+ escapemark = new EscapeMark(null)
+ self.break_mark = escapemark
end
return new ABreakExpr.make(escapemark)
end
+
+ redef fun add(expr: AExpr)
+ do
+ n_block.add expr
+ end
end
redef class ABreakExpr
private init make(escapemark: EscapeMark)
do
+ _n_kwbreak = new TKwbreak
self.escapemark = escapemark
+ escapemark.escapes.add self
+ self.is_typed = true
end
end
@@ -251,7 +289,6 @@ redef class ACallExpr
if args != null then
self.n_args.n_exprs.add_all(args)
end
- var mtype = recv.mtype.as(not null)
self.callsite = callsite
self.mtype = callsite.msignature.return_mtype
self.is_typed = true
diff --git a/src/compiler/abstract_compiler.nit b/src/compiler/abstract_compiler.nit
index c98d54e..85222a9 100644
--- a/src/compiler/abstract_compiler.nit
+++ b/src/compiler/abstract_compiler.nit
@@ -22,47 +22,46 @@ import semantize
import platform
import c_tools
private import annotation
+import mixin
# Add compiling options
redef class ToolContext
# --output
- var opt_output: OptionString = new OptionString("Output file", "-o", "--output")
+ var opt_output = new OptionString("Output file", "-o", "--output")
# --dir
- var opt_dir: OptionString = new OptionString("Output directory", "--dir")
+ var opt_dir = new OptionString("Output directory", "--dir")
# --no-cc
- var opt_no_cc: OptionBool = new OptionBool("Do not invoke C compiler", "--no-cc")
+ var opt_no_cc = new OptionBool("Do not invoke C compiler", "--no-cc")
# --no-main
- var opt_no_main: OptionBool = new OptionBool("Do not generate main entry point", "--no-main")
+ var opt_no_main = new OptionBool("Do not generate main entry point", "--no-main")
# --cc-paths
- var opt_cc_path: OptionArray = new OptionArray("Set include path for C header files (may be used more than once)", "--cc-path")
+ var opt_cc_path = new OptionArray("Set include path for C header files (may be used more than once)", "--cc-path")
# --make-flags
- var opt_make_flags: OptionString = new OptionString("Additional options to make", "--make-flags")
+ var opt_make_flags = new OptionString("Additional options to make", "--make-flags")
# --compile-dir
- var opt_compile_dir: OptionString = new OptionString("Directory used to generate temporary files", "--compile-dir")
+ var opt_compile_dir = new OptionString("Directory used to generate temporary files", "--compile-dir")
# --hardening
- var opt_hardening: OptionBool = new OptionBool("Generate contracts in the C code against bugs in the compiler", "--hardening")
- # --no-shortcut-range
- var opt_no_shortcut_range: OptionBool = new OptionBool("Always insantiate a range and its iterator on 'for' loops", "--no-shortcut-range")
+ var opt_hardening = new OptionBool("Generate contracts in the C code against bugs in the compiler", "--hardening")
# --no-check-covariance
- var opt_no_check_covariance: OptionBool = new OptionBool("Disable type tests of covariant parameters (dangerous)", "--no-check-covariance")
+ var opt_no_check_covariance = new OptionBool("Disable type tests of covariant parameters (dangerous)", "--no-check-covariance")
# --no-check-attr-isset
- var opt_no_check_attr_isset: OptionBool = new OptionBool("Disable isset tests before each attribute access (dangerous)", "--no-check-attr-isset")
+ var opt_no_check_attr_isset = new OptionBool("Disable isset tests before each attribute access (dangerous)", "--no-check-attr-isset")
# --no-check-assert
- var opt_no_check_assert: OptionBool = new OptionBool("Disable the evaluation of explicit 'assert' and 'as' (dangerous)", "--no-check-assert")
+ var opt_no_check_assert = new OptionBool("Disable the evaluation of explicit 'assert' and 'as' (dangerous)", "--no-check-assert")
# --no-check-autocast
- var opt_no_check_autocast: OptionBool = new OptionBool("Disable implicit casts on unsafe expression usage (dangerous)", "--no-check-autocast")
+ var opt_no_check_autocast = new OptionBool("Disable implicit casts on unsafe expression usage (dangerous)", "--no-check-autocast")
# --no-check-null
- var opt_no_check_null: OptionBool = new OptionBool("Disable tests of null receiver (dangerous)", "--no-check-null")
+ var opt_no_check_null = new OptionBool("Disable tests of null receiver (dangerous)", "--no-check-null")
# --no-check-all
- var opt_no_check_all: OptionBool = new OptionBool("Disable all tests (dangerous)", "--no-check-all")
+ var opt_no_check_all = new OptionBool("Disable all tests (dangerous)", "--no-check-all")
# --typing-test-metrics
- var opt_typing_test_metrics: OptionBool = new OptionBool("Enable static and dynamic count of all type tests", "--typing-test-metrics")
+ var opt_typing_test_metrics = new OptionBool("Enable static and dynamic count of all type tests", "--typing-test-metrics")
# --invocation-metrics
- var opt_invocation_metrics: OptionBool = new OptionBool("Enable static and dynamic count of all method invocations", "--invocation-metrics")
+ var opt_invocation_metrics = new OptionBool("Enable static and dynamic count of all method invocations", "--invocation-metrics")
# --isset-checks-metrics
- var opt_isset_checks_metrics: OptionBool = new OptionBool("Enable static and dynamic count of isset checks before attributes access", "--isset-checks-metrics")
+ var opt_isset_checks_metrics = new OptionBool("Enable static and dynamic count of isset checks before attributes access", "--isset-checks-metrics")
# --stacktrace
- var opt_stacktrace: OptionString = new OptionString("Control the generation of stack traces", "--stacktrace")
+ var opt_stacktrace = new OptionString("Control the generation of stack traces", "--stacktrace")
# --no-gcc-directives
var opt_no_gcc_directive = new OptionArray("Disable a advanced gcc directives for optimization", "--no-gcc-directive")
# --release
@@ -71,7 +70,7 @@ redef class ToolContext
redef init
do
super
- self.option_context.add_option(self.opt_output, self.opt_dir, self.opt_no_cc, self.opt_no_main, self.opt_make_flags, self.opt_compile_dir, self.opt_hardening, self.opt_no_shortcut_range)
+ self.option_context.add_option(self.opt_output, self.opt_dir, self.opt_no_cc, self.opt_no_main, self.opt_make_flags, self.opt_compile_dir, self.opt_hardening)
self.option_context.add_option(self.opt_no_check_covariance, self.opt_no_check_attr_isset, self.opt_no_check_assert, self.opt_no_check_autocast, self.opt_no_check_null, self.opt_no_check_all)
self.option_context.add_option(self.opt_typing_test_metrics, self.opt_invocation_metrics, self.opt_isset_checks_metrics)
self.option_context.add_option(self.opt_stacktrace)
@@ -181,7 +180,6 @@ class MakefileToolchain
do
gather_cc_paths
- var mainmodule = compiler.mainmodule
var compile_dir = compile_dir
# Generate the .h and .c files
@@ -229,7 +227,6 @@ class MakefileToolchain
compiler.files_to_copy.add "{cc_paths.first}/gc_chooser.h"
# FFI
- var m2m = toolcontext.modelbuilder.mmodule2nmodule
for m in compiler.mainmodule.in_importation.greaters do
compiler.finalize_ffi_for_module(m)
end
@@ -310,7 +307,16 @@ class MakefileToolchain
fun makefile_name(mainmodule: MModule): String do return "{mainmodule.name}.mk"
- fun default_outname(mainmodule: MModule): String do return mainmodule.name
+ fun default_outname(mainmodule: MModule): String
+ do
+ # Search a non fictive module
+ var res = mainmodule.name
+ while mainmodule.is_fictive do
+ mainmodule = mainmodule.in_importation.direct_greaters.first
+ res = mainmodule.name
+ end
+ return res
+ end
# Combine options and platform informations to get the final path of the outfile
fun outfile(mainmodule: MModule): String
@@ -342,7 +348,6 @@ class MakefileToolchain
end
var linker_options = new HashSet[String]
- var m2m = toolcontext.modelbuilder.mmodule2nmodule
for m in mainmodule.in_importation.greaters do
var libs = m.collect_linker_libs
if libs != null then linker_options.add_all(libs)
@@ -450,7 +455,7 @@ abstract class AbstractCompiler
# The real main module of the program
var realmainmodule: MModule
- # The modeulbuilder used to know the model and the AST
+ # The modelbuilder used to know the model and the AST
var modelbuilder: ModelBuilder is protected writable
# Is hardening asked? (see --hardening)
@@ -474,7 +479,7 @@ abstract class AbstractCompiler
# The list of all associated files
# Used to generate .c files
- var files: List[CodeFile] = new List[CodeFile]
+ var files = new List[CodeFile]
# Initialize a visitor specific for a compiler engine
fun new_visitor: VISITOR is abstract
@@ -541,8 +546,6 @@ abstract class AbstractCompiler
# Compile C headers
# This method call compile_header_strucs method that has to be refined
fun compile_header do
- var v = self.header
- var toolctx = modelbuilder.toolcontext
self.header.add_decl("#include ")
self.header.add_decl("#include ")
self.header.add_decl("#include ")
@@ -891,6 +894,7 @@ extern void nitni_global_ref_decr( struct nitni_ref *ref ) {
var cds = mtype.collect_mclassdefs(self.mainmodule).to_a
self.mainmodule.linearize_mclassdefs(cds)
for cd in cds do
+ if not self.modelbuilder.mclassdef2nclassdef.has_key(cd) then continue
var n = self.modelbuilder.mclassdef2nclassdef[cd]
for npropdef in n.n_propdefs do
if npropdef isa AAttrPropdef then
@@ -906,6 +910,7 @@ extern void nitni_global_ref_decr( struct nitni_ref *ref ) {
var cds = mtype.collect_mclassdefs(self.mainmodule).to_a
self.mainmodule.linearize_mclassdefs(cds)
for cd in cds do
+ if not self.modelbuilder.mclassdef2nclassdef.has_key(cd) then continue
var n = self.modelbuilder.mclassdef2nclassdef[cd]
for npropdef in n.n_propdefs do
if npropdef isa AAttrPropdef then
@@ -1044,7 +1049,7 @@ abstract class AbstractCompilerVisitor
fun get_property(name: String, recv: MType): MMethod
do
assert recv isa MClassType
- return self.compiler.modelbuilder.force_get_primitive_method(self.current_node.as(not null), name, recv.mclass, self.compiler.mainmodule)
+ return self.compiler.modelbuilder.force_get_primitive_method(self.current_node, name, recv.mclass, self.compiler.mainmodule)
end
fun compile_callsite(callsite: CallSite, arguments: Array[RuntimeVariable]): nullable RuntimeVariable
@@ -1081,39 +1086,45 @@ abstract class AbstractCompilerVisitor
fun native_array_def(pname: String, ret_type: nullable MType, arguments: Array[RuntimeVariable]) is abstract
- # Transform varargs, in raw arguments, into a single argument of type `Array`
- # Note: this method modify the given `args`
- # If there is no vararg, then `args` is not modified.
- fun varargize(mpropdef: MPropDef, msignature: MSignature, args: Array[RuntimeVariable])
+ # Evaluate `args` as expressions in the call of `mpropdef` on `recv`.
+ # This method is used to manage varargs in signatures and returns the real array
+ # of runtime variables to use in the call.
+ fun varargize(mpropdef: MMethodDef, recv: RuntimeVariable, args: SequenceRead[AExpr]): Array[RuntimeVariable]
do
- var recv = args.first
- var vararg_rank = msignature.vararg_rank
- if vararg_rank >= 0 then
- assert args.length >= msignature.arity + 1 # because of self
- var rawargs = args
- args = new Array[RuntimeVariable]
-
- args.add(rawargs.first) # recv
-
- for i in [0..vararg_rank[ do
- args.add(rawargs[i+1])
- end
+ var msignature = mpropdef.new_msignature or else mpropdef.msignature.as(not null)
+ var res = new Array[RuntimeVariable]
+ res.add(recv)
- var vararg_lastrank = vararg_rank + rawargs.length-1-msignature.arity
- var vararg = new Array[RuntimeVariable]
- for i in [vararg_rank..vararg_lastrank] do
- vararg.add(rawargs[i+1])
- end
+ if args.is_empty then return res
- var elttype = msignature.mparameters[vararg_rank].mtype
- args.add(self.vararg_instance(mpropdef, recv, vararg, elttype))
+ var vararg_rank = msignature.vararg_rank
+ var vararg_len = args.length - msignature.arity
+ if vararg_len < 0 then vararg_len = 0
- for i in [vararg_lastrank+1..rawargs.length-1[ do
- args.add(rawargs[i+1])
+ for i in [0..msignature.arity[ do
+ if i == vararg_rank then
+ var ne = args[i]
+ if ne isa AVarargExpr then
+ var e = self.expr(ne.n_expr, null)
+ res.add(e)
+ continue
+ end
+ var vararg = new Array[RuntimeVariable]
+ for j in [vararg_rank..vararg_rank+vararg_len] do
+ var e = self.expr(args[j], null)
+ vararg.add(e)
+ end
+ var elttype = msignature.mparameters[vararg_rank].mtype
+ var arg = self.vararg_instance(mpropdef, recv, vararg, elttype)
+ res.add(arg)
+ else
+ var j = i
+ if i > vararg_rank then j += vararg_len
+ var e = self.expr(args[j], null)
+ res.add(e)
end
- rawargs.clear
- rawargs.add_all(args)
end
+ return res
end
# Type handling
@@ -1217,7 +1228,7 @@ abstract class AbstractCompilerVisitor
# Checks
- # Add a check and an abort for a null reciever if needed
+ # Add a check and an abort for a null receiver if needed
fun check_recv_notnull(recv: RuntimeVariable)
do
if self.compiler.modelbuilder.toolcontext.opt_no_check_null.value then return
@@ -1232,7 +1243,7 @@ abstract class AbstractCompilerVisitor
# Names handling
- private var names: HashSet[String] = new HashSet[String]
+ private var names = new HashSet[String]
private var last: Int = 0
# Return a new name based on `s` and unique in the visitor
@@ -1266,6 +1277,14 @@ abstract class AbstractCompilerVisitor
return name
end
+ # Insert a C label for associated with an escapemark
+ fun add_escape_label(e: nullable EscapeMark)
+ do
+ if e == null then return
+ if e.escapes.is_empty then return
+ add("BREAK_{escapemark_name(e)}: (void)0;")
+ end
+
private var escapemark_names = new HashMap[EscapeMark, String]
# Return a "const char*" variable associated to the classname of the dynamic type of an object
@@ -1274,7 +1293,7 @@ abstract class AbstractCompilerVisitor
# Variables handling
- protected var variables: HashMap[Variable, RuntimeVariable] = new HashMap[Variable, RuntimeVariable]
+ protected var variables = new HashMap[Variable, RuntimeVariable]
# Return the local runtime_variable associated to a Nit local variable
fun variable(variable: Variable): RuntimeVariable
@@ -1353,6 +1372,18 @@ abstract class AbstractCompilerVisitor
return res
end
+ # Generate an integer value
+ fun bool_instance(value: Bool): RuntimeVariable
+ do
+ var res = self.new_var(self.get_class("Bool").mclass_type)
+ if value then
+ self.add("{res} = 1;")
+ else
+ self.add("{res} = 0;")
+ end
+ return res
+ end
+
# Generate a string value
fun string_instance(string: String): RuntimeVariable
do
@@ -1373,6 +1404,19 @@ abstract class AbstractCompilerVisitor
return res
end
+ fun value_instance(object: Object): RuntimeVariable
+ do
+ if object isa Int then
+ return int_instance(object)
+ else if object isa Bool then
+ return bool_instance(object)
+ else if object isa String then
+ return string_instance(object)
+ else
+ abort
+ end
+ end
+
# Generate an array value
fun array_instance(array: Array[RuntimeVariable], elttype: MType): RuntimeVariable is abstract
@@ -1813,6 +1857,7 @@ redef class MMethodDef
fun compile_inside_to_c(v: VISITOR, arguments: Array[RuntimeVariable]): nullable RuntimeVariable
do
var modelbuilder = v.compiler.modelbuilder
+ var val = constant_value
if modelbuilder.mpropdef2npropdef.has_key(self) then
var npropdef = modelbuilder.mpropdef2npropdef[self]
var oldnode = v.current_node
@@ -1827,6 +1872,8 @@ redef class MMethodDef
self.compile_parameter_check(v, arguments)
nclassdef.compile_to_c(v, self, arguments)
v.current_node = oldnode
+ else if val != null then
+ v.ret(v.value_instance(val))
else
abort
end
@@ -2356,8 +2403,7 @@ redef class AExpr
# Do not call this method directly, use `v.stmt` instead
private fun stmt(v: AbstractCompilerVisitor)
do
- var res = expr(v)
- if res != null then v.add("{res};")
+ expr(v)
end
end
@@ -2399,12 +2445,6 @@ redef class AVarExpr
end
redef class AVarAssignExpr
- redef fun stmt(v)
- do
- var variable = self.variable.as(not null)
- var i = v.expr(self.n_value, variable.declared_type)
- v.assign(v.variable(variable), i)
- end
redef fun expr(v)
do
var variable = self.variable.as(not null)
@@ -2430,11 +2470,7 @@ redef class ASelfExpr
redef fun expr(v) do return v.frame.arguments.first
end
-redef class AContinueExpr
- redef fun stmt(v) do v.add("goto CONTINUE_{v.escapemark_name(self.escapemark)};")
-end
-
-redef class ABreakExpr
+redef class AEscapeExpr
redef fun stmt(v) do v.add("goto BREAK_{v.escapemark_name(self.escapemark)};")
end
@@ -2497,10 +2533,7 @@ redef class ADoExpr
redef fun stmt(v)
do
v.stmt(self.n_block)
- var escapemark = self.escapemark
- if escapemark != null then
- v.add("BREAK_{v.escapemark_name(escapemark)}: (void)0;")
- end
+ v.add_escape_label(break_mark)
end
end
@@ -2511,9 +2544,9 @@ redef class AWhileExpr
var cond = v.expr_bool(self.n_expr)
v.add("if (!{cond}) break;")
v.stmt(self.n_block)
- v.add("CONTINUE_{v.escapemark_name(escapemark)}: (void)0;")
+ v.add_escape_label(continue_mark)
v.add("\}")
- v.add("BREAK_{v.escapemark_name(escapemark)}: (void)0;")
+ v.add_escape_label(break_mark)
end
end
@@ -2522,47 +2555,15 @@ redef class ALoopExpr
do
v.add("for(;;) \{")
v.stmt(self.n_block)
- v.add("CONTINUE_{v.escapemark_name(escapemark)}: (void)0;")
+ v.add_escape_label(continue_mark)
v.add("\}")
- v.add("BREAK_{v.escapemark_name(escapemark)}: (void)0;")
+ v.add_escape_label(break_mark)
end
end
redef class AForExpr
redef fun stmt(v)
do
- # Shortcut on explicit range
- # Avoid the instantiation of the range and the iterator
- var nexpr = self.n_expr
- if self.variables.length == 1 and nexpr isa ARangeExpr and not v.compiler.modelbuilder.toolcontext.opt_no_shortcut_range.value then
- var from = v.expr(nexpr.n_expr, null)
- var to = v.expr(nexpr.n_expr2, null)
- var variable = v.variable(variables.first)
- var one = v.new_expr("1", v.get_class("Int").mclass_type)
-
- v.assign(variable, from)
- v.add("for(;;) \{ /* shortcut range */")
-
- var ok
- if nexpr isa AOrangeExpr then
- ok = v.send(v.get_property("<", variable.mtype), [variable, to])
- else
- ok = v.send(v.get_property("<=", variable.mtype), [variable, to])
- end
- assert ok != null
- v.add("if(!{ok}) break;")
-
- v.stmt(self.n_block)
-
- v.add("CONTINUE_{v.escapemark_name(escapemark)}: (void)0;")
- var succ = v.send(v.get_property("successor", variable.mtype), [variable, one])
- assert succ != null
- v.assign(variable, succ)
- v.add("\}")
- v.add("BREAK_{v.escapemark_name(escapemark)}: (void)0;")
- return
- end
-
var cl = v.expr(self.n_expr, null)
var it_meth = self.method_iterator
assert it_meth != null
@@ -2595,12 +2596,18 @@ redef class AForExpr
abort
end
v.stmt(self.n_block)
- v.add("CONTINUE_{v.escapemark_name(escapemark)}: (void)0;")
+ v.add_escape_label(continue_mark)
var next_meth = self.method_next
assert next_meth != null
v.compile_callsite(next_meth, [it])
v.add("\}")
- v.add("BREAK_{v.escapemark_name(escapemark)}: (void)0;")
+ v.add_escape_label(break_mark)
+
+ var method_finish = self.method_finish
+ if method_finish != null then
+ # TODO: Find a way to call this also in long escape (e.g. return)
+ v.compile_callsite(method_finish, [it])
+ end
end
end
@@ -2741,7 +2748,7 @@ redef class ACrangeExpr
var i2 = v.expr(self.n_expr2, null)
var mtype = self.mtype.as(MClassType)
var res = v.init_instance(mtype)
- var it = v.compile_callsite(init_callsite.as(not null), [res, i1, i2])
+ v.compile_callsite(init_callsite.as(not null), [res, i1, i2])
return res
end
end
@@ -2753,7 +2760,7 @@ redef class AOrangeExpr
var i2 = v.expr(self.n_expr2, null)
var mtype = self.mtype.as(MClassType)
var res = v.init_instance(mtype)
- var it = v.compile_callsite(init_callsite.as(not null), [res, i1, i2])
+ v.compile_callsite(init_callsite.as(not null), [res, i1, i2])
return res
end
end
@@ -2833,11 +2840,9 @@ redef class ASendExpr
redef fun expr(v)
do
var recv = v.expr(self.n_expr, null)
- var args = [recv]
- for a in self.raw_arguments do
- args.add(v.expr(a, null))
- end
- return v.compile_callsite(self.callsite.as(not null), args)
+ var callsite = self.callsite.as(not null)
+ var args = v.varargize(callsite.mpropdef, recv, self.raw_arguments)
+ return v.compile_callsite(callsite, args)
end
end
@@ -2845,13 +2850,12 @@ redef class ASendReassignFormExpr
redef fun stmt(v)
do
var recv = v.expr(self.n_expr, null)
- var args = [recv]
- for a in self.raw_arguments do
- args.add(v.expr(a, null))
- end
+ var callsite = self.callsite.as(not null)
+ var args = v.varargize(callsite.mpropdef, recv, self.raw_arguments)
+
var value = v.expr(self.n_value, null)
- var left = v.compile_callsite(self.callsite.as(not null), args)
+ var left = v.compile_callsite(callsite, args)
assert left != null
var res = v.compile_callsite(self.reassign_callsite.as(not null), [left, value])
@@ -2866,14 +2870,12 @@ redef class ASuperExpr
redef fun expr(v)
do
var recv = v.frame.arguments.first
- var args = [recv]
- for a in self.n_args.n_exprs do
- args.add(v.expr(a, null))
- end
var callsite = self.callsite
if callsite != null then
- # Add additionnals arguments for the super init call
+ var args = v.varargize(callsite.mpropdef, recv, self.n_args.n_exprs)
+
+ # Add additional arguments for the super init call
if args.length == 1 then
for i in [0..callsite.msignature.arity[ do
args.add(v.frame.arguments[i+1])
@@ -2884,12 +2886,14 @@ redef class ASuperExpr
return res
end
+ var mpropdef = self.mpropdef.as(not null)
+ var args = v.varargize(mpropdef, recv, self.n_args.n_exprs)
if args.length == 1 then
args = v.frame.arguments
end
# stantard call-next-method
- return v.supercall(mpropdef.as(not null), recv.mtype.as(MClassType), args)
+ return v.supercall(mpropdef, recv.mtype.as(MClassType), args)
end
end
@@ -2912,11 +2916,10 @@ redef class ANewExpr
else
recv = v.new_expr("({ctype})0/*special!*/", mtype)
end
- var args = [recv]
- for a in self.n_args.n_exprs do
- args.add(v.expr(a, null))
- end
- var res2 = v.compile_callsite(self.callsite.as(not null), args)
+
+ var callsite = self.callsite.as(not null)
+ var args = v.varargize(callsite.mpropdef, recv, self.n_args.n_exprs)
+ var res2 = v.compile_callsite(callsite, args)
if res2 != null then
#self.debug("got {res2} from {mproperty}. drop {recv}")
return res2
@@ -2935,12 +2938,13 @@ redef class AAttrExpr
end
redef class AAttrAssignExpr
- redef fun stmt(v)
+ redef fun expr(v)
do
var recv = v.expr(self.n_expr, null)
var i = v.expr(self.n_value, null)
var mproperty = self.mproperty.as(not null)
v.write_attribute(mproperty, recv, i)
+ return i
end
end
@@ -3019,9 +3023,6 @@ end
# Create a tool context to handle options and paths
var toolcontext = new ToolContext
-var opt_mixins = new OptionArray("Additionals module to min-in", "-m")
-toolcontext.option_context.add_option(opt_mixins)
-
toolcontext.tooldescription = "Usage: nitg [OPTION]... file.nit...\nCompiles Nit programs."
# We do not add other options, so process them now!
@@ -3040,7 +3041,6 @@ end
# Here we load an process all modules passed on the command line
var mmodules = modelbuilder.parse(arguments)
-var mixins = modelbuilder.parse(opt_mixins.value)
if mmodules.is_empty then return
modelbuilder.run_phases
@@ -3048,8 +3048,5 @@ modelbuilder.run_phases
for mmodule in mmodules do
toolcontext.info("*** PROCESS {mmodule} ***", 1)
var ms = [mmodule]
- if not mixins.is_empty then
- ms.add_all mixins
- end
toolcontext.run_global_phases(ms)
end
diff --git a/src/compiler/android_annotations.nit b/src/compiler/android_annotations.nit
index a6fc4e2..cc24d6e 100644
--- a/src/compiler/android_annotations.nit
+++ b/src/compiler/android_annotations.nit
@@ -125,11 +125,9 @@ redef class AAnnotation
# revision number. If the working tree is dirty, it will append another field with "d" for dirty.
private fun as_version(modelbuilder: ModelBuilder): String
do
- var annotation_name = n_atid.n_id.text
var version_fields = new Array[Object]
var args = n_args
- var platform_name
if args.length < 1 then
modelbuilder.error(self, "Annotation error: \"{name}\" expects at least a single argument.")
return ""
diff --git a/src/compiler/coloring.nit b/src/compiler/coloring.nit
index ed9b466..e447080 100644
--- a/src/compiler/coloring.nit
+++ b/src/compiler/coloring.nit
@@ -279,8 +279,6 @@ class BucketsColorer[H: Object, E: Object]
private var colors = new HashMap[E, Int]
private var conflicts = new HashMap[E, Set[E]]
- init do end
-
# Start bucket coloring
fun colorize(buckets: Map[H, Set[E]]): Map[E, Int] do
compute_conflicts(buckets)
diff --git a/src/compiler/compiler_ffi.nit b/src/compiler/compiler_ffi.nit
index 37689d8..e9c740a 100644
--- a/src/compiler/compiler_ffi.nit
+++ b/src/compiler/compiler_ffi.nit
@@ -82,7 +82,7 @@ extern void nitni_global_ref_decr(void*);
return res
end
- private var compiled_callbacks: Array[NitniCallback] = new Array[NitniCallback]
+ private var compiled_callbacks = new Array[NitniCallback]
# Returns true if callbacks has yet to be generated and register it as being generated
private fun check_callback_compilation(cb: NitniCallback): Bool
@@ -98,7 +98,6 @@ redef class AMethPropdef
do
var mmodule = mpropdef.mclassdef.mmodule
var mainmodule = v.compiler.mainmodule
- var amainmodule = v.compiler.modelbuilder.mmodule2nmodule[mainmodule]
var amodule = v.compiler.modelbuilder.mmodule2nmodule[mmodule]
var mclass_type = mpropdef.mclassdef.bound_mtype
@@ -428,7 +427,6 @@ redef class MExplicitSuper
var mproperty = from.mproperty
assert mproperty isa MMethod
var mclass_type = from.mclassdef.mclass.mclass_type
- var mmodule = from.mclassdef.mmodule
# In nitni files, declare internal function as extern
var internal_csignature = mproperty.build_csignature(mclass_type, v.compiler.mainmodule, "___super", long_signature, internal_call_context)
diff --git a/src/compiler/global_compiler.nit b/src/compiler/global_compiler.nit
index 2196071..7652368 100644
--- a/src/compiler/global_compiler.nit
+++ b/src/compiler/global_compiler.nit
@@ -342,7 +342,7 @@ class GlobalCompilerVisitor
var valtype = value.mtype.as(MClassType)
var res = self.new_var(mtype)
- if compiler.runtime_type_analysis != null and not compiler.runtime_type_analysis.live_types.has(value.mtype.as(MClassType)) then
+ if not compiler.runtime_type_analysis.live_types.has(value.mtype.as(MClassType)) then
self.add("/*no boxing of {value.mtype}: {value.mtype} is not live! */")
self.add("PRINT_ERROR(\"Dead code executed!\\n\"); show_backtrace(1);")
return res
@@ -520,45 +520,21 @@ class GlobalCompilerVisitor
return recvtype
end
- # Subpart of old call function
- # Gets the receiver boxed and casted if necessary
- private fun get_recv(recvtype: MClassType, args: Array[RuntimeVariable]): RuntimeVariable
+ redef fun call(m, recvtype, args)
do
- return self.autoadapt(self.autobox(args.first, recvtype), recvtype)
- end
+ var recv_type = get_recvtype(m, recvtype, args)
+ var recv = self.autoadapt(self.autobox(args.first, recvtype), recvtype)
+ if m.is_extern then recv = unbox_extern(recv, recv_type)
+
+ args = args.to_a
+ args.first = recv
- # Finalizes a call to a method ´m´ on type ´recvtype´ with arguments ´args´
- private fun finalize_call(m: MMethodDef, recvtype: MClassType, args: Array[RuntimeVariable]): nullable RuntimeVariable
- do
assert args.length == m.msignature.arity + 1 else debug("Invalid arity for {m}. {args.length} arguments given.")
var rm = new CustomizedRuntimeFunction(m, recvtype)
return rm.call(self, args)
end
- redef fun call(m, recvtype, args)
- do
- var recv_type = get_recvtype(m, recvtype, args)
- var recv = get_recv(recv_type, args)
- if m.is_extern then recv = unbox_extern(recv, recv_type)
- var new_args = args.to_a
- self.varargize(m, m.msignature.as(not null), new_args)
- new_args.first = recv
- return finalize_call(m, recv_type, new_args)
- end
-
- # Does a call without encapsulating varargs into an array
- # Avoids multiple encapsulation when calling a super in a variadic function
- fun call_without_varargize(m: MMethodDef, recvtype: MClassType, args: Array[RuntimeVariable]): nullable RuntimeVariable
- do
- var recv_type = get_recvtype(m, recvtype, args)
- var recv = get_recv(recv_type, args)
- if m.is_extern then recv = unbox_extern(recv, recv_type)
- var new_args = args.to_a
- new_args.first = recv
- return finalize_call(m, recv_type, new_args)
- end
-
redef fun supercall(m: MMethodDef, recvtype: MClassType, args: Array[RuntimeVariable]): nullable RuntimeVariable
do
var types = self.collect_types(args.first)
@@ -580,7 +556,7 @@ class GlobalCompilerVisitor
return res
end
var propdef = m.lookup_next_definition(self.compiler.mainmodule, mclasstype)
- var res2 = self.call_without_varargize(propdef, mclasstype, args)
+ var res2 = self.call(propdef, mclasstype, args)
if res != null then self.assign(res, res2.as(not null))
return res
end
@@ -602,7 +578,7 @@ class GlobalCompilerVisitor
else
self.add("case {self.compiler.classid(t)}: /* test {t} */")
end
- var res2 = self.call_without_varargize(propdef, t, args)
+ var res2 = self.call(propdef, t, args)
if res != null then self.assign(res, res2.as(not null))
self.add "break;"
end
diff --git a/src/compiler/separate_compiler.nit b/src/compiler/separate_compiler.nit
index 8c400f9..3645f54 100644
--- a/src/compiler/separate_compiler.nit
+++ b/src/compiler/separate_compiler.nit
@@ -22,19 +22,19 @@ import rapid_type_analysis
# Add separate compiler specific options
redef class ToolContext
# --separate
- var opt_separate: OptionBool = new OptionBool("Use separate compilation", "--separate")
+ var opt_separate = new OptionBool("Use separate compilation", "--separate")
# --no-inline-intern
- var opt_no_inline_intern: OptionBool = new OptionBool("Do not inline call to intern methods", "--no-inline-intern")
+ var opt_no_inline_intern = new OptionBool("Do not inline call to intern methods", "--no-inline-intern")
# --no-union-attribute
- var opt_no_union_attribute: OptionBool = new OptionBool("Put primitive attibutes in a box instead of an union", "--no-union-attribute")
+ var opt_no_union_attribute = new OptionBool("Put primitive attibutes in a box instead of an union", "--no-union-attribute")
# --no-shortcut-equate
- var opt_no_shortcut_equate: OptionBool = new OptionBool("Always call == in a polymorphic way", "--no-shortcut-equal")
+ var opt_no_shortcut_equate = new OptionBool("Always call == in a polymorphic way", "--no-shortcut-equal")
# --inline-coloring-numbers
- var opt_inline_coloring_numbers: OptionBool = new OptionBool("Inline colors and ids (semi-global)", "--inline-coloring-numbers")
+ var opt_inline_coloring_numbers = new OptionBool("Inline colors and ids (semi-global)", "--inline-coloring-numbers")
# --inline-some-methods
- var opt_inline_some_methods: OptionBool = new OptionBool("Allow the separate compiler to inline some methods (semi-global)", "--inline-some-methods")
+ var opt_inline_some_methods = new OptionBool("Allow the separate compiler to inline some methods (semi-global)", "--inline-some-methods")
# --direct-call-monomorph
- var opt_direct_call_monomorph: OptionBool = new OptionBool("Allow the separate compiler to direct call monomorph sites (semi-global)", "--direct-call-monomorph")
+ var opt_direct_call_monomorph = new OptionBool("Allow the separate compiler to direct call monomorph sites (semi-global)", "--direct-call-monomorph")
# --skip-dead-methods
var opt_skip_dead_methods = new OptionBool("Do not compile dead methods (semi-global)", "--skip-dead-methods")
# --semi-global
@@ -42,7 +42,7 @@ redef class ToolContext
# --no-colo-dead-methods
var opt_colo_dead_methods = new OptionBool("Force colorization of dead methods", "--colo-dead-methods")
# --tables-metrics
- var opt_tables_metrics: OptionBool = new OptionBool("Enable static size measuring of tables used for vft, typing and resolution", "--tables-metrics")
+ var opt_tables_metrics = new OptionBool("Enable static size measuring of tables used for vft, typing and resolution", "--tables-metrics")
redef init
do
@@ -963,7 +963,6 @@ class SeparateCompilerVisitor
redef fun unbox_signature_extern(m, args)
do
var msignature = m.msignature.resolve_for(m.mclassdef.bound_mtype, m.mclassdef.bound_mtype, m.mclassdef.mmodule, true)
- var recv = args.first
if not m.mproperty.is_init and m.is_extern then
args.first = self.unbox_extern(args.first, m.mclassdef.mclass.mclass_type)
end
@@ -1063,14 +1062,12 @@ class SeparateCompilerVisitor
redef fun compile_callsite(callsite, args)
do
var rta = compiler.runtime_type_analysis
- var recv = args.first.mtype
var mmethod = callsite.mproperty
# TODO: Inlining of new-style constructors
if compiler.modelbuilder.toolcontext.opt_direct_call_monomorph.value and rta != null and not mmethod.is_root_init then
var tgs = rta.live_targets(callsite)
if tgs.length == 1 then
# DIRECT CALL
- self.varargize(mmethod.intro, mmethod.intro.msignature.as(not null), args)
var res0 = before_send(mmethod, args)
var res = call(tgs.first, tgs.first.mclassdef.bound_mtype, args)
if res0 != null then
@@ -1086,8 +1083,6 @@ class SeparateCompilerVisitor
end
redef fun send(mmethod, arguments)
do
- self.varargize(mmethod.intro, mmethod.intro.msignature.as(not null), arguments)
-
if arguments.first.mcasttype.ctype != "val*" then
# In order to shortcut the primitive, we need to find the most specific method
# Howverr, because of performance (no flattening), we always work on the realmainmodule
diff --git a/src/compiler/separate_erasure_compiler.nit b/src/compiler/separate_erasure_compiler.nit
index af3a43c..c23476d 100644
--- a/src/compiler/separate_erasure_compiler.nit
+++ b/src/compiler/separate_erasure_compiler.nit
@@ -20,11 +20,11 @@ intrude import separate_compiler
# Add separate erased compiler specific options
redef class ToolContext
# --erasure
- var opt_erasure: OptionBool = new OptionBool("Erase generic types", "--erasure")
+ var opt_erasure = new OptionBool("Erase generic types", "--erasure")
# --rta
var opt_rta = new OptionBool("Activate RTA (implicit with --global and --separate)", "--rta")
# --no-check-erasure-cast
- var opt_no_check_erasure_cast: OptionBool = new OptionBool("Disable implicit casts on unsafe return with erasure-typing policy (dangerous)", "--no-check-erasure-cast")
+ var opt_no_check_erasure_cast = new OptionBool("Disable implicit casts on unsafe return with erasure-typing policy (dangerous)", "--no-check-erasure-cast")
redef init
do
@@ -549,7 +549,6 @@ class SeparateErasureCompilerVisitor
end
var class_ptr
- var type_table
if value.mtype.ctype == "val*" then
class_ptr = "{value}->class->"
else
diff --git a/src/doc/doc_model.nit b/src/doc/doc_model.nit
index f13d69f..41386d2 100644
--- a/src/doc/doc_model.nit
+++ b/src/doc/doc_model.nit
@@ -190,12 +190,8 @@ redef class MGroup
redef fun tpl_namespace do
var tpl = new Template
- if mproject != null then
- tpl.add mproject.tpl_namespace
- else if parent != null then
- tpl.add parent.tpl_namespace
- end
- if mproject != null and mproject.root != self then
+ tpl.add mproject.tpl_namespace
+ if mproject.root != self then
tpl.add "::"
tpl.add tpl_link
end
diff --git a/src/doc/doc_templates.nit b/src/doc/doc_templates.nit
index 200e650..516b17e 100644
--- a/src/doc/doc_templates.nit
+++ b/src/doc/doc_templates.nit
@@ -240,7 +240,9 @@ end
# Comparator used to sort boxes by order
private class OrderComparator
- super Comparator[TplSidebarElt]
+ super Comparator
+
+ redef type COMPARED: TplSidebarElt
redef fun compare(a, b) do
if a.order < b.order then return -1
diff --git a/src/ffi/java.nit b/src/ffi/java.nit
index 7be54ce..49a880b 100644
--- a/src/ffi/java.nit
+++ b/src/ffi/java.nit
@@ -96,7 +96,6 @@ class JavaLanguage
var jni_signature_alt
var return_type
- var c_return_type
var params = new Array[String]
params.add "nit_ffi_jni_env"
params.add "java_class"
@@ -105,19 +104,16 @@ class JavaLanguage
if mproperty.is_init then
jni_signature_alt = mclass_type.jni_signature_alt
return_type = mclass_type
- c_return_type = mclass_type.cname
else
params.add "recv"
if signature.return_mtype != null then
var ret_mtype = signature.return_mtype
ret_mtype = ret_mtype.resolve_for(mclass_type, mclass_type, mmodule, true)
return_type = signature.return_mtype
- c_return_type = mclass_type.cname
jni_signature_alt = return_type.jni_signature_alt
else
jni_signature_alt = "Void"
return_type = null
- c_return_type = null
end
end
@@ -262,16 +258,15 @@ redef class AMethPropdef
end
end
- # Insert additionnal explicit calls to get the current `JNIEnv`
+ # Insert additional explicit calls to get the current `JNIEnv`
#
# This forces declaration of callbacks to Nit. The callbacks will be available in Java
# but will be used mainly by the FFI itself.
#
- # The developper can aso customize the JNIEnv used by the FFI by redefing `Sys::jni_env`.
+ # The developer can also customize the JNIEnv used by the FFI by redefining `Sys::jni_env`.
private fun insert_artificial_callbacks(toolcontext: ToolContext)
do
var fcc = foreign_callbacks
- assert fcc != null
var modelbuilder = toolcontext.modelbuilder
var mmodule = mpropdef.mclassdef.mmodule
@@ -450,7 +445,7 @@ redef class MType
# Type name in Java
#
# * Primitives common to both languages use their Java primitive type
- # * Nit extern Java classes are reprensented by their full Java type
+ # * Nit extern Java classes are represented by their full Java type
# * Other Nit objects are represented by `int` in Java. It holds the
# pointer to the underlying C structure.
# TODO create static Java types to store and hide the pointer
@@ -502,7 +497,6 @@ redef class MClassType
do
var ftype = mclass.ftype
if ftype isa ForeignJavaType then
- var ori_jni_type = jni_type
var jni_type = ftype.java_type.
replace('.', "/").replace(' ', "").replace('\n', "")
diff --git a/src/frontend/simple_misc_analysis.nit b/src/frontend/simple_misc_analysis.nit
index a50b45b..9e3775d 100644
--- a/src/frontend/simple_misc_analysis.nit
+++ b/src/frontend/simple_misc_analysis.nit
@@ -117,17 +117,7 @@ redef class AReturnExpr
end
end
-redef class AContinueExpr
- redef fun after_simple_misc(v)
- do
- var e = n_expr
- if e != null then
- e.warn_parentheses(v)
- end
- end
-end
-
-redef class ABreakExpr
+redef class AEscapeExpr
redef fun after_simple_misc(v)
do
var e = n_expr
diff --git a/src/highlight.nit b/src/highlight.nit
index 06075b4..fe5375c 100644
--- a/src/highlight.nit
+++ b/src/highlight.nit
@@ -52,7 +52,6 @@ class HighlightVisitor
do
var stack2 = new Array[HTMLTag]
var stack = new Array[Prod]
- var closes = new Array[Prod]
var line = 0
var c: nullable Token = first_token
var hv = new HighlightVisitor
@@ -932,4 +931,3 @@ redef class AExpr
return t.infobox(v)
end
end
-
diff --git a/src/interpreter/breakpoint.nit b/src/interpreter/breakpoint.nit
deleted file mode 100644
index ef04a3b..0000000
--- a/src/interpreter/breakpoint.nit
+++ /dev/null
@@ -1,60 +0,0 @@
-# This file is part of NIT ( http://www.nitlanguage.org ).
-#
-# Copyright 2013 Lucas Bajolet
-#
-# 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.
-
-# Classes and methods relative to the management of Breakpoints for the Debugger
-module breakpoint
-
-# Contains all the informations of a Breakpoint for the Debugger
-class Breakpoint
-
- # Line to break on
- var line: Int
-
- # File concerned by the breakpoint
- var file: String
-
- # Maximum times to break on self
- var max_breaks: Int
-
- init(line: Int, file: String)
- do
- self.line = line
- self.file = file
- self.max_breaks = -1
- end
-
- fun set_max_breaks(breaks: Int)
- do
- self.max_breaks = breaks
- end
-
- # When the breakpoint is encountered, the check-in function should be called
- fun check_in
- do
- if self.max_breaks > 0 then self.max_breaks -= 1
- end
-
- # Checks if the breakpoint is still valid (that is, if it has a remaining breaks number > 0 or == -1)
- fun is_valid: Bool
- do
- if max_breaks == 0 then
- return false
- else
- return true
- end
- end
-
-end
diff --git a/src/interpreter/debugger.nit b/src/interpreter/debugger.nit
index 586c04c..771d4a2 100644
--- a/src/interpreter/debugger.nit
+++ b/src/interpreter/debugger.nit
@@ -17,7 +17,6 @@
# Debugging of a nit program using the NaiveInterpreter
module debugger
-import breakpoint
intrude import naive_interpreter
import nitx
intrude import semantize::local_var_init
@@ -120,9 +119,9 @@ redef class ToolContext
end
# -d
- var opt_debugger_mode: OptionBool = new OptionBool("Launches the target program with the debugger attached to it", "-d")
+ var opt_debugger_mode = new OptionBool("Launches the target program with the debugger attached to it", "-d")
# -c
- var opt_debugger_autorun: OptionBool = new OptionBool("Launches the target program with the interpreter, such as when the program fails, the debugging prompt is summoned", "-c")
+ var opt_debugger_autorun = new OptionBool("Launches the target program with the interpreter, such as when the program fails, the debugging prompt is summoned", "-c")
redef init
do
@@ -167,6 +166,20 @@ redef class ModelBuilder
end
end
+# Contains all the informations of a Breakpoint for the Debugger
+class Breakpoint
+
+ # Line to break on
+ var line: Int
+
+ # File concerned by the breakpoint
+ var file: String
+
+ redef init do
+ if not file.has_suffix(".nit") then file += ".nit"
+ end
+end
+
# The class extending `NaiveInterpreter` by adding debugging methods
class Debugger
super NaiveInterpreter
@@ -257,19 +270,8 @@ class Debugger
end
# Same as a regular call but for a runtime injected module
- #
fun rt_call(mpropdef: MMethodDef, args: Array[Instance]): nullable Instance
do
- args = call_commons(mpropdef, args)
- return rt_call_without_varargs(mpropdef, args)
- end
-
- # Common code to call and this function
- #
- # Call only executes the variadic part, this avoids
- # double encapsulation of variadic parameters into an Array
- fun rt_call_without_varargs(mpropdef: MMethodDef, args: Array[Instance]): nullable Instance
- do
if self.modelbuilder.toolcontext.opt_discover_call_trace.value and not self.discover_call_trace.has(mpropdef) then
self.discover_call_trace.add mpropdef
self.debug("Discovered {mpropdef}")
@@ -324,7 +326,6 @@ class Debugger
var mmod = e.mmodule
if mmod != null then
self.mainmodule = mmod
- var local_classdefs = mmod.mclassdefs
var sys_type = mmod.sys_type
if sys_type == null then
print "Fatal error, cannot find Class Sys !\nAborting"
@@ -379,14 +380,6 @@ class Debugger
var breakpoint = find_breakpoint(curr_file, n.location.line_start)
if breakpoints.keys.has(curr_file) and breakpoint != null then
-
- breakpoint.check_in
-
- if not breakpoint.is_valid
- then
- remove_breakpoint(curr_file, n.location.line_start)
- end
-
n.debug("Execute stmt {n.to_s}")
while read_cmd do end
end
@@ -399,7 +392,6 @@ class Debugger
var identifiers_in_instruction = get_identifiers_in_current_instruction(n.location.text)
for i in identifiers_in_instruction do
- var variable = seek_variable(i, frame)
for j in self.traces do
if j.is_variable_traced_in_frame(i, frame) then
n.debug("Traced variable {i} used")
@@ -465,7 +457,7 @@ class Debugger
#
# Returns a boolean value, representing whether or not to
# continue reading commands from the console input
- fun process_debug_command(command:String): Bool
+ fun process_debug_command(command: String): Bool
do
# Step-out command
if command == "finish"
@@ -478,10 +470,17 @@ class Debugger
# Step-over command
else if command == "n" then
return step_over
+ # Shows help
+ else if command == "help" then
+ help
+ return true
# Opens a new NitIndex prompt on current model
else if command == "nitx" then
new NitIndex.with_infos(modelbuilder, self.mainmodule).prompt
return true
+ else if command == "bt" or command == "backtrack" then
+ print stack_trace
+ return true
# Continues execution until the end
else if command == "c" then
return continue_exec
@@ -503,41 +502,72 @@ class Debugger
print stack_trace
exit(0)
else
- var parts_of_command = command.split_with(' ')
+ var parts = command.split_with(' ')
+ var cname = parts.first
# Shows the value of a variable in the current frame
- if parts_of_command[0] == "p" or parts_of_command[0] == "print" then
- print_command(parts_of_command)
+ if cname == "p" or cname == "print" then
+ print_command(parts)
# Places a breakpoint on line x of file y
- else if parts_of_command[0] == "break" or parts_of_command[0] == "b"
- then
- process_place_break_fun(parts_of_command)
- # Places a temporary breakpoint on line x of file y
- else if parts_of_command[0] == "tbreak" and (parts_of_command.length == 2 or parts_of_command.length == 3)
- then
- process_place_tbreak_fun(parts_of_command)
+ else if cname == "break" or cname == "b" then
+ process_place_break_fun(parts)
# Removes a breakpoint on line x of file y
- else if parts_of_command[0] == "d" or parts_of_command[0] == "delete" then
- process_remove_break_fun(parts_of_command)
+ else if cname == "d" or cname == "delete" then
+ process_remove_break_fun(parts)
# Sets an alias for a variable
- else if parts_of_command.length == 3 and parts_of_command[1] == "as"
- then
- add_alias(parts_of_command[0], parts_of_command[2])
+ else if parts.length == 2 and parts[1] == "as" then
+ process_alias(parts)
# Modifies the value of a variable in the current frame
- else if parts_of_command.length >= 3 and parts_of_command[1] == "=" then
- process_mod_function(parts_of_command)
+ else if parts.length == 3 and parts[1] == "=" then
+ process_mod_function(parts)
# Traces the modifications on a variable
- else if parts_of_command.length >= 2 and parts_of_command[0] == "trace" then
- process_trace_command(parts_of_command)
+ else if cname == "trace" then
+ process_trace_command(parts)
# Untraces the modifications on a variable
- else if parts_of_command.length == 2 and parts_of_command[0] == "untrace" then
- process_untrace_command(parts_of_command)
+ else if cname == "untrace" then
+ process_untrace_command(parts)
else
- print "Unknown command \"{command}\""
+ bad_command(command)
end
end
return true
end
+ # Produces help for the commands of the debugger
+ fun help do
+ print ""
+ print "Help :"
+ print "-----------------------------------"
+ print ""
+ print "Variables"
+ print " * Modification: var_name = value (Warning: var_name must be primitive)"
+ print " * Alias: var_name as alias"
+ print ""
+ print "Printing"
+ print " * Variables: p(rint) var_name (Use * to print all local variables)"
+ print " * Collections: p(rint) var_name '[' start_index (.. end_index) ']'"
+ print ""
+ print "Breakpoints"
+ print " * File/line: b(reak) file_name line_number"
+ print " * Remove: d(elete) id"
+ print ""
+ print "Tracepoints"
+ print " * Variable: trace var_name break/print"
+ print " * Untrace variable: untrace var_name"
+ print ""
+ print "Flow control"
+ print " * Next instruction (same-level): n"
+ print " * Next instruction: s"
+ print " * Finish current method: finish"
+ print " * Continue until next breakpoint or end: c"
+ print ""
+ print "General commands"
+ print " * quit: Quits the debugger"
+ print " * abort: Aborts the interpretation, prints the stack trace before leaving"
+ print " * nitx: Ask questions to the model about its entities (classes, methods, etc.)"
+ print " * nit: Inject dynamic code for interpretation"
+ print ""
+ end
+
#######################################################################
## Processing specific command functions ##
#######################################################################
@@ -580,75 +610,96 @@ class Debugger
return false
end
+ fun bad_command(cmd: String) do
+ print "Unrecognized command {cmd}. Use 'help' to show help."
+ end
+
# Prints the demanded variable in the command
#
# The name of the variable in in position 1 of the array 'parts_of_command'
- fun print_command(parts_of_command: Array[String])
+ fun print_command(parts: Array[String])
do
- if parts_of_command[1] == "*" then
+ if parts.length != 2 then
+ bad_command(parts.join(" "))
+ return
+ end
+ if parts[1] == "*" then
var map_of_instances = frame.map
- var keys = map_of_instances.iterator
-
var self_var = seek_variable("self", frame)
print "self: {self_var.to_s}"
for instance in map_of_instances.keys do
print "{instance.to_s}: {map_of_instances[instance].to_s}"
end
- else if parts_of_command[1] == "stack" then
- print self.stack_trace
- else if parts_of_command[1].chars.has('[') and parts_of_command[1].chars.has(']') then
- process_array_command(parts_of_command)
+ else if parts[1].chars.has('[') and parts[1].chars.has(']') then
+ process_array_command(parts)
else
- var instance = seek_variable(get_real_variable_name(parts_of_command[1]), frame)
+ var instance = seek_variable(get_real_variable_name(parts[1]), frame)
if instance != null
then
print_instance(instance)
else
- print "Cannot find variable {parts_of_command[1]}"
+ print "Cannot find variable {parts[1]}"
end
end
end
+ # Process the input command to set an alias for a variable
+ fun process_alias(parts: Array[String]) do
+ if parts.length != 3 then
+ bad_command(parts.join(" "))
+ return
+ end
+ add_alias(parts.first, parts.last)
+ end
+
# Processes the input string to know where to put a breakpoint
- fun process_place_break_fun(parts_of_command: Array[String])
+ fun process_place_break_fun(parts: Array[String])
do
- var bp = get_breakpoint_from_command(parts_of_command)
+ if parts.length != 3 then
+ bad_command(parts.join(" "))
+ return
+ end
+ var bp = get_breakpoint_from_command(parts)
if bp != null then
place_breakpoint(bp)
end
end
# Returns a breakpoint containing the informations stored in the command
- fun get_breakpoint_from_command(parts_of_command: Array[String]): nullable Breakpoint
+ fun get_breakpoint_from_command(parts: Array[String]): nullable Breakpoint
do
- if parts_of_command[1].is_numeric then
- return new Breakpoint(parts_of_command[1].to_i, curr_file)
- else if parts_of_command.length >= 3 and parts_of_command[2].is_numeric then
- return new Breakpoint(parts_of_command[2].to_i, parts_of_command[1])
+ if parts[1].is_numeric then
+ return new Breakpoint(parts[1].to_i, curr_file)
+ else if parts.length >= 3 and parts[2].is_numeric then
+ return new Breakpoint(parts[2].to_i, parts[1])
else
return null
end
end
# Processes the command of removing a breakpoint on specified line and file
- fun process_remove_break_fun(parts_of_command: Array[String])
+ fun process_remove_break_fun(parts: Array[String])
do
- if parts_of_command[1].is_numeric then
- remove_breakpoint(self.curr_file, parts_of_command[1].to_i)
- else if parts_of_command.length >= 3 and parts_of_command[2].is_numeric then
- remove_breakpoint(parts_of_command[1], parts_of_command[2].to_i)
+ if parts.length != 2 then
+ bad_command(parts.join(" "))
+ return
+ end
+ if parts[1].is_numeric then
+ remove_breakpoint(self.curr_file, parts[1].to_i)
+ else if parts.length >= 3 and parts[2].is_numeric then
+ remove_breakpoint(parts[1], parts[2].to_i)
end
end
# Processes an array print command
- fun process_array_command(parts_of_command: Array[String])
+ fun process_array_command(parts: Array[String])
do
- var index_of_first_brace = parts_of_command[1].chars.index_of('[')
- var variable_name = get_real_variable_name(parts_of_command[1].substring(0,index_of_first_brace))
- var braces = parts_of_command[1].substring_from(index_of_first_brace)
+ var index_of_first_brace = parts[1].chars.index_of('[')
+ var variable_name = get_real_variable_name(parts[1].substring(0,index_of_first_brace))
+ var braces = parts[1].substring_from(index_of_first_brace)
var indexes = remove_braces(braces)
@@ -676,27 +727,32 @@ class Debugger
# Processes the modification function to modify a variable dynamically
#
# Command of type variable = value
- fun process_mod_function(parts_of_command: Array[String])
+ fun process_mod_function(parts: Array[String])
do
- parts_of_command[0] = get_real_variable_name(parts_of_command[0])
- var parts_of_variable = parts_of_command[0].split_with(".")
+ if parts.length != 3 then
+ bad_command(parts.join(" "))
+ return
+ end
+ var p0 = parts[0]
+ p0 = get_real_variable_name(p0)
+ var parts_of_variable = p0.split_with(".")
if parts_of_variable.length > 1 then
var last_part = parts_of_variable.pop
- var first_part = parts_of_command[0].substring(0,parts_of_command[0].length - last_part.length - 1)
+ var first_part = p0.substring(0,p0.length - last_part.length - 1)
var papa = seek_variable(first_part, frame)
if papa != null and papa isa MutableInstance then
var attribute = get_attribute_in_mutable_instance(papa, last_part)
if attribute != null then
- modify_argument_of_complex_type(papa, attribute, parts_of_command[2])
+ modify_argument_of_complex_type(papa, attribute, parts[2])
end
end
else
var target = seek_variable(parts_of_variable[0], frame)
if target != null then
- modify_in_frame(target, parts_of_command[2])
+ modify_in_frame(target, parts[2])
end
end
end
@@ -704,42 +760,46 @@ class Debugger
# Processes the untrace variable command
#
# Command pattern : "untrace variable"
- fun process_untrace_command(parts_of_command: Array[String])
+ fun process_untrace_command(parts: Array[String])
do
- var variable_name = get_real_variable_name(parts_of_command[1])
+ if parts.length != 2 then
+ bad_command(parts.join(" "))
+ return
+ end
+ var variable_name = get_real_variable_name(parts[1])
if untrace_variable(variable_name) then
- print "Untraced variable {parts_of_command[1]}"
+ print "Untraced variable {parts[1]}"
else
- print "{parts_of_command[1]} is not traced"
+ print "{parts[1]} is not traced"
end
end
# Processes the trace variable command
#
# Command pattern : "trace variable [break/print]"
- fun process_trace_command(parts_of_command: Array[String])
+ fun process_trace_command(parts: Array[String])
do
- var variable_name = get_real_variable_name(parts_of_command[1])
+ if parts.length != 3 then
+ bad_command(parts.join(" "))
+ return
+ end
+ var variable_name = get_real_variable_name(parts[1])
var breaker:Bool
if seek_variable(variable_name, frame) == null then
- print "Cannot find a variable called {parts_of_command[1]}"
+ print "Cannot find a variable called {parts[1]}"
return
end
- if parts_of_command.length == 3 then
- if parts_of_command[2] == "break" then
- breaker = true
- else
- breaker = false
- end
+ if parts[2] == "break" then
+ breaker = true
else
breaker = false
end
trace_variable(variable_name, breaker)
- print "Successfully tracing {parts_of_command[1]}"
+ print "Successfully tracing {parts[1]}"
end
#######################################################################
@@ -832,14 +892,12 @@ class Debugger
var trigger_char_escape = false
var trigger_string_escape = false
- var trigger_concat_in_string = false
for i in instruction.chars do
if trigger_char_escape then
if i == '\'' then trigger_char_escape = false
else if trigger_string_escape then
if i == '{' then
- trigger_concat_in_string = true
trigger_string_escape = false
else if i == '\"' then trigger_string_escape = false
else
@@ -857,7 +915,6 @@ class Debugger
else if i == '\"' then
trigger_string_escape = true
else if i == '}' then
- trigger_concat_in_string = false
trigger_string_escape = true
else
if instruction_buffer.length > 0 and not instruction_buffer.is_numeric and not (instruction_buffer.chars[0] >= 'A' and instruction_buffer.chars[0] <= 'Z') then result_array.push(instruction_buffer.to_s)
@@ -1084,8 +1141,6 @@ class Debugger
do
var collection_length_attribute = get_attribute_in_mutable_instance(collection, "length")
- var real_collection_length: nullable Int = null
-
if collection_length_attribute != null then
var primitive_length_instance = collection.attributes[collection_length_attribute]
if primitive_length_instance isa PrimitiveInstance[Int] then
@@ -1215,17 +1270,6 @@ class Debugger
end
end
- #Places a breakpoint that will trigger once and be destroyed afterwards
- fun process_place_tbreak_fun(parts_of_command: Array[String])
- do
- var bp = get_breakpoint_from_command(parts_of_command)
- if bp != null
- then
- bp.set_max_breaks(1)
- place_breakpoint(bp)
- end
- end
-
#######################################################################
## Breakpoint removing functions ##
#######################################################################
diff --git a/src/interpreter/naive_interpreter.nit b/src/interpreter/naive_interpreter.nit
index 1121ed0..e16f060 100644
--- a/src/interpreter/naive_interpreter.nit
+++ b/src/interpreter/naive_interpreter.nit
@@ -20,10 +20,11 @@ module naive_interpreter
import literal
import semantize
private import parser::tables
+import mixin
redef class ToolContext
# --discover-call-trace
- var opt_discover_call_trace: OptionBool = new OptionBool("Trace calls of the first invocation of a method", "--discover-call-trace")
+ var opt_discover_call_trace = new OptionBool("Trace calls of the first invocation of a method", "--discover-call-trace")
redef init
do
@@ -57,7 +58,7 @@ class NaiveInterpreter
# The modelbuilder that know the AST and its associations with the model
var modelbuilder: ModelBuilder
- # The main moduleof the program (used to lookup methoda
+ # The main module of the program (used to lookup method)
var mainmodule: MModule
# The command line arguments of the interpreted program
@@ -65,6 +66,7 @@ class NaiveInterpreter
# arguments[1] is the first argument
var arguments: Array[String]
+ # The main Sys instance
var mainobj: nullable Instance
init(modelbuilder: ModelBuilder, mainmodule: MModule, arguments: Array[String])
@@ -112,43 +114,26 @@ class NaiveInterpreter
# Set this mark to skip the evaluation until the end of the specified method frame
var returnmark: nullable Frame = null
- # Is a break executed?
- # Set this mark to skip the evaluation until a labeled statement catch it with `is_break`
- var breakmark: nullable EscapeMark = null
-
- # Is a continue executed?
- # Set this mark to skip the evaluation until a labeled statement catch it with `is_continue`
- var continuemark: nullable EscapeMark = null
+ # Is a break or a continue executed?
+ # Set this mark to skip the evaluation until a labeled statement catch it with `is_escape`
+ var escapemark: nullable EscapeMark = null
# Is a return or a break or a continue executed?
# Use this function to know if you must skip the evaluation of statements
- fun is_escaping: Bool do return returnmark != null or breakmark != null or continuemark != null
+ fun is_escaping: Bool do return returnmark != null or escapemark != null
# The value associated with the current return/break/continue, if any.
# Set the value when you set a escapemark.
# Read the value when you catch a mark or reach the end of a method
var escapevalue: nullable Instance = null
- # If there is a break and is associated with `escapemark`, then return true an clear the mark.
- # If there is no break or if `escapemark` is null then return false.
- # Use this function to catch a potential break.
- fun is_break(escapemark: nullable EscapeMark): Bool
- do
- if escapemark != null and self.breakmark == escapemark then
- self.breakmark = null
- return true
- else
- return false
- end
- end
-
- # If there is a continue and is associated with `escapemark`, then return true an clear the mark.
- # If there is no continue or if `escapemark` is null then return false.
- # Use this function to catch a potential continue.
- fun is_continue(escapemark: nullable EscapeMark): Bool
+ # If there is a break/continue and is associated with `escapemark`, then return true and clear the mark.
+ # If there is no break/continue or if `escapemark` is null then return false.
+ # Use this function to catch a potential break/continue.
+ fun is_escape(escapemark: nullable EscapeMark): Bool
do
- if escapemark != null and self.continuemark == escapemark then
- self.continuemark = null
+ if escapemark != null and self.escapemark == escapemark then
+ self.escapemark = null
return true
else
return false
@@ -225,13 +210,13 @@ class NaiveInterpreter
return new PrimitiveInstance[Float](ic.mclass_type, val)
end
- # The unique intance of the `true` value.
+ # The unique instance of the `true` value.
var true_instance: Instance
- # The unique intance of the `false` value.
+ # The unique instance of the `false` value.
var false_instance: Instance
- # The unique intance of the `null` value.
+ # The unique instance of the `null` value.
var null_instance: Instance
# Return a new array made of `values`.
@@ -247,6 +232,19 @@ class NaiveInterpreter
return res
end
+ fun value_instance(object: Object): Instance
+ do
+ if object isa Int then
+ return int_instance(object)
+ else if object isa Bool then
+ return bool_instance(object)
+ else if object isa String then
+ return string_instance(object)
+ else
+ abort
+ end
+ end
+
# Return a new native string initialized with `txt`
fun native_string_instance(txt: String): Instance
do
@@ -256,13 +254,22 @@ class NaiveInterpreter
return new PrimitiveInstance[Buffer](ic.mclass_type, val)
end
+ # Return a new String instance for `txt`
+ fun string_instance(txt: String): Instance
+ do
+ var nat = native_string_instance(txt)
+ var res = self.send(self.force_get_primitive_method("to_s_with_length", nat.mtype), [nat, self.int_instance(txt.length)])
+ assert res != null
+ return res
+ end
+
# The current frame used to store local variables of the current method executed
fun frame: Frame do return frames.first
# The stack of all frames. The first one is the current one.
- var frames: List[Frame] = new List[Frame]
+ var frames = new List[Frame]
- # Return a stack stace. One line per function
+ # Return a stack trace. One line per function
fun stack_trace: String
do
var b = new FlatBuffer
@@ -309,55 +316,58 @@ class NaiveInterpreter
f.map[v] = value
end
- # Store known method, used to trace methods as thez are reached
+ # Store known methods, used to trace methods as they are reached
var discover_call_trace: Set[MMethodDef] = new HashSet[MMethodDef]
- # Common code for calls to injected methods and normal methods
- fun call_commons(mpropdef: MMethodDef, args: Array[Instance]): Array[Instance]
+ # Evaluate `args` as expressions in the call of `mpropdef` on `recv`.
+ # This method is used to manage varargs in signatures and returns the real array
+ # of instances to use in the call.
+ # Return `null` if one of the evaluation of the arguments return null.
+ fun varargize(mpropdef: MMethodDef, recv: Instance, args: SequenceRead[AExpr]): nullable Array[Instance]
do
- var vararg_rank = mpropdef.msignature.vararg_rank
- if vararg_rank >= 0 then
- assert args.length >= mpropdef.msignature.arity + 1 # because of self
- var rawargs = args
- args = new Array[Instance]
+ var msignature = mpropdef.new_msignature or else mpropdef.msignature.as(not null)
+ var res = new Array[Instance]
+ res.add(recv)
- args.add(rawargs.first) # recv
+ if args.is_empty then return res
- for i in [0..vararg_rank[ do
- args.add(rawargs[i+1])
- end
-
- var vararg_lastrank = vararg_rank + rawargs.length-1-mpropdef.msignature.arity
- var vararg = new Array[Instance]
- for i in [vararg_rank..vararg_lastrank] do
- vararg.add(rawargs[i+1])
- end
- # FIXME: its it to late to determine the vararg type, this should have been done during a previous analysis
- var elttype = mpropdef.msignature.mparameters[vararg_rank].mtype.anchor_to(self.mainmodule, args.first.mtype.as(MClassType))
- args.add(self.array_instance(vararg, elttype))
+ var vararg_rank = msignature.vararg_rank
+ var vararg_len = args.length - msignature.arity
+ if vararg_len < 0 then vararg_len = 0
- for i in [vararg_lastrank+1..rawargs.length-1[ do
- args.add(rawargs[i+1])
+ for i in [0..msignature.arity[ do
+ if i == vararg_rank then
+ var ne = args[i]
+ if ne isa AVarargExpr then
+ var e = self.expr(ne.n_expr)
+ if e == null then return null
+ res.add(e)
+ continue
+ end
+ var vararg = new Array[Instance]
+ for j in [vararg_rank..vararg_rank+vararg_len] do
+ var e = self.expr(args[j])
+ if e == null then return null
+ vararg.add(e)
+ end
+ var elttype = msignature.mparameters[vararg_rank].mtype.anchor_to(self.mainmodule, recv.mtype.as(MClassType))
+ res.add(self.array_instance(vararg, elttype))
+ else
+ var j = i
+ if i > vararg_rank then j += vararg_len
+ var e = self.expr(args[j])
+ if e == null then return null
+ res.add(e)
end
end
- return args
+ return res
end
# Execute `mpropdef` for a `args` (where `args[0]` is the receiver).
- # Return a falue if `mpropdef` is a function, or null if it is a procedure.
- # The call is direct/static. There is no message-seding/late-binding.
+ # Return a value if `mpropdef` is a function, or null if it is a procedure.
+ # The call is direct/static. There is no message-sending/late-binding.
fun call(mpropdef: MMethodDef, args: Array[Instance]): nullable Instance
do
- args = call_commons(mpropdef, args)
- return call_without_varargs(mpropdef, args)
- end
-
- # Common code to call and this function
- #
- # Call only executes the variadic part, this avoids
- # double encapsulation of variadic parameters into an Array
- fun call_without_varargs(mpropdef: MMethodDef, args: Array[Instance]): nullable Instance
- do
if self.modelbuilder.toolcontext.opt_discover_call_trace.value and not self.discover_call_trace.has(mpropdef) then
self.discover_call_trace.add mpropdef
self.debug("Discovered {mpropdef}")
@@ -366,6 +376,7 @@ class NaiveInterpreter
# Look for the AST node that implements the property
var mproperty = mpropdef.mproperty
+ var val = mpropdef.constant_value
if self.modelbuilder.mpropdef2npropdef.has_key(mpropdef) then
var npropdef = self.modelbuilder.mpropdef2npropdef[mpropdef]
self.parameter_check(npropdef, mpropdef, args)
@@ -374,6 +385,8 @@ class NaiveInterpreter
var nclassdef = self.modelbuilder.mclassdef2nclassdef[mpropdef.mclassdef]
self.parameter_check(nclassdef, mpropdef, args)
return nclassdef.call(self, mpropdef, args)
+ else if val != null then
+ return value_instance(val)
else
fatal("Fatal Error: method {mpropdef} not found in the AST")
abort
@@ -418,7 +431,7 @@ class NaiveInterpreter
end
# Execute a full `callsite` for given `args`
- # Use this method, instead of `send` to execute and control the aditionnal behavior of the call-sites
+ # Use this method, instead of `send` to execute and control the additional behavior of the call-sites
fun callsite(callsite: nullable CallSite, arguments: Array[Instance]): nullable Instance
do
var initializers = callsite.mpropdef.initializers
@@ -447,8 +460,8 @@ class NaiveInterpreter
end
# Execute `mproperty` for a `args` (where `args[0]` is the receiver).
- # Return a falue if `mproperty` is a function, or null if it is a procedure.
- # The call is polimotphic. There is a message-seding/late-bindng according to te receiver (args[0]).
+ # Return a value if `mproperty` is a function, or null if it is a procedure.
+ # The call is polymorphic. There is a message-sending/late-binding according to the receiver (args[0]).
fun send(mproperty: MMethod, args: Array[Instance]): nullable Instance
do
var recv = args.first
@@ -495,6 +508,7 @@ class NaiveInterpreter
var cds = mtype.collect_mclassdefs(self.mainmodule).to_a
self.mainmodule.linearize_mclassdefs(cds)
for cd in cds do
+ if not self.modelbuilder.mclassdef2nclassdef.has_key(cd) then continue
var n = self.modelbuilder.mclassdef2nclassdef[cd]
for npropdef in n.n_propdefs do
if npropdef isa AAttrPropdef then
@@ -507,7 +521,7 @@ class NaiveInterpreter
return res
end
- var collect_attr_propdef_cache = new HashMap[MType, Array[AAttrPropdef]]
+ private var collect_attr_propdef_cache = new HashMap[MType, Array[AAttrPropdef]]
# Fill the initial values of the newly created instance `recv`.
# `recv.mtype` is used to know what must be filled.
@@ -694,7 +708,7 @@ redef class AMethPropdef
if auto_super_call then
# standard call-next-method
var superpd = mpropdef.lookup_next_definition(v.mainmodule, arguments.first.mtype)
- v.call_without_varargs(superpd, arguments)
+ v.call(superpd, arguments)
end
if mpropdef.is_intern or mpropdef.is_extern then
@@ -743,14 +757,14 @@ redef class AMethPropdef
var txt = recv.mtype.to_s
return v.native_string_instance(txt)
else if pname == "==" then
- # == is correclt redefined for instances
+ # == is correctly redefined for instances
return v.bool_instance(args[0] == args[1])
else if pname == "!=" then
return v.bool_instance(args[0] != args[1])
else if pname == "is_same_type" then
return v.bool_instance(args[0].mtype == args[1].mtype)
else if pname == "is_same_instance" then
- return v.bool_instance(args[1] != null and args[0].eq_is(args[1]))
+ return v.bool_instance(args[0].eq_is(args[1]))
else if pname == "exit" then
exit(args[1].to_i)
abort
@@ -797,6 +811,8 @@ redef class AMethPropdef
return v.int_instance(args[0].to_i.bin_or(args[1].to_i))
else if pname == "bin_xor" then
return v.int_instance(args[0].to_i.bin_xor(args[1].to_i))
+ else if pname == "bin_not" then
+ return v.int_instance(args[0].to_i.bin_not)
else if pname == "native_int_to_s" then
return v.native_string_instance(recvval.to_s)
else if pname == "strerror_ext" then
@@ -1097,7 +1113,7 @@ redef class AClassdef
if not mpropdef.is_intro then
# standard call-next-method
var superpd = mpropdef.lookup_next_definition(v.mainmodule, args.first.mtype)
- v.call_without_varargs(superpd, args)
+ v.call(superpd, args)
end
return null
else
@@ -1197,7 +1213,7 @@ redef class ASelfExpr
end
end
-redef class AContinueExpr
+redef class AEscapeExpr
redef fun stmt(v)
do
var ne = self.n_expr
@@ -1206,20 +1222,7 @@ redef class AContinueExpr
if i == null then return
v.escapevalue = i
end
- v.continuemark = self.escapemark
- end
-end
-
-redef class ABreakExpr
- redef fun stmt(v)
- do
- var ne = self.n_expr
- if ne != null then
- var i = v.expr(ne)
- if i == null then return
- v.escapevalue = i
- end
- v.breakmark = self.escapemark
+ v.escapemark = self.escapemark
end
end
@@ -1285,7 +1288,7 @@ redef class ADoExpr
redef fun stmt(v)
do
v.stmt(self.n_block)
- v.is_break(self.escapemark) # Clear the break (if any)
+ v.is_escape(self.break_mark) # Clear the break (if any)
end
end
@@ -1297,8 +1300,8 @@ redef class AWhileExpr
if cond == null then return
if not cond.is_true then return
v.stmt(self.n_block)
- if v.is_break(self.escapemark) then return
- v.is_continue(self.escapemark) # Clear the break
+ if v.is_escape(self.break_mark) then return
+ v.is_escape(self.continue_mark) # Clear the break
if v.is_escaping then return
end
end
@@ -1309,8 +1312,8 @@ redef class ALoopExpr
do
loop
v.stmt(self.n_block)
- if v.is_break(self.escapemark) then return
- v.is_continue(self.escapemark) # Clear the break
+ if v.is_escape(self.break_mark) then return
+ v.is_escape(self.continue_mark) # Clear the break
if v.is_escaping then return
end
end
@@ -1328,7 +1331,7 @@ redef class AForExpr
#self.debug("iter {iter}")
loop
var isok = v.callsite(method_is_ok, [iter]).as(not null)
- if not isok.is_true then return
+ if not isok.is_true then break
if self.variables.length == 1 then
var item = v.callsite(method_item, [iter]).as(not null)
#self.debug("item {item}")
@@ -1342,11 +1345,15 @@ redef class AForExpr
abort
end
v.stmt(self.n_block)
- if v.is_break(self.escapemark) then return
- v.is_continue(self.escapemark) # Clear the break
- if v.is_escaping then return
+ if v.is_escape(self.break_mark) then break
+ v.is_escape(self.continue_mark) # Clear the break
+ if v.is_escaping then break
v.callsite(method_next, [iter])
end
+ var method_finish = self.method_finish
+ if method_finish != null then
+ v.callsite(method_finish, [iter])
+ end
end
end
@@ -1458,9 +1465,7 @@ redef class AStringFormExpr
redef fun expr(v)
do
var txt = self.value.as(not null)
- var nat = v.native_string_instance(txt)
- var res = v.send(v.force_get_primitive_method("to_s", nat.mtype), [nat]).as(not null)
- return res
+ return v.string_instance(txt)
end
end
@@ -1560,7 +1565,6 @@ redef class AAsNotnullExpr
do
var i = v.expr(self.n_expr)
if i == null then return null
- var mtype = v.unanchor_type(self.mtype.as(not null))
if i.mtype isa MNullType then
fatal(v, "Cast failed")
end
@@ -1594,12 +1598,8 @@ redef class ASendExpr
do
var recv = v.expr(self.n_expr)
if recv == null then return null
- var args = [recv]
- for a in self.raw_arguments do
- var i = v.expr(a)
- if i == null then return null
- args.add(i)
- end
+ var args = v.varargize(callsite.mpropdef, recv, self.raw_arguments)
+ if args == null then return null
var res = v.callsite(callsite, args)
return res
@@ -1611,12 +1611,8 @@ redef class ASendReassignFormExpr
do
var recv = v.expr(self.n_expr)
if recv == null then return
- var args = [recv]
- for a in self.raw_arguments do
- var i = v.expr(a)
- if i == null then return
- args.add(i)
- end
+ var args = v.varargize(callsite.mpropdef, recv, self.raw_arguments)
+ if args == null then return
var value = v.expr(self.n_value)
if value == null then return
@@ -1636,16 +1632,12 @@ redef class ASuperExpr
redef fun expr(v)
do
var recv = v.frame.arguments.first
- var args = [recv]
- for a in self.n_args.n_exprs do
- var i = v.expr(a)
- if i == null then return null
- args.add(i)
- end
var callsite = self.callsite
if callsite != null then
- # Add additionnals arguments for the super init call
+ var args = v.varargize(callsite.mpropdef, recv, self.n_args.n_exprs)
+ if args == null then return null
+ # Add additional arguments for the super init call
if args.length == 1 then
for i in [0..callsite.msignature.arity[ do
args.add(v.frame.arguments[i+1])
@@ -1656,14 +1648,17 @@ redef class ASuperExpr
return res
end
+ # standard call-next-method
+ var mpropdef = self.mpropdef
+ mpropdef = mpropdef.lookup_next_definition(v.mainmodule, recv.mtype)
+
+ var args = v.varargize(mpropdef, recv, self.n_args.n_exprs)
+ if args == null then return null
+
if args.length == 1 then
args = v.frame.arguments
end
-
- # stantard call-next-method
- var mpropdef = self.mpropdef
- mpropdef = mpropdef.lookup_next_definition(v.mainmodule, recv.mtype)
- var res = v.call_without_varargs(mpropdef, args)
+ var res = v.call(mpropdef, args)
return res
end
end
@@ -1674,12 +1669,8 @@ redef class ANewExpr
var mtype = v.unanchor_type(self.mtype.as(not null))
var recv: Instance = new MutableInstance(mtype)
v.init_instance(recv)
- var args = [recv]
- for a in self.n_args.n_exprs do
- var i = v.expr(a)
- if i == null then return null
- args.add(i)
- end
+ var args = v.varargize(callsite.mpropdef, recv, self.n_args.n_exprs)
+ if args == null then return null
var res2 = v.callsite(callsite, args)
if res2 != null then
#self.debug("got {res2} from {mproperty}. drop {recv}")
diff --git a/src/metrics/tables_metrics.nit b/src/metrics/tables_metrics.nit
index 664415a..eac5853 100644
--- a/src/metrics/tables_metrics.nit
+++ b/src/metrics/tables_metrics.nit
@@ -35,8 +35,6 @@ end
# Print class tables metrics for the classes of the program main
fun compute_tables_metrics(main: MModule)
do
- var model = main.model
-
var nc = 0 # Number of runtime classes
var nl = 0 # Number of usages of class definitions (a class definition can be used more than once)
var nhp = 0 # Number of usages of properties (a property can be used more than once)
diff --git a/src/mixin.nit b/src/mixin.nit
new file mode 100644
index 0000000..94d0c32
--- /dev/null
+++ b/src/mixin.nit
@@ -0,0 +1,110 @@
+# 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.
+
+# Loading and additional module refinements at link-time.
+#
+# Used to factorize some code used by the engines.
+module mixin
+
+import modelbuilder
+
+redef class ToolContext
+ # --mixin
+ var opt_mixins = new OptionArray("Additionals module to min-in", "-m", "--mixin")
+ # --define
+ var opt_defines = new OptionArray("Define a specific property", "-D", "--define")
+
+ redef init
+ do
+ super
+ option_context.add_option(opt_mixins, opt_defines)
+ end
+
+ redef fun make_main_module(mmodules)
+ do
+ var mixins = opt_mixins.value
+ if not mixins.is_empty then
+ mmodules.add_all modelbuilder.parse(opt_mixins.value)
+ modelbuilder.run_phases
+ end
+
+ var mainmodule = super
+
+ var defines = opt_defines.value
+ if not defines.is_empty then
+ var location = mainmodule.location
+ var model = mainmodule.model
+
+ if mainmodule == mmodules.first then
+ mainmodule = new MModule(model, null, mainmodule.name + "-d", location)
+ mainmodule.set_imported_mmodules(mmodules)
+ mainmodule.is_fictive = true
+ end
+
+ var recv = mainmodule.object_type
+ var mclassdef = new MClassDef(mainmodule, recv, location)
+ mclassdef.add_in_hierarchy
+
+ for define in defines do
+ var spl = define.split_once_on('=')
+ var name = spl.first
+ var val = null
+ if spl.length > 1 then val = spl[1]
+ var prop = mainmodule.try_get_primitive_method(name, recv.mclass)
+ if prop == null then
+ error(null, "Error: --define: no top-level function `{name}`")
+ continue
+ end
+ var ret = prop.intro.msignature.return_mtype
+ var v
+ if ret == null then
+ error(null, "Error: --define: Method `{prop}` is not a function")
+ continue
+ else if ret.to_s == "Bool" then
+ if val == null or val == "true" then
+ v = true
+ else if val == "false" then
+ v = false
+ else
+ error(null, "Error: --define: Method `{prop}` need a Bool.")
+ continue
+ end
+ else if ret.to_s == "Int" then
+ if val != null and val.is_numeric then
+ v = val.to_i
+ else
+ error(null, "Error: --define: Method `{prop}` need a Int.")
+ continue
+ end
+ else if ret.to_s == "String" then
+ if val != null then
+ v = val
+ else
+ error(null, "Error: --define: Method `{prop}` need a String.")
+ continue
+ end
+ else
+ error(null, "Error: --define: Method `{prop}` return an unmanaged type {ret}.")
+ continue
+ end
+ var pd = new MMethodDef(mclassdef, prop, location)
+ pd.msignature = prop.intro.msignature
+ pd.constant_value = v
+ end
+ check_errors
+ end
+
+ return mainmodule
+ end
+end
diff --git a/src/model/model.nit b/src/model/model.nit
index f989302..64e82c7 100644
--- a/src/model/model.nit
+++ b/src/model/model.nit
@@ -293,7 +293,8 @@ redef class MModule
end
private class MClassDefSorter
- super AbstractSorter[MClassDef]
+ super Comparator
+ redef type COMPARED: MClassDef
var mmodule: MModule
redef fun compare(a, b)
do
@@ -305,7 +306,8 @@ private class MClassDefSorter
end
private class MPropDefSorter
- super AbstractSorter[MPropDef]
+ super Comparator
+ redef type COMPARED: MPropDef
var mmodule: MModule
redef fun compare(pa, pb)
do
@@ -1224,7 +1226,6 @@ class MVirtualType
if is_fixed(mmodule, resolved_reciever) then return res
# If the resolved type isa intern class, then there is no possible valid redefinition in any potential subclass. self is just fixed. so simply return the resolution
if res isa MClassType and res.mclass.kind == enum_kind then return res
- # TODO: Add 'fixed' virtual type in the specification.
# TODO: What if bound to a MParameterType?
# Note that Nullable types can always be redefined by the non nullable version, so there is no specific case on it.
@@ -1273,7 +1274,6 @@ end
#
# Note that parameter types are shared among class refinements.
# Therefore parameter only have an internal name (see `to_s` for details).
-# TODO: Add a `name_for` to get better messages.
class MParameterType
super MType
@@ -1975,6 +1975,16 @@ class MMethodDef
# Is the method definition extern?
var is_extern = false is writable
+
+ # An optional constant value returned in functions.
+ #
+ # Only some specific primitife value are accepted by engines.
+ # Is used when there is no better implementation available.
+ #
+ # Currently used only for the implementation of the `--define`
+ # command-line option.
+ # SEE: module `mixin`.
+ var constant_value: nullable Object = null is writable
end
# A local definition of an attribute
diff --git a/src/model/model_viz.nit b/src/model/model_viz.nit
index bc324b7..03ca3eb 100644
--- a/src/model/model_viz.nit
+++ b/src/model/model_viz.nit
@@ -62,16 +62,19 @@ end
# Compare modules and groups using the
# FIXME do not use Object, but a better common interface of MModule and MGroup
private class LinexComparator
- super Comparator[Object]
+ super Comparator
+
+ redef type COMPARED: Object
+
var mins = new HashMap [MGroup, nullable MModule]
var maxs = new HashMap [MGroup, nullable MModule]
- fun min(o: Object): nullable MModule do
+ fun mini(o: Object): nullable MModule do
if o isa MModule then return o
assert o isa MGroup
if not mins.has_key(o) then computeminmax(o)
return mins[o]
end
- fun max(o: Object): nullable MModule do
+ fun maxi(o: Object): nullable MModule do
if o isa MModule then return o
assert o isa MGroup
if not maxs.has_key(o) then computeminmax(o)
@@ -84,14 +87,14 @@ private class LinexComparator
return
end
var subs = tree.sub[o]
- var minres = min(subs.first)
- var maxres = max(subs.first)
+ var minres = mini(subs.first)
+ var maxres = maxi(subs.first)
var order = minres.model.mmodule_importation_hierarchy
for o2 in subs do
- var c = min(o2)
+ var c = mini(o2)
if c == null then continue
if minres == null or order.compare(minres, c) > 0 then minres = c
- c = max(o2)
+ c = maxi(o2)
if c == null then continue
if maxres == null or order.compare(maxres, c) < 0 then maxres = c
end
@@ -100,8 +103,8 @@ private class LinexComparator
#if minres != maxres then print "* {o} {minres}..{maxres}"
end
redef fun compare(a,b) do
- var ma = min(a)
- var mb = min(b)
+ var ma = mini(a)
+ var mb = mini(b)
if ma == null then
if mb == null then return 0 else return -1
else if mb == null then
diff --git a/src/model_utils.nit b/src/model_utils.nit
index ff1a8d9..9297793 100644
--- a/src/model_utils.nit
+++ b/src/model_utils.nit
@@ -525,9 +525,9 @@ end
# Sort mentities by their name
class MEntityNameSorter
- super AbstractSorter[MEntity]
+ super Comparator
+ redef type COMPARED: MEntity
redef fun compare(a, b) do return a.name <=> b.name
- init do end
end
# Sort MConcerns based on the module importation hierarchy ranking
@@ -540,9 +540,8 @@ end
# If both `a` and `b` have the same ranking,
# ordering is based on lexicographic comparison of `a.name` and `b.name`
class MConcernRankSorter
- super AbstractSorter[MConcern]
-
- init do end
+ super Comparator
+ redef type COMPARED: MConcern
redef fun compare(a, b) do
if a.concern_rank == b.concern_rank then
diff --git a/src/modelbuilder.nit b/src/modelbuilder.nit
index d702369..30a0617 100644
--- a/src/modelbuilder.nit
+++ b/src/modelbuilder.nit
@@ -53,8 +53,8 @@ redef class ToolContext
private var modelbuilder_real: nullable ModelBuilder = null
- # Run `process_mainmodule` on all phases
- fun run_global_phases(mmodules: Array[MModule])
+ # Combine module to make a single one if required.
+ fun make_main_module(mmodules: Array[MModule]): MModule
do
assert not mmodules.is_empty
var mainmodule
@@ -62,10 +62,17 @@ redef class ToolContext
mainmodule = mmodules.first
else
# We need a main module, so we build it by importing all modules
- mainmodule = new MModule(modelbuilder.model, null, mmodules.first.name, new Location(mmodules.first.location.file, 0, 0, 0, 0))
+ mainmodule = new MModule(modelbuilder.model, null, mmodules.first.name + "-m", new Location(mmodules.first.location.file, 0, 0, 0, 0))
mainmodule.is_fictive = true
mainmodule.set_imported_mmodules(mmodules)
end
+ return mainmodule
+ end
+
+ # Run `process_mainmodule` on all phases
+ fun run_global_phases(mmodules: Array[MModule])
+ do
+ var mainmodule = make_main_module(mmodules)
for phase in phases_list do
if phase.disabled then continue
phase.process_mainmodule(mainmodule, mmodules)
@@ -738,11 +745,13 @@ class ModelBuilder
end
# Force to get the primitive method named `name` on the type `recv` or do a fatal error on `n`
- fun force_get_primitive_method(n: ANode, name: String, recv: MClass, mmodule: MModule): MMethod
+ fun force_get_primitive_method(n: nullable ANode, name: String, recv: MClass, mmodule: MModule): MMethod
do
var res = mmodule.try_get_primitive_method(name, recv)
if res == null then
- self.toolcontext.fatal_error(n.hot_location, "Fatal Error: {recv} must have a property named {name}.")
+ var l = null
+ if n != null then l = n.hot_location
+ self.toolcontext.fatal_error(l, "Fatal Error: {recv} must have a property named {name}.")
abort
end
return res
diff --git a/src/modelize/modelize_class.nit b/src/modelize/modelize_class.nit
index 2a5e9fb..441a6c2 100644
--- a/src/modelize/modelize_class.nit
+++ b/src/modelize/modelize_class.nit
@@ -258,7 +258,6 @@ redef class ModelBuilder
private fun check_supertypes(nmodule: AModule, nclassdef: AClassdef)
do
var mmodule = nmodule.mmodule.as(not null)
- var objectclass = try_get_mclass_by_name(nmodule, mmodule, "Object")
var mclass = nclassdef.mclass.as(not null)
var mclassdef = nclassdef.mclassdef.as(not null)
@@ -410,7 +409,7 @@ redef class ModelBuilder
# Register the nclassdef associated to each mclassdef
# FIXME: why not refine the `MClassDef` class with a nullable attribute?
- var mclassdef2nclassdef: HashMap[MClassDef, AClassdef] = new HashMap[MClassDef, AClassdef]
+ var mclassdef2nclassdef = new HashMap[MClassDef, AClassdef]
# Return the static type associated to the node `ntype`.
# `mmodule` and `mclassdef` is the context where the call is made (used to understand formal types)
diff --git a/src/modelize/modelize_property.nit b/src/modelize/modelize_property.nit
index 74e4932..6a34e2e 100644
--- a/src/modelize/modelize_property.nit
+++ b/src/modelize/modelize_property.nit
@@ -38,7 +38,7 @@ end
redef class ModelBuilder
# Register the npropdef associated to each mpropdef
# FIXME: why not refine the `MPropDef` class with a nullable attribute?
- var mpropdef2npropdef: HashMap[MPropDef, APropdef] = new HashMap[MPropDef, APropdef]
+ var mpropdef2npropdef = new HashMap[MPropDef, APropdef]
# Build the properties of `nclassdef`.
# REQUIRE: all superclasses are built.
@@ -202,6 +202,7 @@ redef class ModelBuilder
# Can we just inherit?
if spropdefs.length == 1 and mparameters.is_empty and defined_init == null then
self.toolcontext.info("{mclassdef} inherits the basic constructor {longest}", 3)
+ mclassdef.mclass.root_init = longest
return
end
@@ -217,6 +218,7 @@ redef class ModelBuilder
var msignature = new MSignature(mparameters, null)
defined_init.new_msignature = msignature
self.toolcontext.info("{mclassdef} extends its basic constructor signature to {defined_init}{msignature}", 3)
+ mclassdef.mclass.root_init = defined_init
return
end
@@ -230,6 +232,7 @@ redef class ModelBuilder
mpropdef.msignature = new MSignature(new Array[MParameter], null) # always an empty real signature
nclassdef.mfree_init = mpropdef
self.toolcontext.info("{mclassdef} gets a free constructor for attributes {mpropdef}{msignature}", 3)
+ mclassdef.mclass.root_init = mpropdef
end
# Check the visibility of `mtype` as an element of the signature of `mpropdef`.
@@ -241,7 +244,7 @@ redef class ModelBuilder
# Extract visibility information of the main part of `mtype`
# It is a case-by case
var vis_type: nullable MVisibility = null # The own visibility of the type
- var mmodule_type: nullable MModule = null # The origial module of the type
+ var mmodule_type: nullable MModule = null # The original module of the type
mtype = mtype.as_notnullable
if mtype isa MClassType then
vis_type = mtype.mclass.visibility
@@ -288,12 +291,21 @@ redef class MPropDef
end
redef class AClassdef
- var build_properties_is_done: Bool = false
+ var build_properties_is_done = false
# The free init (implicitely constructed by the class if required)
var mfree_init: nullable MMethodDef = null
end
+redef class MClass
+ # The base init of the class.
+ # Used to get the common new_msignature and initializers
+ #
+ # TODO: Where to put this information is not clear because unlike other
+ # informations, the initialisers are stable in a same class.
+ var root_init: nullable MMethodDef = null
+end
+
redef class MClassDef
# What is the `APropdef` associated to a `MProperty`?
# Used to check multiple definition of a property.
@@ -440,7 +452,7 @@ redef class ASignature
var ntype = self.n_type
if ntype != null then
self.ret_type = modelbuilder.resolve_mtype(mmodule, mclassdef, ntype)
- if self.ret_type == null then return false # Skip errir
+ if self.ret_type == null then return false # Skip error
end
self.is_visited = true
@@ -582,6 +594,16 @@ redef class AMethPropdef
var mmodule = mclassdef.mmodule
var nsig = self.n_signature
+ if mpropdef.mproperty.is_root_init and not mclassdef.is_intro then
+ var root_init = mclassdef.mclass.root_init
+ if root_init != null then
+ # Inherit the initializers by refinement
+ mpropdef.new_msignature = root_init.new_msignature
+ assert mpropdef.initializers.is_empty
+ mpropdef.initializers.add_all root_init.initializers
+ end
+ end
+
# Retrieve info from the signature AST
var param_names = new Array[String] # Names of parameters from the AST
var param_types = new Array[MType] # Types of parameters from the AST
@@ -718,12 +740,12 @@ redef class AAttrPropdef
# Is the node tagged `noinit`?
var noinit = false
- # Is the node taggeg lazy?
+ # Is the node tagged lazy?
var is_lazy = false
- # The guard associated to a lasy attribute.
+ # The guard associated to a lazy attribute.
# Because some engines does not have a working `isset`,
- # this additionnal attribute is used to guard the lazy initialization.
+ # this additional attribute is used to guard the lazy initialization.
# TODO: to remove once isset is correctly implemented
var mlazypropdef: nullable MAttributeDef
@@ -830,7 +852,7 @@ redef class AAttrPropdef
redef fun build_signature(modelbuilder)
do
var mpropdef = self.mpropdef
- if mpropdef == null then return # Error thus skiped
+ if mpropdef == null then return # Error thus skipped
var mclassdef = mpropdef.mclassdef
var mmodule = mclassdef.mmodule
var mtype: nullable MType = null
@@ -843,10 +865,10 @@ redef class AAttrPropdef
if mtype == null then return
end
- # Inherit the type from the getter (usually an abstact getter)
+ # Inherit the type from the getter (usually an abstract getter)
if mtype == null and mreadpropdef != null and not mreadpropdef.is_intro then
var msignature = mreadpropdef.mproperty.intro.msignature
- if msignature == null then return # Error, thus skiped
+ if msignature == null then return # Error, thus skipped
mtype = msignature.return_mtype
end
@@ -918,12 +940,10 @@ redef class AAttrPropdef
redef fun check_signature(modelbuilder)
do
var mpropdef = self.mpropdef
- if mpropdef == null then return # Error thus skiped
- var mclassdef = mpropdef.mclassdef
- var mmodule = mclassdef.mmodule
+ if mpropdef == null then return # Error thus skipped
var ntype = self.n_type
var mtype = self.mpropdef.static_mtype
- if mtype == null then return # Error thus skiped
+ if mtype == null then return # Error thus skipped
# Lookup for signature in the precursor
# FIXME all precursors should be considered
@@ -1046,7 +1066,7 @@ redef class ATypePropdef
redef fun build_signature(modelbuilder)
do
var mpropdef = self.mpropdef
- if mpropdef == null then return # Error thus skiped
+ if mpropdef == null then return # Error thus skipped
var mclassdef = mpropdef.mclassdef
var mmodule = mclassdef.mmodule
var mtype: nullable MType = null
@@ -1062,10 +1082,10 @@ redef class ATypePropdef
redef fun check_signature(modelbuilder)
do
var mpropdef = self.mpropdef
- if mpropdef == null then return # Error thus skiped
+ if mpropdef == null then return # Error thus skipped
var bound = self.mpropdef.bound
- if bound == null then return # Error thus skiped
+ if bound == null then return # Error thus skipped
modelbuilder.check_visibility(n_type, bound, mpropdef)
diff --git a/src/neo.nit b/src/neo.nit
index b44d034..f9d3c9a 100644
--- a/src/neo.nit
+++ b/src/neo.nit
@@ -12,17 +12,17 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-# Save and load `Model` from/to Neo4j base.
+# Save and load a `Model` to/from a Neo4j graph.
#
# Nit models are composed by MEntities.
# This module creates NeoNode for each MEntity found in a `Model` and save them
# into Neo4j database.
#
-# see `Neo4jClient`.
+# SEE: `Neo4jClient`
#
# NeoNodes can also be translated back to MEntities to rebuild a Nit `Model`.
#
-# Structure of the nit `Model` in base:
+# Structure of the nit `Model` in the graph:
#
# Note : Any null or empty attribute will not be saved in the database.
#
@@ -67,9 +67,10 @@
#
# * labels: `MClass`, `model_name` and `MEntity`.
# * `full_name`: fully qualified name.
-# * `arity`: number of generic formal parameters. 0 if the class is not generic.
# * `kind`: kind of the class (`interface`, `abstract class`, etc.)
# * `visibility`: visibility of the class.
+# * `parameter_names`: JSON array listing the name of each formal generic
+# parameter (in order of declaration).
# * `(:MClass)-[:CLASSTYPE]->(:MClassType)`: SEE: `MClass.mclass_type`
#
# Arguments in the `CLASSTYPE` are named following the `parameter_names`
@@ -82,8 +83,6 @@
# * labels: `MClassDef`, `model_name` and `MEntity`.
# * `is_intro`: Does this definition introduce the class?
# * `location`: origin of the definition. SEE: `Location.to_s`
-# * `parameter_names`: JSON array listing the name of each formal generic
-# parameter (in order of declaration).
# * `(:MClassDef)-[:BOUNDTYPE]->(:MClassType)`: bounded type associated to the
# classdef.
# * `(:MClassDef)-[:MCLASS]->(:MClass)`: associated `MClass`.
@@ -122,6 +121,11 @@
# * `(:MMethodDef)-[:SIGNATURE]->(:MSignature)`: signature attached to the
# property definition.
#
+# Additional relationship for `MAttributeDef`:
+#
+# * `(:MAttributeDef)-[:TYPE]->(:MType)`: static type of the attribute,
+# if specified.
+#
# Additional relationship for `MVirtualTypeDef`:
#
# * `(:MVirtualTypeDef)-[:BOUND]->(:MType)`: type to which the virtual type
@@ -141,7 +145,7 @@
# * `(:MClassType)-[:ARGUMENT]->(:MType)`: type arguments.
#
# Arguments are named following the `parameter_names` attribute of the
-# `MClassDef` that introduces the class referred by `CLASS`.
+# `MClass` referred by `CLASS`.
#
# Additional relationship for `MVirtualType`:
#
@@ -446,7 +450,6 @@ class NeoModel
node.labels.add "MModule"
node["full_name"] = mmodule.full_name
node["location"] = mmodule.location.to_s
- var mgroup = mmodule.mgroup
for parent in mmodule.in_importation.direct_greaters do
node.out_edges.add(new NeoEdge(node, "IMPORTS", to_node(parent)))
end
@@ -633,6 +636,10 @@ class NeoModel
end
else if mpropdef isa MAttributeDef then
node.labels.add "MAttributeDef"
+ var static_mtype = mpropdef.static_mtype
+ if static_mtype != null then
+ node.out_edges.add(new NeoEdge(node, "TYPE", to_node(static_mtype)))
+ end
else if mpropdef isa MVirtualTypeDef then
node.labels.add "MVirtualTypeDef"
var bound = mpropdef.bound
@@ -663,6 +670,8 @@ class NeoModel
else if node.labels.has("MAttributeDef") then
mpropdef = new MAttributeDef(mclassdef, mproperty.as(MAttribute), location)
mentities[node] = mpropdef
+ var static_mtype = node.out_nodes("TYPE")
+ if not static_mtype.is_empty then mpropdef.static_mtype = to_mtype(model, static_mtype.first)
else if node.labels.has("MVirtualTypeDef") then
mpropdef = new MVirtualTypeDef(mclassdef, mproperty.as(MVirtualTypeProp), location)
mentities[node] = mpropdef
diff --git a/src/nit.nit b/src/nit.nit
index 24bb00e..9a95194 100644
--- a/src/nit.nit
+++ b/src/nit.nit
@@ -27,10 +27,9 @@ toolcontext.tooldescription = "Usage: nit [OPTION]... ...\nInterprets
# Add an option "-o" to enable compatibilit with the tests.sh script
var opt = new OptionString("compatibility (does noting)", "-o")
toolcontext.option_context.add_option(opt)
-var opt_mixins = new OptionArray("Additionals module to min-in", "-m")
var opt_eval = new OptionBool("Specifies the program from command-line", "-e")
var opt_loop = new OptionBool("Repeatedly run the program for each line in file-name arguments", "-n")
-toolcontext.option_context.add_option(opt_mixins, opt_eval, opt_loop)
+toolcontext.option_context.add_option(opt_eval, opt_loop)
# We do not add other options, so process them now!
toolcontext.process_options(args)
@@ -66,20 +65,11 @@ else
mmodules = modelbuilder.parse([progname])
end
-mmodules.add_all modelbuilder.parse(opt_mixins.value)
modelbuilder.run_phases
if toolcontext.opt_only_metamodel.value then exit(0)
-var mainmodule: nullable MModule
-
-# Here we launch the interpreter on the main module
-if mmodules.length == 1 then
- mainmodule = mmodules.first
-else
- mainmodule = new MModule(model, null, mmodules.first.name, mmodules.first.location)
- mainmodule.set_imported_mmodules(mmodules)
-end
+var mainmodule = toolcontext.make_main_module(mmodules)
var self_mm = mainmodule
var self_args = arguments
diff --git a/src/nitpretty.nit b/src/nitpretty.nit
index f43c8d1..32294c2 100644
--- a/src/nitpretty.nit
+++ b/src/nitpretty.nit
@@ -2248,7 +2248,6 @@ end
redef class ASuperstringExpr
redef fun accept_pretty_printer(v) do
- var force_inline = self.force_inline
for n_expr in n_exprs do v.visit n_expr
end
diff --git a/src/nitserial.nit b/src/nitserial.nit
index 5ad0aed..2fd0f82 100644
--- a/src/nitserial.nit
+++ b/src/nitserial.nit
@@ -53,7 +53,7 @@ class NitModule
if header != null then add header
var name = name
- if name != null then add "module {name}\n\n"
+ add "module {name}\n\n"
for i in imports do add "import {i}\n"
add "\n"
diff --git a/src/parser/parser_nodes.nit b/src/parser/parser_nodes.nit
index f7f4b60..a4d6d44 100644
--- a/src/parser/parser_nodes.nit
+++ b/src/parser/parser_nodes.nit
@@ -1347,14 +1347,19 @@ abstract class ALabelable
var n_label: nullable ALabel = null is writable
end
-# A `break` statement.
-class ABreakExpr
+# A `break` or a `continue`
+abstract class AEscapeExpr
super AExpr
super ALabelable
- var n_kwbreak: TKwbreak is writable, noinit
var n_expr: nullable AExpr = null is writable
end
+# A `break` statement.
+class ABreakExpr
+ super AEscapeExpr
+ var n_kwbreak: TKwbreak is writable, noinit
+end
+
# An `abort` statement
class AAbortExpr
super AExpr
@@ -1363,10 +1368,8 @@ end
# A `continue` statement
class AContinueExpr
- super AExpr
- super ALabelable
+ super AEscapeExpr
var n_kwcontinue: nullable TKwcontinue = null is writable
- var n_expr: nullable AExpr = null is writable
end
# A `do` statement
diff --git a/src/parser/parser_work.nit b/src/parser/parser_work.nit
index 2a83ee0..4d67908 100644
--- a/src/parser/parser_work.nit
+++ b/src/parser/parser_work.nit
@@ -246,8 +246,6 @@ private class ComputeProdLocationVisitor
end
end
end
-
- init do end
end
private class TextCollectorVisitor
diff --git a/src/rapid_type_analysis.nit b/src/rapid_type_analysis.nit
index a6adfee..897d7b7 100644
--- a/src/rapid_type_analysis.nit
+++ b/src/rapid_type_analysis.nit
@@ -244,6 +244,9 @@ class RapidTypeAnalysis
if mmethoddef.mproperty.is_root_init and not mmethoddef.is_intro then
self.add_super_send(v.receiver, mmethoddef)
end
+ else if mmethoddef.constant_value != null then
+ # Make the return type live
+ v.add_type(mmethoddef.msignature.return_mtype.as(MClassType))
else
abort
end
@@ -675,6 +678,8 @@ redef class AForExpr
abort
end
v.add_callsite(self.method_next)
+ var mf = self.method_finish
+ if mf != null then v.add_callsite(mf)
end
end
diff --git a/src/semantize/auto_super_init.nit b/src/semantize/auto_super_init.nit
index 95b2acb..25874e2 100644
--- a/src/semantize/auto_super_init.nit
+++ b/src/semantize/auto_super_init.nit
@@ -32,10 +32,6 @@ end
private class AutoSuperInitVisitor
super Visitor
- init
- do
- end
-
redef fun visit(n)
do
n.accept_auto_super_init(self)
@@ -210,7 +206,6 @@ redef class ASendExpr
redef fun accept_auto_super_init(v)
do
var mproperty = self.callsite.mproperty
- if mproperty == null then return
if mproperty.is_init then
v.has_explicit_super_init = self
end
diff --git a/src/semantize/flow.nit b/src/semantize/flow.nit
index d4f6cb9..522a347 100644
--- a/src/semantize/flow.nit
+++ b/src/semantize/flow.nit
@@ -165,7 +165,7 @@ private class FlowVisitor
fun merge_continues_to(before_loop: FlowContext, escapemark: nullable EscapeMark)
do
if escapemark == null then return
- for b in escapemark.continues do
+ for b in escapemark.escapes do
var before = b.before_flow_context
if before == null then continue # Forward error
before_loop.add_loop(before)
@@ -175,7 +175,7 @@ private class FlowVisitor
fun merge_breaks(escapemark: nullable EscapeMark)
do
if escapemark == null then return
- for b in escapemark.breaks do
+ for b in escapemark.escapes do
var before = b.before_flow_context
if before == null then continue # Forward error
self.make_merge_flow(self.current_flow_context, before)
@@ -319,22 +319,7 @@ redef class AReturnExpr
end
end
-redef class AContinueExpr
- # The flow just before it become unreachable
- fun before_flow_context: nullable FlowContext
- do
- var after = self.after_flow_context
- if after == null then return null
- return after.previous.first
- end
- redef fun accept_flow_visitor(v)
- do
- super
- v.make_unreachable_flow
- end
-end
-
-redef class ABreakExpr
+redef class AEscapeExpr
# The flow just before it become unreachable
fun before_flow_context: nullable FlowContext
do
@@ -361,7 +346,7 @@ redef class ADoExpr
redef fun accept_flow_visitor(v)
do
super
- v.merge_breaks(self.escapemark)
+ v.merge_breaks(self.break_mark)
end
end
@@ -411,10 +396,10 @@ redef class AWhileExpr
var after_block = v.current_flow_context
before_loop.add_loop(after_block)
- v.merge_continues_to(after_block, self.escapemark)
+ v.merge_continues_to(after_block, self.continue_mark)
v.current_flow_context = after_expr.when_false
- v.merge_breaks(self.escapemark)
+ v.merge_breaks(self.break_mark)
end
end
@@ -428,10 +413,10 @@ redef class ALoopExpr
var after_block = v.current_flow_context
before_loop.add_loop(after_block)
- v.merge_continues_to(after_block, self.escapemark)
+ v.merge_continues_to(after_block, self.continue_mark)
v.make_unreachable_flow
- v.merge_breaks(self.escapemark)
+ v.merge_breaks(self.break_mark)
end
end
@@ -447,10 +432,10 @@ redef class AForExpr
var after_block = v.current_flow_context
before_loop.add_loop(after_block)
- v.merge_continues_to(after_block, self.escapemark)
+ v.merge_continues_to(after_block, self.continue_mark)
v.make_merge_flow(v.current_flow_context, before_loop)
- v.merge_breaks(self.escapemark)
+ v.merge_breaks(self.break_mark)
end
end
diff --git a/src/semantize/scope.nit b/src/semantize/scope.nit
index 3039745..00702d0 100644
--- a/src/semantize/scope.nit
+++ b/src/semantize/scope.nit
@@ -50,15 +50,12 @@ class EscapeMark
# The name of the label (unless the mark is an anonymous loop mark)
var name: nullable String
- # Is the mark attached to a loop (loop, while, for)
- # Such a mark is a candidate to a labelless 'continue' or 'break'
- var for_loop: Bool
+ # The associated `continue` mark, if any.
+ # If the mark attached to a loop (loop, while, for), a distinct mark is used.
+ private var continue_mark: nullable EscapeMark = null
- # Each 'continue' attached to the mark
- var continues = new Array[AContinueExpr]
-
- # Each 'break' attached to the mark
- var breaks = new Array[ABreakExpr]
+ # Each break/continue attached to the mark
+ var escapes = new Array[AEscapeExpr]
end
# Visit a npropdef and:
@@ -81,7 +78,7 @@ private class ScopeVisitor
end
# All stacked scope. `scopes.first` is the current scope
- private var scopes = new List[Scope]
+ var scopes = new List[Scope]
# Shift and check the last scope
fun shift_scope
@@ -176,7 +173,8 @@ private class ScopeVisitor
else
name = null
end
- var res = new EscapeMark(name, for_loop)
+ var res = new EscapeMark(name)
+ if for_loop then res.continue_mark = new EscapeMark(name)
return res
end
@@ -292,43 +290,47 @@ redef class ASelfExpr
end
end
-redef class AContinueExpr
- # The escape mark associated with the continue
+redef class AEscapeExpr
+ # The escape mark associated with the break/continue
var escapemark: nullable EscapeMark
+end
+
+redef class AContinueExpr
redef fun accept_scope_visitor(v)
do
super
var escapemark = v.get_escapemark(self, self.n_label)
if escapemark == null then return # Skip error
- if not escapemark.for_loop then
+ escapemark = escapemark.continue_mark
+ if escapemark == null then
v.error(self, "Error: cannot 'continue', only 'break'.")
+ return
end
- escapemark.continues.add(self)
+ escapemark.escapes.add(self)
self.escapemark = escapemark
end
end
redef class ABreakExpr
- # The escape mark associated with the break
- var escapemark: nullable EscapeMark
redef fun accept_scope_visitor(v)
do
super
var escapemark = v.get_escapemark(self, self.n_label)
if escapemark == null then return # Skip error
- escapemark.breaks.add(self)
+ escapemark.escapes.add(self)
self.escapemark = escapemark
end
end
redef class ADoExpr
- # The escape mark associated with the 'do' block
- var escapemark: nullable EscapeMark
+ # The break escape mark associated with the 'do' block
+ var break_mark: nullable EscapeMark
+
redef fun accept_scope_visitor(v)
do
- self.escapemark = v.make_escape_mark(n_label, false)
- v.enter_visit_block(n_block, self.escapemark)
+ self.break_mark = v.make_escape_mark(n_label, false)
+ v.enter_visit_block(n_block, self.break_mark)
end
end
@@ -342,24 +344,34 @@ redef class AIfExpr
end
redef class AWhileExpr
- # The escape mark associated with the 'while'
- var escapemark: nullable EscapeMark
+ # The break escape mark associated with the 'while'
+ var break_mark: nullable EscapeMark
+
+ # The continue escape mark associated with the 'while'
+ var continue_mark: nullable EscapeMark
+
redef fun accept_scope_visitor(v)
do
var escapemark = v.make_escape_mark(n_label, true)
- self.escapemark = escapemark
+ self.break_mark = escapemark
+ self.continue_mark = escapemark.continue_mark
v.enter_visit(n_expr)
v.enter_visit_block(n_block, escapemark)
end
end
redef class ALoopExpr
- # The escape mark associated with the 'loop'
- var escapemark: nullable EscapeMark
+ # The break escape mark associated with the 'loop'
+ var break_mark: nullable EscapeMark
+
+ # The continue escape mark associated with the 'loop'
+ var continue_mark: nullable EscapeMark
+
redef fun accept_scope_visitor(v)
do
var escapemark = v.make_escape_mark(n_label, true)
- self.escapemark = escapemark
+ self.break_mark = escapemark
+ self.continue_mark = escapemark.continue_mark
v.enter_visit_block(n_block, escapemark)
end
end
@@ -368,8 +380,11 @@ redef class AForExpr
# The automatic variables in order
var variables: nullable Array[Variable]
- # The escape mark associated with the 'for'
- var escapemark: nullable EscapeMark
+ # The break escape mark associated with the 'for'
+ var break_mark: nullable EscapeMark
+
+ # The continue escape mark associated with the 'for'
+ var continue_mark: nullable EscapeMark
redef fun accept_scope_visitor(v)
do
@@ -388,7 +403,8 @@ redef class AForExpr
end
var escapemark = v.make_escape_mark(n_label, true)
- self.escapemark = escapemark
+ self.break_mark = escapemark
+ self.continue_mark = escapemark.continue_mark
v.enter_visit_block(n_block, escapemark)
v.shift_scope
diff --git a/src/semantize/typing.nit b/src/semantize/typing.nit
index 95d7b3a..d3d4da7 100644
--- a/src/semantize/typing.nit
+++ b/src/semantize/typing.nit
@@ -47,7 +47,7 @@ private class TypeVisitor
# The analyzed property
var mpropdef: nullable MPropDef
- var selfvariable: Variable = new Variable("self")
+ var selfvariable = new Variable("self")
# Is `self` use restricted?
# * no explicit `self`
@@ -195,6 +195,40 @@ private class TypeVisitor
return sup
end
+ # Special verification on != and == for null
+ # Return true
+ fun null_test(anode: ABinopExpr)
+ do
+ var mtype = anode.n_expr.mtype
+ var mtype2 = anode.n_expr2.mtype
+
+ if mtype == null or mtype2 == null then return
+
+ if not mtype2 isa MNullType then return
+
+ # Check of useless null
+ if not mtype isa MNullableType then
+ if not anchor_to(mtype) isa MNullableType then
+ modelbuilder.warning(anode, "useless-null-test", "Warning: expression is not null, since it is a `{mtype}`.")
+ end
+ return
+ end
+
+ # Check for type adaptation
+ var variable = anode.n_expr.its_variable
+ if variable == null then return
+
+ if anode isa AEqExpr then
+ anode.after_flow_context.when_true.set_var(variable, mtype2)
+ anode.after_flow_context.when_false.set_var(variable, mtype.mtype)
+ else if anode isa ANeExpr then
+ anode.after_flow_context.when_false.set_var(variable, mtype2)
+ anode.after_flow_context.when_true.set_var(variable, mtype.mtype)
+ else
+ abort
+ end
+ end
+
fun try_get_mproperty_by_name2(anode: ANode, mtype: MType, name: String): nullable MProperty
do
return self.modelbuilder.try_get_mproperty_by_name2(anode, mmodule, mtype, name)
@@ -304,6 +338,15 @@ private class TypeVisitor
return callsite
end
+ fun try_get_method(node: ANode, recvtype: MType, name: String, recv_is_self: Bool): nullable CallSite
+ do
+ var unsafe_type = self.anchor_to(recvtype)
+ var mproperty = self.try_get_mproperty_by_name2(node, unsafe_type, name)
+ if mproperty == null then return null
+ return get_method(node, recvtype, name, recv_is_self)
+ end
+
+
# Visit the expressions of args and check their conformity with the corresponding type in signature
# The point of this method is to handle varargs correctly
# Note: The signature must be correctly adapted
@@ -334,11 +377,18 @@ private class TypeVisitor
self.visit_expr_subtype(args[j], paramtype)
end
if vararg_rank >= 0 then
- var varargs = new Array[AExpr]
var paramtype = msignature.mparameters[vararg_rank].mtype
- for j in [vararg_rank..vararg_rank+vararg_decl] do
- varargs.add(args[j])
- self.visit_expr_subtype(args[j], paramtype)
+ var first = args[vararg_rank]
+ if vararg_decl == 0 and first isa AVarargExpr then
+ var mclass = get_mclass(node, "Array")
+ if mclass == null then return false # Forward error
+ var array_mtype = mclass.get_mtype([paramtype])
+ self.visit_expr_subtype(first.n_expr, array_mtype)
+ first.mtype = first.n_expr.mtype
+ else
+ for j in [vararg_rank..vararg_rank+vararg_decl] do
+ self.visit_expr_subtype(args[j], paramtype)
+ end
end
end
return true
@@ -386,7 +436,6 @@ private class TypeVisitor
fun merge_types(node: ANode, col: Array[nullable MType]): nullable MType
do
if col.length == 1 then return col.first
- var res = new Array[nullable MType]
for t1 in col do
if t1 == null then continue # return null
var found = true
@@ -452,8 +501,8 @@ end
redef class FlowContext
# Store changes of types because of type evolution
- private var vars: HashMap[Variable, nullable MType] = new HashMap[Variable, nullable MType]
- private var cache: HashMap[Variable, nullable Array[nullable MType]] = new HashMap[Variable, nullable Array[nullable MType]]
+ private var vars = new HashMap[Variable, nullable MType]
+ private var cache = new HashMap[Variable, nullable Array[nullable MType]]
# Adapt the variable to a static type
# Warning1: do not modify vars directly.
@@ -738,7 +787,7 @@ redef class AContinueExpr
do
var nexpr = self.n_expr
if nexpr != null then
- var mtype = v.visit_expr(nexpr)
+ v.visit_expr(nexpr)
end
self.is_typed = true
end
@@ -749,7 +798,7 @@ redef class ABreakExpr
do
var nexpr = self.n_expr
if nexpr != null then
- var mtype = v.visit_expr(nexpr)
+ v.visit_expr(nexpr)
end
self.is_typed = true
end
@@ -762,9 +811,9 @@ redef class AReturnExpr
var ret_type = v.mpropdef.as(MMethodDef).msignature.return_mtype
if nexpr != null then
if ret_type != null then
- var mtype = v.visit_expr_subtype(nexpr, ret_type)
+ v.visit_expr_subtype(nexpr, ret_type)
else
- var mtype = v.visit_expr(nexpr)
+ v.visit_expr(nexpr)
v.error(self, "Error: Return with value in a procedure.")
end
else if ret_type != null then
@@ -846,6 +895,10 @@ redef class AForExpr
var method_item: nullable CallSite
var method_next: nullable CallSite
var method_key: nullable CallSite
+ var method_finish: nullable CallSite
+
+ var method_lt: nullable CallSite
+ var method_successor: nullable CallSite
private fun do_type_iterator(v: TypeVisitor, mtype: MType)
do
@@ -937,6 +990,8 @@ redef class AForExpr
end
self.method_next = nextdef
+ self.method_finish = v.try_get_method(self, ittype, "finish", false)
+
if is_map then
var keydef = v.get_method(self, ittype, "key", false)
if keydef == null then
@@ -945,6 +1000,19 @@ redef class AForExpr
end
self.method_key = keydef
end
+
+ if self.variables.length == 1 and n_expr isa ARangeExpr then
+ var variable = variables.first
+ var vtype = variable.declared_type.as(not null)
+
+ if n_expr isa AOrangeExpr then
+ self.method_lt = v.get_method(self, vtype, "<", false)
+ else
+ self.method_lt = v.get_method(self, vtype, "<=", false)
+ end
+
+ self.method_successor = v.get_method(self, vtype, "successor", false)
+ end
end
redef fun accept_typing(v)
@@ -1195,9 +1263,9 @@ redef class AIsaExpr
var variable = self.n_expr.its_variable
if variable != null then
- var orig = self.n_expr.mtype
- var from = if orig != null then orig.to_s else "invalid"
- var to = if mtype != null then mtype.to_s else "invalid"
+ #var orig = self.n_expr.mtype
+ #var from = if orig != null then orig.to_s else "invalid"
+ #var to = if mtype != null then mtype.to_s else "invalid"
#debug("adapt {variable}: {from} -> {to}")
self.after_flow_context.when_true.set_var(variable, mtype)
end
@@ -1331,16 +1399,7 @@ redef class AEqExpr
redef fun accept_typing(v)
do
super
-
- var variable = self.n_expr.its_variable
- if variable == null then return
- var mtype = self.n_expr2.mtype
- if not mtype isa MNullType then return
- var vartype = v.get_variable(self, variable)
- if not vartype isa MNullableType then return
- self.after_flow_context.when_true.set_var(variable, mtype)
- self.after_flow_context.when_false.set_var(variable, vartype.mtype)
- #debug("adapt {variable}:{vartype} ; true->{mtype} false->{vartype.mtype}")
+ v.null_test(self)
end
end
redef class ANeExpr
@@ -1348,16 +1407,7 @@ redef class ANeExpr
redef fun accept_typing(v)
do
super
-
- var variable = self.n_expr.its_variable
- if variable == null then return
- var mtype = self.n_expr2.mtype
- if not mtype isa MNullType then return
- var vartype = v.get_variable(self, variable)
- if not vartype isa MNullableType then return
- self.after_flow_context.when_false.set_var(variable, mtype)
- self.after_flow_context.when_true.set_var(variable, vartype.mtype)
- #debug("adapt {variable}:{vartype} ; true->{vartype.mtype} false->{mtype}")
+ v.null_test(self)
end
end
redef class ALtExpr
@@ -1758,6 +1808,16 @@ redef class AIssetAttrExpr
end
end
+redef class AVarargExpr
+ redef fun accept_typing(v)
+ do
+ # This kind of pseudo-expression can be only processed trough a signature
+ # See `check_signature`
+ # Other cases are a syntax error.
+ v.error(self, "Syntax error: unexpected `...`")
+ end
+end
+
###
redef class ADebugTypeExpr
diff --git a/src/testing/testing_doc.nit b/src/testing/testing_doc.nit
index 9f31805..566e014 100644
--- a/src/testing/testing_doc.nit
+++ b/src/testing/testing_doc.nit
@@ -136,7 +136,7 @@ class NitUnitExecutor
var res = sys.system(cmd)
var res2 = 0
if res == 0 then
- res2 = sys.system("./{file}.bin >>'{file}.out1' 2>&1 >'{file}.out1' 2>&1 '{file}.out1' 2>&1 '{file}.out1' 2>&1 """
+ exit 0
+ end
+
var errors = option_context.get_errors
if not errors.is_empty then
for e in errors do print "Error: {e}"
@@ -438,7 +472,7 @@ class BashCompletion
addn " COMPREPLY=()"
addn " cur=\"$\{COMP_WORDS[COMP_CWORD]\}\""
addn " prev=\"$\{COMP_WORDS[COMP_CWORD-1]\}\""
- if option_names != null then
+ if not option_names.is_empty then
addn " opts=\"{option_names.join(" ")}\""
addn " if [[ $\{cur\} == -* ]] ; then"
addn " COMPREPLY=( $(compgen -W \"$\{opts\}\" -- $\{cur\}) )"
diff --git a/src/transform.nit b/src/transform.nit
index 6a209c3..6c8208a 100644
--- a/src/transform.nit
+++ b/src/transform.nit
@@ -19,9 +19,19 @@ module transform
import astbuilder
import astvalidation
import semantize
+intrude import semantize::scope
redef class ToolContext
var transform_phase: Phase = new TransformPhase(self, [typing_phase, auto_super_init_phase])
+
+ # --no-shortcut-range
+ var opt_no_shortcut_range: OptionBool = new OptionBool("Always insantiate a range and its iterator on 'for' loops", "--no-shortcut-range")
+
+ redef init
+ do
+ super
+ self.option_context.add_option(self.opt_no_shortcut_range)
+ end
end
private class TransformPhase
@@ -151,14 +161,113 @@ end
redef class AWhileExpr
redef fun accept_transform_visitor(v)
do
- # TODO
+ var nloop = v.builder.make_loop
+ var nif = v.builder.make_if(n_expr, null)
+ nloop.add nif
+
+ var nblock = n_block
+ if nblock != null then nif.n_then.add nblock
+
+ var escapemark = self.break_mark.as(not null)
+ var nbreak = v.builder.make_break(escapemark)
+ nif.n_else.add nbreak
+
+ nloop.break_mark = self.break_mark
+ nloop.continue_mark = self.continue_mark
+
+ replace_with(nloop)
end
end
redef class AForExpr
redef fun accept_transform_visitor(v)
do
- # TODO
+ var escapemark = self.break_mark
+ assert escapemark != null
+
+ var nblock = v.builder.make_block
+
+ var nexpr = n_expr
+
+ # Shortcut on explicit range
+ # Avoid the instantiation of the range and the iterator
+ if self.variables.length == 1 and nexpr isa ARangeExpr and not v.phase.toolcontext.opt_no_shortcut_range.value then
+ var variable = variables.first
+ nblock.add v.builder.make_var_assign(variable, nexpr.n_expr)
+ var to = nexpr.n_expr2
+ nblock.add to
+
+ var nloop = v.builder.make_loop
+ nloop.break_mark = escapemark
+ nblock.add nloop
+
+ var is_ok = v.builder.make_call(v.builder.make_var_read(variable, variable.declared_type.as(not null)), method_lt.as(not null), [to.make_var_read])
+
+ var nif = v.builder.make_if(is_ok, null)
+ nloop.add nif
+
+ var nthen = nif.n_then
+ var ndo = v.builder.make_do
+ ndo.break_mark = escapemark.continue_mark
+ nthen.add ndo
+
+ ndo.add self.n_block.as(not null)
+
+ var one = v.builder.make_int(1)
+ var succ = v.builder.make_call(v.builder.make_var_read(variable, variable.declared_type.as(not null)), method_successor.as(not null), [one])
+ nthen.add v.builder.make_var_assign(variable, succ)
+
+ var nbreak = v.builder.make_break(escapemark)
+ nif.n_else.add nbreak
+
+ replace_with(nblock)
+ return
+ end
+
+ nblock.add nexpr
+
+ var iter = v.builder.make_call(nexpr.make_var_read, method_iterator.as(not null), null)
+ nblock.add iter
+
+ var nloop = v.builder.make_loop
+ nloop.break_mark = escapemark
+ nblock.add nloop
+
+ var is_ok = v.builder.make_call(iter.make_var_read, method_is_ok.as(not null), null)
+
+ var nif = v.builder.make_if(is_ok, null)
+ nloop.add nif
+
+ var nthen = nif.n_then
+ var ndo = v.builder.make_do
+ ndo.break_mark = escapemark.continue_mark
+ nthen.add ndo
+
+ if self.variables.length == 1 then
+ var item = v.builder.make_call(iter.make_var_read, method_item.as(not null), null)
+ ndo.add v.builder.make_var_assign(variables.first, item)
+ else if self.variables.length == 2 then
+ var key = v.builder.make_call(iter.make_var_read, method_key.as(not null), null)
+ ndo.add v.builder.make_var_assign(variables[0], key)
+ var item = v.builder.make_call(iter.make_var_read, method_item.as(not null), null)
+ ndo.add v.builder.make_var_assign(variables[1], item)
+ else
+ abort
+ end
+
+ ndo.add self.n_block.as(not null)
+
+ nthen.add v.builder.make_call(iter.make_var_read, method_next.as(not null), null)
+
+ var nbreak = v.builder.make_break(escapemark)
+ nif.n_else.add nbreak
+
+ var method_finish = self.method_finish
+ if method_finish != null then
+ nblock.add v.builder.make_call(iter.make_var_read, method_finish, null)
+ end
+
+ replace_with(nblock)
end
end
diff --git a/src/vm.nit b/src/vm.nit
index 0779a6a..3807ab7 100644
--- a/src/vm.nit
+++ b/src/vm.nit
@@ -106,7 +106,6 @@ class VirtualMachine super NaiveInterpreter
# Sub can be discovered inside a Generic type during the subtyping test
if not sub.mclass.loaded then create_class(sub.mclass)
- if anchor == null then anchor = sub
if sup isa MGenericType then
var sub2 = sub.supertype_to(mainmodule, anchor, sup.mclass)
assert sub2.mclass == sup.mclass
diff --git a/tests/base_for_finish.nit b/tests/base_for_finish.nit
new file mode 100644
index 0000000..baaf29e
--- /dev/null
+++ b/tests/base_for_finish.nit
@@ -0,0 +1,60 @@
+# 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 array
+
+class MyC
+ var data: Collection[Object]
+ fun iterator: MyI do return new MyI(data.iterator)
+end
+
+class MyI
+ super Iterator[Object]
+ var iter: Iterator[Object]
+ redef fun is_ok do return iter.is_ok
+ redef fun item do return iter.item
+ redef fun next do iter.next
+ redef fun finish do 0.output
+end
+
+fun test(a: MyC)
+do
+ for x in a do
+ x.output
+ for y in [10,20] do
+ y.output
+ if x == 2 then return
+ end
+ 100.output
+ end
+ 200.output
+end
+
+var a = new MyC([1,2,3])
+
+for x in a do
+ x.output
+end
+
+'\n'.output
+
+for x in a do
+ x.output
+ if x == 2 then break
+ 100.output
+end
+
+'\n'.output
+
+test(a)
diff --git a/tests/base_init_auto_refine.nit b/tests/base_init_auto_refine.nit
new file mode 100644
index 0000000..afa534f
--- /dev/null
+++ b/tests/base_init_auto_refine.nit
@@ -0,0 +1,22 @@
+# 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 base_init_auto
+
+redef class A
+ redef init do 'A'.output
+end
+
+var a = new A(2)
+a.work
diff --git a/tests/base_vararg3.nit b/tests/base_vararg3.nit
new file mode 100644
index 0000000..6918fef
--- /dev/null
+++ b/tests/base_vararg3.nit
@@ -0,0 +1,45 @@
+# 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 array
+
+class A
+ fun foo(a: Int...) do a.first.output
+end
+
+class B
+ super A
+ redef fun foo(a)
+ do
+ 'a'.output
+ super
+ 'b'.output
+ super(a...)
+ 'c'.output
+ super(4,5,6)
+ 'd'.output
+ super([5,6,7]...)
+ #alt3#super(a)
+ #alt4#super(1...)
+ end
+end
+
+var a = new A
+a.foo(1,2,3)
+a.foo([2,3,4]...)
+#alt1#a.foo([1,2,3])
+#alt2#a.foo(1...)
+
+var b = new B
+b.foo(3,4,5)
diff --git a/tests/bench_complex_sort.nit b/tests/bench_complex_sort.nit
index 116d7d7..2eef2cb 100644
--- a/tests/bench_complex_sort.nit
+++ b/tests/bench_complex_sort.nit
@@ -74,8 +74,9 @@ class E
end
class EltComparator
- super Comparator[Elt]
- redef fun compare(a: Elt, b: Elt): Int
+ super Comparator
+ redef type COMPARED: Elt
+ redef fun compare(a, b)
do
if _is_val1 then
return a.val1 <=> b.val1
diff --git a/tests/example_sorter.nit b/tests/example_sorter.nit
index 32b661c..ae839ed 100644
--- a/tests/example_sorter.nit
+++ b/tests/example_sorter.nit
@@ -16,7 +16,8 @@
class BackIntComparator
- super Comparator[Int]
+ super Comparator
+ redef type COMPARED: Int
redef fun compare(a: Int, b: Int): Int
do
return b <=> a
@@ -26,7 +27,8 @@ class BackIntComparator
end
class DecimalComparator
- super Comparator[Int]
+ super Comparator
+ redef type COMPARED: Int
redef fun compare(a: Int, b: Int): Int
do
return (a%10) <=> (b%10)
@@ -51,7 +53,7 @@ end
var q = get_an_array(50)
print(q.join(" "))
-(new DefaultComparator[Int]).sort(q)
+(default_comparator).sort(q)
print(q.join(" "))
(new DecimalComparator).sort(q)
print(q.join(" "))
diff --git a/tests/nit.args b/tests/nit.args
index 3011fc1..0c14c1c 100644
--- a/tests/nit.args
+++ b/tests/nit.args
@@ -1,3 +1,4 @@
--log --log-dir out/test_nitc_logs ../examples/hello_world.nit
base_simple3.nit
-m test_mixin.nit ../examples/hello_world.nit
+test_define.nit -D text=hello -D num=42 -D flag
diff --git a/tests/nitg.args b/tests/nitg.args
index 3b38c54..6a47146 100644
--- a/tests/nitg.args
+++ b/tests/nitg.args
@@ -5,3 +5,4 @@
--global ../examples/hello_world.nit -m test_mixin.nit -o out/nitg-hello_world_mixed ; out/nitg-hello_world_mixed
--separate ../examples/hello_world.nit -m test_mixin.nit -o out/nitgs-hello_world_mixed ; out/nitgs-hello_world_mixed
base_simple_import.nit base_simple.nit --dir out/ ; out/base_simple ; out/base_simple_import
+test_define.nit -D text=hello -D num=42 -D flag --dir out/ ; out/test_define
diff --git a/tests/niti.skip b/tests/niti.skip
index c052cff..baf5b76 100644
--- a/tests/niti.skip
+++ b/tests/niti.skip
@@ -5,6 +5,7 @@ shoot_logic
bench_
nit_args1
nit_args3
+nit_args4
nitvm_args1
nitvm_args3
nitc_args1
@@ -12,6 +13,7 @@ nitg_args1
nitg_args3
nitg_args5
nitg_args6
+nitg_args8
test_markdown_args1
pep8analysis
nitcc_parser_gen
diff --git a/tests/sav/base_eq_null_notnull.res b/tests/sav/base_eq_null_notnull.res
index 41a85bf..b4226bc 100644
--- a/tests/sav/base_eq_null_notnull.res
+++ b/tests/sav/base_eq_null_notnull.res
@@ -1,3 +1,5 @@
+base_eq_null_notnull.nit:36,6--14: Warning: expression is not null, since it is a `A`.
+base_eq_null_notnull.nit:43,2--10: Warning: expression is not null, since it is a `A`.
true
true
true
diff --git a/tests/sav/base_for_finish.res b/tests/sav/base_for_finish.res
new file mode 100644
index 0000000..07ea0b2
--- /dev/null
+++ b/tests/sav/base_for_finish.res
@@ -0,0 +1,17 @@
+1
+2
+3
+0
+
+1
+100
+2
+0
+
+1
+10
+20
+100
+2
+10
+0
diff --git a/tests/sav/base_init_auto_refine.res b/tests/sav/base_init_auto_refine.res
new file mode 100644
index 0000000..445bff9
--- /dev/null
+++ b/tests/sav/base_init_auto_refine.res
@@ -0,0 +1,2 @@
+A2
+-2
diff --git a/tests/sav/base_var_type_evolution_null3.res b/tests/sav/base_var_type_evolution_null3.res
index a556a0a..46069e8 100644
--- a/tests/sav/base_var_type_evolution_null3.res
+++ b/tests/sav/base_var_type_evolution_null3.res
@@ -1,3 +1,4 @@
+base_var_type_evolution_null3.nit:52,5--13: Warning: expression is not null, since it is a `Object`.
1
1
5
diff --git a/tests/sav/base_var_type_evolution_null3_alt1.res b/tests/sav/base_var_type_evolution_null3_alt1.res
index a556a0a..a10a5e3 100644
--- a/tests/sav/base_var_type_evolution_null3_alt1.res
+++ b/tests/sav/base_var_type_evolution_null3_alt1.res
@@ -1,3 +1,4 @@
+alt/base_var_type_evolution_null3_alt1.nit:52,5--13: Warning: expression is not null, since it is a `Object`.
1
1
5
diff --git a/tests/sav/base_vararg3.res b/tests/sav/base_vararg3.res
new file mode 100644
index 0000000..7d434e8
--- /dev/null
+++ b/tests/sav/base_vararg3.res
@@ -0,0 +1,6 @@
+1
+2
+a3
+b3
+c4
+d5
diff --git a/tests/sav/base_vararg3_alt1.res b/tests/sav/base_vararg3_alt1.res
new file mode 100644
index 0000000..1e24ee6
--- /dev/null
+++ b/tests/sav/base_vararg3_alt1.res
@@ -0,0 +1 @@
+alt/base_vararg3_alt1.nit:41,7--13: Type error: expected Int, got Array[Int]
diff --git a/tests/sav/base_vararg3_alt2.res b/tests/sav/base_vararg3_alt2.res
new file mode 100644
index 0000000..52bce29
--- /dev/null
+++ b/tests/sav/base_vararg3_alt2.res
@@ -0,0 +1 @@
+alt/base_vararg3_alt2.nit:42,7: Type error: expected Array[Int], got Int
diff --git a/tests/sav/base_vararg3_alt3.res b/tests/sav/base_vararg3_alt3.res
new file mode 100644
index 0000000..e7e44bc
--- /dev/null
+++ b/tests/sav/base_vararg3_alt3.res
@@ -0,0 +1 @@
+alt/base_vararg3_alt3.nit:33,9: Type error: expected Int, got Array[Int]
diff --git a/tests/sav/base_vararg3_alt4.res b/tests/sav/base_vararg3_alt4.res
new file mode 100644
index 0000000..caca43b
--- /dev/null
+++ b/tests/sav/base_vararg3_alt4.res
@@ -0,0 +1 @@
+alt/base_vararg3_alt4.nit:34,9: Type error: expected Array[Int], got Int
diff --git a/tests/sav/nit_args4.res b/tests/sav/nit_args4.res
new file mode 100644
index 0000000..483d841
--- /dev/null
+++ b/tests/sav/nit_args4.res
@@ -0,0 +1,3 @@
+hello
+42
+true
diff --git a/tests/sav/nitg-e/fixme/base_for_finish.res b/tests/sav/nitg-e/fixme/base_for_finish.res
new file mode 100644
index 0000000..390c4e4
--- /dev/null
+++ b/tests/sav/nitg-e/fixme/base_for_finish.res
@@ -0,0 +1,16 @@
+1
+2
+3
+0
+
+1
+100
+2
+0
+
+1
+10
+20
+100
+2
+10
diff --git a/tests/sav/nitg-g/fixme/base_for_finish.res b/tests/sav/nitg-g/fixme/base_for_finish.res
new file mode 100644
index 0000000..390c4e4
--- /dev/null
+++ b/tests/sav/nitg-g/fixme/base_for_finish.res
@@ -0,0 +1,16 @@
+1
+2
+3
+0
+
+1
+100
+2
+0
+
+1
+10
+20
+100
+2
+10
diff --git a/tests/sav/nitg-s/fixme/base_for_finish.res b/tests/sav/nitg-s/fixme/base_for_finish.res
new file mode 100644
index 0000000..390c4e4
--- /dev/null
+++ b/tests/sav/nitg-s/fixme/base_for_finish.res
@@ -0,0 +1,16 @@
+1
+2
+3
+0
+
+1
+100
+2
+0
+
+1
+10
+20
+100
+2
+10
diff --git a/tests/sav/nitg-sg/fixme/base_for_finish.res b/tests/sav/nitg-sg/fixme/base_for_finish.res
new file mode 100644
index 0000000..390c4e4
--- /dev/null
+++ b/tests/sav/nitg-sg/fixme/base_for_finish.res
@@ -0,0 +1,16 @@
+1
+2
+3
+0
+
+1
+100
+2
+0
+
+1
+10
+20
+100
+2
+10
diff --git a/tests/sav/nitg_args8.res b/tests/sav/nitg_args8.res
new file mode 100644
index 0000000..483d841
--- /dev/null
+++ b/tests/sav/nitg_args8.res
@@ -0,0 +1,3 @@
+hello
+42
+true
diff --git a/tests/sav/niti/error_needed_method_alt3.res b/tests/sav/niti/error_needed_method_alt3.res
deleted file mode 100644
index 34dd8c9..0000000
--- a/tests/sav/niti/error_needed_method_alt3.res
+++ /dev/null
@@ -1 +0,0 @@
-alt/error_needed_method_alt3.nit:48,9--13: Fatal Error: NativeString must have a property named to_s.
diff --git a/tests/sav/niti/error_needed_method_alt4.res b/tests/sav/niti/error_needed_method_alt4.res
index 4daa384..d1e2d76 100644
--- a/tests/sav/niti/error_needed_method_alt4.res
+++ b/tests/sav/niti/error_needed_method_alt4.res
@@ -1 +1 @@
-alt/error_needed_method_alt4.nit:49,10--14: Fatal Error: NativeString must have a property named to_s.
+alt/error_needed_method_alt4.nit:49,10--14: Fatal Error: NativeString must have a property named to_s_with_length.
diff --git a/tests/sav/nitmetrics_args1.res b/tests/sav/nitmetrics_args1.res
index e706f2c..481e468 100644
--- a/tests/sav/nitmetrics_args1.res
+++ b/tests/sav/nitmetrics_args1.res
@@ -257,7 +257,7 @@
## Module importation hierarchy
Number of nodes: 1
Number of edges: 1 (1.00 per node)
-Number of direct edges: 0 (0.0 per node)
+Number of direct edges: 0 (0.00 per node)
Distribution of greaters
population: 1
minimum value: 1
@@ -271,7 +271,7 @@ Distribution of direct greaters
minimum value: 0
maximum value: 0
total value: 0
- average value: 0.0
+ average value: 0.00
distribution:
<=0: sub-population=1 (100.00%); cumulated value=0 (na%)
Distribution of smallers
@@ -287,7 +287,7 @@ Distribution of direct smallers
minimum value: 0
maximum value: 0
total value: 0
- average value: 0.0
+ average value: 0.00
distribution:
<=0: sub-population=1 (100.00%); cumulated value=0 (na%)
## Classdef hierarchy
@@ -310,7 +310,7 @@ Distribution of direct greaters
total value: 6
average value: 0.85
distribution:
- <=0: sub-population=1 (14.28%); cumulated value=0 (0.0%)
+ <=0: sub-population=1 (14.28%); cumulated value=0 (0.00%)
<=1: sub-population=6 (85.71%); cumulated value=6 (100.00%)
Distribution of smallers
population: 7
@@ -328,7 +328,7 @@ Distribution of direct smallers
total value: 6
average value: 0.85
distribution:
- <=0: sub-population=6 (85.71%); cumulated value=0 (0.0%)
+ <=0: sub-population=6 (85.71%); cumulated value=0 (0.00%)
<=8: sub-population=1 (14.28%); cumulated value=6 (100.00%)
## Class hierarchy
Number of nodes: 7
@@ -350,7 +350,7 @@ Distribution of direct greaters
total value: 6
average value: 0.85
distribution:
- <=0: sub-population=1 (14.28%); cumulated value=0 (0.0%)
+ <=0: sub-population=1 (14.28%); cumulated value=0 (0.00%)
<=1: sub-population=6 (85.71%); cumulated value=6 (100.00%)
Distribution of smallers
population: 7
@@ -368,7 +368,7 @@ Distribution of direct smallers
total value: 6
average value: 0.85
distribution:
- <=0: sub-population=6 (85.71%); cumulated value=0 (0.0%)
+ <=0: sub-population=6 (85.71%); cumulated value=0 (0.00%)
<=8: sub-population=1 (14.28%); cumulated value=6 (100.00%)
--- AST Metrics ---
## All nodes of the AST
@@ -449,8 +449,8 @@ Number of classes: 7
Number of class kind: 4 (57.14%)
Number of class definitions: 7
-Number of refined classes: 0 (0.0%)
-Average number of class refinments by classes: 0.0
+Number of refined classes: 0 (0.00%)
+Average number of class refinments by classes: 0.00
Average number of class refinments by refined classes: na
Number of properties: 18
@@ -714,8 +714,8 @@ Statistics of type usage:
sum: 0
--- Sends on Nullable Receiver ---
Total number of sends: 19
-Number of sends on a nullable receiver: 0 (0.0%)
-Number of buggy sends (cannot determine the type of the receiver): 0 (0.0%)
+Number of sends on a nullable receiver: 0 (0.00%)
+Number of buggy sends (cannot determine the type of the receiver): 0 (0.00%)
# RTA metrics
diff --git a/tests/sav/test_define.res b/tests/sav/test_define.res
new file mode 100644
index 0000000..8d40171
--- /dev/null
+++ b/tests/sav/test_define.res
@@ -0,0 +1,3 @@
+some text
+1
+false
diff --git a/tests/sav/test_for_abuse.res b/tests/sav/test_for_abuse.res
index 51ef296..f2856be 100644
--- a/tests/sav/test_for_abuse.res
+++ b/tests/sav/test_for_abuse.res
@@ -1 +1,4 @@
# This file is part of NIT ( http://www.nitlanguage.org ).
+f is closed? false
+f is closed? true
+* ** **** *******
diff --git a/tests/sav/test_hash_debug.res b/tests/sav/test_hash_debug.res
index 9748c49..b52a9c5 100644
--- a/tests/sav/test_hash_debug.res
+++ b/tests/sav/test_hash_debug.res
@@ -6,9 +6,9 @@ false
~~~Hash statistics~~~
GET:
number of get and has_key: 1
-number of collisions: 0 (0.0%)
+number of collisions: 0 (0.00%)
average length of collisions: NA
-average length of considered collections: 0.0
+average length of considered collections: 0.00
average capacity of considered collections: 1.00 (NA%)
STORE:
@@ -21,47 +21,47 @@ average capacity or considered collections: NA (NA%)
~~~Hash statistics~~~
GET:
number of get and has_key: 2
-number of collisions: 0 (0.0%)
+number of collisions: 0 (0.00%)
average length of collisions: NA
-average length of considered collections: 0.0
+average length of considered collections: 0.00
average capacity of considered collections: 1.00 (NA%)
STORE:
number of stores: 1
-number of collisions: 0 (0.0%)
+number of collisions: 0 (0.00%)
average length of collisions: NA
-average length of considered collections: 0.0
+average length of considered collections: 0.00
average capacity or considered collections: 1.00 (NA%)
~~~~~~
~~~Hash statistics~~~
GET:
number of get and has_key: 3
-number of collisions: 0 (0.0%)
+number of collisions: 0 (0.00%)
average length of collisions: NA
average length of considered collections: 0.33
average capacity of considered collections: 6.33 (1900.00%)
STORE:
number of stores: 1
-number of collisions: 0 (0.0%)
+number of collisions: 0 (0.00%)
average length of collisions: NA
-average length of considered collections: 0.0
+average length of considered collections: 0.00
average capacity or considered collections: 1.00 (NA%)
~~~~~~
true
~~~Hash statistics~~~
GET:
number of get and has_key: 4
-number of collisions: 0 (0.0%)
+number of collisions: 0 (0.00%)
average length of collisions: NA
average length of considered collections: 0.50
average capacity of considered collections: 9.00 (1800.00%)
STORE:
number of stores: 1
-number of collisions: 0 (0.0%)
+number of collisions: 0 (0.00%)
average length of collisions: NA
-average length of considered collections: 0.0
+average length of considered collections: 0.00
average capacity or considered collections: 1.00 (NA%)
~~~~~~
@@ -70,22 +70,22 @@ false
~~~Hash statistics~~~
GET:
number of get and has_key: 5
-number of collisions: 0 (0.0%)
+number of collisions: 0 (0.00%)
average length of collisions: NA
average length of considered collections: 0.60
average capacity of considered collections: 10.60 (1766.67%)
STORE:
number of stores: 1
-number of collisions: 0 (0.0%)
+number of collisions: 0 (0.00%)
average length of collisions: NA
-average length of considered collections: 0.0
+average length of considered collections: 0.00
average capacity or considered collections: 1.00 (NA%)
~~~~~~
~~~Hash statistics~~~
GET:
number of get and has_key: 6
-number of collisions: 0 (0.0%)
+number of collisions: 0 (0.00%)
average length of collisions: NA
average length of considered collections: 0.67
average capacity of considered collections: 11.67 (1750.00%)
diff --git a/tests/sav/test_toolcontext_args1.res b/tests/sav/test_toolcontext_args1.res
index 5e997e3..800327a 100644
--- a/tests/sav/test_toolcontext_args1.res
+++ b/tests/sav/test_toolcontext_args1.res
@@ -5,7 +5,7 @@ _DUMMY_TOOL()
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
prev="${COMP_WORDS[COMP_CWORD-1]}"
- opts="--warn --warning --quiet --stop-on-first-error --no-color --log --log-dir --help --version --set-dummy-tool --verbose --bash-completion --option-a --option-b"
+ opts="--warn --warning --quiet --stop-on-first-error --no-color --log --log-dir --help --version --set-dummy-tool --verbose --bash-completion --stub-man --option-a --option-b"
if [[ ${cur} == -* ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
return 0
diff --git a/tests/sav/test_toolcontext_args2.res b/tests/sav/test_toolcontext_args2.res
index 8757721..91fa2fa 100644
--- a/tests/sav/test_toolcontext_args2.res
+++ b/tests/sav/test_toolcontext_args2.res
@@ -12,6 +12,7 @@ Test for ToolContext, try --bash-completion.
--set-dummy-tool Set toolname and version to DUMMY. Useful for testing
-v, --verbose Verbose
--bash-completion Generate bash_completion file for this program
+ --stub-man Generate a stub manpage in pandoc markdown format
-a, --option-a option a, do nothing
-b, --option-b option b, do nothing
-c option c, do nothing
diff --git a/tests/test_define.nit b/tests/test_define.nit
new file mode 100644
index 0000000..4b8ebc7
--- /dev/null
+++ b/tests/test_define.nit
@@ -0,0 +1,20 @@
+# 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 text: String do return "some text"
+fun num: Int do return 1
+fun flag: Bool do return false
+print text
+print num
+print flag
diff --git a/tests/test_for_abuse.nit b/tests/test_for_abuse.nit
index 545440b..cae1cd1 100644
--- a/tests/test_for_abuse.nit
+++ b/tests/test_for_abuse.nit
@@ -14,12 +14,21 @@
import for_abuse
+var escape_f: nullable IStream = null
for f in file_open("test_for_abuse.nit") do
+ escape_f = f
print f.read_line
+ print "f is closed? {f.eof}"
end
+print "f is closed? {escape_f.eof}"
var array = ["*", "****", "**", "*******"]
for q in array.sort_fa do
- q.res = q.b.length <=> q.b.length
+ # IN:
+ # q.a
+ # q-b
+ # OUT
+ # q.res
+ q.res = q.a.length <=> q.b.length
end
-
+print array.join(" ")
diff --git a/tests/test_jvm.nit b/tests/test_jvm.nit
index b070f63..8b49b8b 100644
--- a/tests/test_jvm.nit
+++ b/tests/test_jvm.nit
@@ -128,15 +128,10 @@ if test.address_is_null then env.print_error("object test not initialized")
# Retrieve field value with field ids
var v_bool = env.get_boolean_field(test, f_bool)
-if v_bool == null then env.print_error("vbool not found")
var v_char = env.get_char_field(test, f_char)
-if v_char == null then env.print_error("vchar not found")
var v_i = env.get_int_field(test, f_i)
-if v_i == null then env.print_error("vi not found")
var v_f = env.get_float_field(test, f_f)
-if v_f == null then env.print_error("vf not found")
var v_test1 = env.get_object_field(test, f_test)
-if v_test1 == null then env.print_error("vtest1 not found")
# Set the new values for the fields
env.set_boolean_field(test, f_bool, true)
@@ -151,7 +146,6 @@ v_char = env.call_char_method(test, m_char, null)
v_i = env.call_int_method(test, m_i, null)
v_f = env.call_float_method(test, m_f, null)
var v_test2 = env.call_object_method(test, m_test, null)
-if v_test2 == null then env.print_error("vtest2 not found")
# assert the values of the fields
print v_bool
diff --git a/tests/tests.sh b/tests/tests.sh
index 32afdf0..14be6d4 100755
--- a/tests/tests.sh
+++ b/tests/tests.sh
@@ -36,6 +36,9 @@ paths=($paths)
JNI_LIB_PATH=${paths[0]}
shopt -u nullglob
+outdir="out"
+compdir=".nit_compile"
+
usage()
{
e=`basename "$0"`
@@ -46,9 +49,74 @@ Usage: $e [options] modulenames
-h This help
--engine Use a specific engine (default=nitg)
--noskip Do not skip a test even if the .skip file matches
+--outdir Use a specific output folder (default=out/)
+--compdir Use a specific temporary compilation folder (default=.nit_compile)
+--node Run as a node in parallel, will not output context information
END
}
+# Run a command with a timeout and a time count.
+# Options:
+# -o file write the user time into file (REQUIRED). see `-o` in `man time`
+# -a append the time to the file (instead of overwriting it). see `-a` in `man time`
+saferun()
+{
+ local stop=false
+ local o=
+ local a=
+ while [ $stop = false ]; do
+ case $1 in
+ -o) o="$2"; shift; shift;;
+ -a) a="-a"; shift;;
+ *) stop=true
+ esac
+ done
+ if test -n "$TIME"; then
+ $TIME -o "$o" $a $TIMEOUT "$@"
+ else
+ $TIMEOUT "$@"
+ if test -n "$a"; then echo 0 >> "$o"; else echo 0 > "$o"; fi
+ fi
+}
+
+# Output a timestamp attribute for XML, or an empty line
+timestamp()
+{
+ if test -n "$TIMESTAMP"; then
+ echo "timestamp='`$TIMESTAMP`'"
+ else
+ echo ""
+ fi
+
+}
+
+# Get platform specific commands ##########################
+
+# Detect a working timeout
+if sh -c "timelimit echo" 1>/dev/null 2>&1; then
+ TIMEOUT="timelimit -t 600"
+elif sh -c "timeout 1 echo" 1>/dev/null 2>&1; then
+ TIMEOUT="timeout 600s"
+else
+ echo "No timelimit or timeout command detected. Tests may hang :("
+fi
+
+# Detect a working time command
+if env time --quiet -f%U true 2>/dev/null; then
+ TIME="env time --quiet -f%U"
+elif env time -f%U true 2>/dev/null; then
+ TIME="env time -f%U"
+else
+ TIME=
+fi
+
+# Detect a working date command
+if date -Iseconds >/dev/null 2>&1; then
+ TIMESTAMP="date -Iseconds"
+else
+ TIMESTAMP=
+fi
+
# $1 is the pattern of the test
# $2 is the file to compare to
# the result is:
@@ -62,15 +130,15 @@ function compare_to_result()
local sav="$2"
if [ ! -r "$sav" ]; then return 0; fi
test "`cat "$sav"`" = "UNDEFINED" && return 1
- diff -u "$sav" "out/$pattern.res" > "out/$pattern.diff.sav.log"
+ diff -u "$sav" "$outdir/$pattern.res" > "$outdir/$pattern.diff.sav.log"
if [ "$?" == 0 ]; then
return 1
fi
- sed '/[Ww]arning/d;/[Ee]rror/d' "out/$pattern.res" > "out/$pattern.res2"
- sed '/[Ww]arning/d;/[Ee]rror/d' "$sav" > "out/$pattern.sav2"
- grep '[Ee]rror' "out/$pattern.res" >/dev/null && echo "Error" >> "out/$pattern.res2"
- grep '[Ee]rror' "$sav" >/dev/null && echo "Error" >> "out/$pattern.sav2"
- diff -u "out/$pattern.sav2" "out/$pattern.res2" > "out/$pattern.diff.sav.log2"
+ sed '/[Ww]arning/d;/[Ee]rror/d' "$outdir/$pattern.res" > "$outdir/$pattern.res2"
+ sed '/[Ww]arning/d;/[Ee]rror/d' "$sav" > "$outdir/$pattern.sav2"
+ grep '[Ee]rror' "$outdir/$pattern.res" >/dev/null && echo "Error" >> "$outdir/$pattern.res2"
+ grep '[Ee]rror' "$sav" >/dev/null && echo "Error" >> "$outdir/$pattern.sav2"
+ diff -u "$outdir/$pattern.sav2" "$outdir/$pattern.res2" > "$outdir/$pattern.diff.sav.log2"
if [ "$?" == 0 ]; then
return 2
else
@@ -96,7 +164,7 @@ function process_result()
OLD=""
LIST=""
FIRST=""
- echo >>$xml ""
+ echo >>$xml ""
#for sav in "sav/$engine/fixme/$pattern.res" "sav/$engine/$pattern.res" "sav/fixme/$pattern.res" "sav/$pattern.res" "sav/$pattern.sav"; do
for savdir in $savdirs; do
sav=$savdir/fixme/$pattern.res
@@ -152,79 +220,79 @@ function process_result()
esac
done
OLD=`echo "$OLD" | sed -e 's/ */ /g' -e 's/^ //' -e 's/ $//'`
- grep 'NOT YET IMPLEMENTED' "out/$pattern.res" >/dev/null
+ grep 'NOT YET IMPLEMENTED' "$outdir/$pattern.res" >/dev/null
NYI="$?"
if [ -n "$SAV" ]; then
if [ -n "$OLD" ]; then
- echo "[*ok*] out/$pattern.res $SAV - but $OLD remains!"
- echo >>$xml ""
+ echo "[*ok*] $outdir/$pattern.res $SAV - but $OLD remains!"
+ echo >>$xml ""
remains="$remains $OLD"
else
- echo "[ok] out/$pattern.res $SAV"
+ echo "[ok] $outdir/$pattern.res $SAV"
fi
ok="$ok $pattern"
elif [ -n "$FIXME" ]; then
if [ -n "$OLD" ]; then
- echo "[*fixme*] out/$pattern.res $FIXME - but $OLD remains!"
- echo >>$xml ""
+ echo "[*fixme*] $outdir/$pattern.res $FIXME - but $OLD remains!"
+ echo >>$xml ""
remains="$remains $OLD"
else
- echo "[fixme] out/$pattern.res $FIXME"
+ echo "[fixme] $outdir/$pattern.res $FIXME"
echo >>$xml ""
fi
todos="$todos $pattern"
elif [ "x$NYI" = "x0" ]; then
- echo "[todo] out/$pattern.res -> not yet implemented"
+ echo "[todo] $outdir/$pattern.res -> not yet implemented"
echo >>$xml ""
todos="$todos $pattern"
elif [ -n "$SOSO" ]; then
- echo "[======= soso out/$pattern.res $SOSO =======]"
- echo >>$xml ""
+ echo "[======= soso $outdir/$pattern.res $SOSO =======]"
+ echo >>$xml ""
echo >>$xml ">$xml -n 50
+ cat -v $outdir/$pattern.diff.sav.log | head >>$xml -n 50
echo >>$xml "]]>"
nok="$nok $pattern"
echo "$ii" >> "$ERRLIST"
elif [ -n "$SOSOF" ]; then
- echo "[======= fixme soso out/$pattern.res $SOSOF =======]"
- echo >>$xml ""
+ echo "[======= fixme soso $outdir/$pattern.res $SOSOF =======]"
+ echo >>$xml ""
echo >>$xml ">$xml -n 50
+ cat -v $outdir/$pattern.diff.sav.log | head >>$xml -n 50
echo >>$xml "]]>"
nok="$nok $pattern"
echo "$ii" >> "$ERRLIST"
elif [ -n "$NSAV" ]; then
- echo "[======= fail out/$pattern.res $NSAV =======]"
- echo >>$xml ""
+ echo "[======= fail $outdir/$pattern.res $NSAV =======]"
+ echo >>$xml ""
echo >>$xml ">$xml -n 50
+ cat -v $outdir/$pattern.diff.sav.log | head >>$xml -n 50
echo >>$xml "]]>"
nok="$nok $pattern"
echo "$ii" >> "$ERRLIST"
elif [ -n "$NFIXME" ]; then
- echo "[======= changed out/$pattern.res $NFIXME ======]"
- echo >>$xml ""
+ echo "[======= changed $outdir/$pattern.res $NFIXME ======]"
+ echo >>$xml ""
echo >>$xml ">$xml -n 50
+ cat -v $outdir/$pattern.diff.sav.log | head >>$xml -n 50
echo >>$xml "]]>"
nok="$nok $pattern"
echo "$ii" >> "$ERRLIST"
- elif [ -s out/$pattern.res ]; then
- echo "[=== no sav ===] out/$pattern.res is not empty"
+ elif [ -s $outdir/$pattern.res ]; then
+ echo "[=== no sav ===] $outdir/$pattern.res is not empty"
echo >>$xml ""
echo >>$xml ">$xml out/$pattern.res
+ cat -v >>$xml $outdir/$pattern.res
echo >>$xml "]]>"
nos="$nos $pattern"
echo "$ii" >> "$ERRLIST"
else
# no sav but empty res
- echo "[0k] out/$pattern.res is empty"
+ echo "[0k] $outdir/$pattern.res is empty"
ok="$ok $pattern"
fi
- if test -s out/$pattern.cmp.err; then
+ if test -s $outdir/$pattern.cmp.err; then
echo >>$xml ">$xml out/$pattern.cmp.err
+ cat -v >>$xml $outdir/$pattern.cmp.err
echo >>$xml "]]>"
fi
echo >>$xml ""
@@ -235,12 +303,12 @@ need_skip()
test "$noskip" = true && return 1
if echo "$1" | grep -f "$engine.skip" >/dev/null 2>&1; then
echo "=> $2: [skip]"
- echo >>$xml ""
+ echo >>$xml ""
return 0
fi
if test -n "$isinterpret" && echo "$1" | grep -f "exec.skip" >/dev/null 2>&1; then
echo "=> $2: [skip exec]"
- echo >>$xml ""
+ echo >>$xml ""
return 0
fi
return 1
@@ -273,11 +341,14 @@ find_nitc()
echo "Could not find binary for engine $engine, aborting"
exit 1
fi
- echo "Find binary for engine $engine: $recent $OPT"
+ if [ "x$isnode" = "xfalse" ]; then
+ echo "Found binary for engine $engine: $recent $OPT"
+ fi
NITC=$recent
}
verbose=false
+isnode=false
stop=false
engine=nitg
noskip=
@@ -289,6 +360,9 @@ while [ $stop = false ]; do
-h) usage; exit;;
--engine) engine="$2"; shift; shift;;
--noskip) noskip=true; shift;;
+ --outdir) outdir="$2"; shift; shift;;
+ --compdir) compdir="$2"; shift; shift;;
+ --node) isnode=true; shift;;
*) stop=true
esac
done
@@ -298,23 +372,23 @@ case $engine in
nitg)
engine=nitg-s;
enginebinname=nitg;
- OPT="--separate $OPT"
+ OPT="--separate $OPT --compile-dir $compdir"
;;
nitg-s)
enginebinname=nitg;
- OPT="--separate $OPT"
+ OPT="--separate $OPT --compile-dir $compdir"
;;
nitg-e)
enginebinname=nitg;
- OPT="--erasure $OPT"
+ OPT="--erasure $OPT --compile-dir $compdir"
;;
nitg-sg)
enginebinname=nitg;
- OPT="--semi-global $OPT"
+ OPT="--semi-global $OPT --compile-dir $compdir"
;;
nitg-g)
enginebinname=nitg;
- OPT="--global $OPT"
+ OPT="--global $OPT --compile-dir $compdir"
;;
nit)
engine=niti
@@ -330,7 +404,7 @@ case $engine in
;;
emscripten)
enginebinname=nitg
- OPT="-m emscripten_nodejs.nit --semi-global $OPT"
+ OPT="-m emscripten_nodejs.nit --semi-global $OPT --compile-dir $compdir"
savdirs="sav/nitg-sg/"
;;
nitc)
@@ -351,30 +425,26 @@ savdirs="sav/$engine $savdirs sav/"
# Set NIT_DIR if needed
[ -z "$NIT_DIR" ] && export NIT_DIR=..
-if sh -c "timelimit echo" 1>/dev/null 2>&1; then
- TIMEOUT="timelimit -t 600"
-elif sh -c "timeout 1 echo" 1>/dev/null 2>&1; then
- TIMEOUT="timeout 600s"
-else
- echo "No timelimit or timeout command detected. Tests may hang :("
-fi
-
# Mark to distinguish files among tests
# MARK=
-# File where error tests are outputed
-# Old ERRLIST is backuped
-ERRLIST=${ERRLIST:-errlist}
-ERRLIST_TARGET=$ERRLIST
-
if [ $# = 0 ]; then
usage;
exit
fi
+# CLEAN the out directory
+rm -rf "$outdir/" 2>/dev/null
+mkdir "$outdir" 2>/dev/null
+
+# File where error tests are outputed
+# Old ERRLIST is backuped
+ERRLIST=${ERRLIST:-errlist}
+ERRLIST_TARGET=$ERRLIST
+
# Initiate new ERRLIST
if [ "x$ERRLIST" = "x" ]; then
- ERRLIST=/dev=null
+ ERRLIST=/dev/null
else
ERRLIST=$ERRLIST.tmp
> "$ERRLIST"
@@ -383,12 +453,14 @@ fi
ok=""
nok=""
todos=""
-xml="tests-$engine.xml"
-echo >$xml ""
-# CLEAN the out directory
-rm -rf out/ 2>/dev/null
-mkdir out 2>/dev/null
+if [ "x$XMLDIR" = "x" ]; then
+ xml="tests-$engine.xml"
+else
+ xml="$XMLDIR/tests-$engine.xml"
+fi
+
+echo >$xml ""
for ii in "$@"; do
if [ ! -f $ii ]; then
@@ -411,7 +483,7 @@ for ii in "$@"; do
for i in "$ii" `./alterner.pl --start '#' --altsep '_' $ii`; do
bf=`basename $i .nit`
- ff="out/$bf"
+ ff="$outdir/$bf"
# Sould we skip the alternative for this engine?
need_skip $bf $bf $pack && continue
@@ -432,10 +504,10 @@ for ii in "$@"; do
fi
if [ -n "$isinterpret" ]; then
- cat > "./$ff.bin" < "$ff.bin" < "$ff.cmp.err"
> "$ff.compile.log"
ERR=0
@@ -452,7 +524,7 @@ END
echo $NITC --no-color $OPT -o "$ffout" "$i" "$includes" $nocc
fi
NIT_NO_STACK=1 JNI_LIB_PATH=$JNI_LIB_PATH JAVA_HOME=$JAVA_HOME \
- /usr/bin/time --quiet -f%U -o "$ff.time.out" $TIMEOUT $NITC --no-color $OPT -o "$ffout" "$i" $includes $nocc 2> "$ff.cmp.err" > "$ff.compile.log"
+ saferun -o "$ff.time.out" $NITC --no-color $OPT -o "$ffout" "$i" $includes $nocc 2> "$ff.cmp.err" > "$ff.compile.log"
ERR=$?
if [ "x$verbose" = "xtrue" ]; then
cat "$ff.compile.log"
@@ -460,11 +532,11 @@ END
fi
fi
if [ "$engine" = "emscripten" ]; then
- echo > "./$ff.bin" "nodejs $ffout \"\$@\""
+ echo > "$ff.bin" "nodejs $ffout \"\$@\""
chmod +x "$ff.bin"
if grep "Fatal Error: more than one primitive class" "$ff.compile.log" > /dev/null; then
echo " [skip] do no not imports kernel"
- echo >>$xml ""
+ echo >>$xml ""
continue
fi
fi
@@ -477,7 +549,7 @@ END
echo -n "nocc "
> "$ff.res"
process_result $bf $bf $pack
- elif [ -x "./$ff.bin" ]; then
+ elif [ -x "$ff.bin" ]; then
if skip_exec "$bf"; then
# No exec
> "$ff.res"
@@ -489,10 +561,10 @@ END
args=""
if [ "x$verbose" = "xtrue" ]; then
echo ""
- echo "NIT_NO_STACK=1 ./$ff.bin" $args
- fi
+ echo "NIT_NO_STACK=1 $ff.bin" $args
+ fi
NIT_NO_STACK=1 LD_LIBRARY_PATH=$JNI_LIB_PATH \
- /usr/bin/time --quiet -f%U -a -o "$ff.time.out" $TIMEOUT "./$ff.bin" $args < "$inputs" > "$ff.res" 2>"$ff.err"
+ saferun -a -o "$ff.time.out" "$ff.bin" $args < "$inputs" > "$ff.res" 2>"$ff.err"
mv $ff.time.out $ff.times.out
awk '{ SUM += $1} END { print SUM }' $ff.times.out > $ff.time.out
@@ -532,12 +604,12 @@ END
rm -rf "$fff.res" "$fff.err" "$fff.write" 2> /dev/null
if [ "x$verbose" = "xtrue" ]; then
echo ""
- echo "NIT_NO_STACK=1 ./$ff.bin" $args
+ echo "NIT_NO_STACK=1 $ff.bin" $args
fi
echo -n "==> $name "
- echo "./$ff.bin $args" > "./$fff.bin"
- chmod +x "./$fff.bin"
- WRITE="$fff.write" /usr/bin/time --quiet -f%U -o "$fff.time.out" sh -c "NIT_NO_STACK=1 $TIMEOUT ./$fff.bin < $ffinputs > $fff.res 2>$fff.err"
+ echo "$ff.bin $args" > "$fff.bin"
+ chmod +x "$fff.bin"
+ WRITE="$fff.write" saferun -o "$fff.time.out" sh -c "NIT_NO_STACK=1 $fff.bin < $ffinputs > $fff.res 2>$fff.err"
if [ "x$verbose" = "xtrue" ]; then
cat "$fff.res"
cat >&2 "$fff.err"
@@ -554,7 +626,7 @@ END
process_result $bff " $name" $pack
done < $fargs
fi
- elif [ -f "./$ff.bin" ]; then
+ elif [ -f "$ff.bin" ]; then
#Not executable (platform?)"
> "$ff.res"
process_result $bf "$bf" $pack
@@ -567,21 +639,23 @@ END
done
done
-echo "engine: $engine ($enginebinname $OPT)"
-echo "ok: " `echo $ok | wc -w` "/" `echo $ok $nok $nos $todos | wc -w`
+if [ "x$isnode" = "xfalse" ]; then
+ echo "engine: $engine ($enginebinname $OPT)"
+ echo "ok: " `echo $ok | wc -w` "/" `echo $ok $nok $nos $todos | wc -w`
-if [ -n "$nok" ]; then
- echo "fail: $nok"
- echo "There were $(echo $nok | wc -w) errors ! (see file $ERRLIST)"
-fi
-if [ -n "$nos" ]; then
- echo "no sav: $nos"
-fi
-if [ -n "$todos" ]; then
- echo "todo/fixme: $todos"
-fi
-if [ -n "$remains" ]; then
- echo "sav that remains: $remains"
+ if [ -n "$nok" ]; then
+ echo "fail: $nok"
+ echo "There were $(echo $nok | wc -w) errors ! (see file $ERRLIST)"
+ fi
+ if [ -n "$nos" ]; then
+ echo "no sav: $nos"
+ fi
+ if [ -n "$todos" ]; then
+ echo "todo/fixme: $todos"
+ fi
+ if [ -n "$remains" ]; then
+ echo "sav that remains: $remains"
+ fi
fi
# write $ERRLIST