Merge: new `with` statement
authorJean Privat <jean@pryen.org>
Thu, 9 Apr 2015 05:24:37 +0000 (12:24 +0700)
committerJean Privat <jean@pryen.org>
Thu, 9 Apr 2015 05:24:37 +0000 (12:24 +0700)
Introduce the `with` statement that is analogous to the `with` of Python or the `uning` of C#.

~~~nit
with x = something do
   x.work
end
~~~

That is equivalent with

~~~nit
do
   var x = something
   x.start
   x.work
   x.finish
end
~~~

Note that an alternative syntax, without the local variable exists:

~~~nit
with something do
   work
end
~~~

that is used when we want some automatic control or whatever. Eg resource allocation or critical section.

~~~nit
do
   var tmp = something
   tmp.start
   work
   tmp.stop
end
~~~

Most real-world examples could be

~~~nit
with file = path.create do
   file.write("Bla")
end
~~~

and

~~~nit
with a_mutex do
   work
end
~~~

## Names

I reused the `finish` method from Iterator.
I introduced the antonym `start` for the other side.

Note that the `start` is important because it helps the object to know it has to prepare itself for a `finish`.

I did not introduce an interface, mainly because I have no idea for a name. C# names it `IDisposable` and the `finish` method is called `Dispose`. There is no `start` because C# designers are lunatic sometime.

In python there is no interface (obviously) and the method are called
`__enter__` and `__exit__` because Python likes identifiers that resemble words eaten by boas.
Note that the returned variable is not the original expression but the result of `__enter__`.
With the Python semantic, but the Nit syntax, the first example will be equivalent to

~~~nit
do
   var tmp = something
   var x = tmp.start
   x.work
   x.finish
end
~~~

I am not sure of the benefits of the additional complexity, but the the more I thing about it the more I think this could be useful, ex for the control case the `start` can return the handler to `finish`.

The issue is that proposed syntax: `with x = something` does not make sense (because `tmp=something` and `x=tmp.start`) thus should be replaced with something else; Python uses `with something as x:` that we can reuse but I do not want because it is ugly.

An other alternative I tough of was to reuse the `for` keyword. but It is convoluted.
The two previous real world examples will then be

~~~nit
for file = path.create do
   file.write("Bla")
end
~~~

and

~~~nit
for a_mutex do
   work
end
~~~

Pull-Request: #1243
Reviewed-by: Alexis Laferrière <alexis.laf@xymus.net>
Reviewed-by: Etienne M. Gagnon <egagnon@j-meg.com>
Reviewed-by: Lucas Bajolet <r4pass@hotmail.com>

187 files changed:
VERSION
benchmarks/bench_engines.sh
benchmarks/markdown/.gitignore [new file with mode: 0644]
benchmarks/markdown/Makefile [new file with mode: 0644]
benchmarks/markdown/README.md
benchmarks/markdown/bench_markdown.sh
benchmarks/markdown/benches/Makefile
benchmarks/markdown/engines/Makefile
benchmarks/markdown/engines/nitmd/Makefile
benchmarks/markdown/engines/pandoc/Makefile [new file with mode: 0644]
benchmarks/markdown/engines/pandoc/pandoc.hs [new file with mode: 0644]
benchmarks/strings/.gitignore [new file with mode: 0644]
benchmarks/strings/Makefile [new file with mode: 0644]
benchmarks/strings/README.md [new file with mode: 0644]
benchmarks/strings/array_to_s_vars/array_to_s_buffer.nit
benchmarks/strings/array_to_s_vars/array_to_s_flatstr.nit
benchmarks/strings/array_to_s_vars/array_to_s_man_buf.nit
benchmarks/strings/array_to_s_vars/array_to_s_rope.nit
benchmarks/strings/array_to_s_vars/array_to_s_rope_buf.nit [new file with mode: 0644]
benchmarks/strings/bench_strings.sh [moved from benchmarks/bench_strings.sh with 53% similarity]
benchmarks/strings/chain_concat.nit
benchmarks/strings/iteration_bench.nit
benchmarks/strings/substr_bench.nit
benchmarks/strings/utf_chain_concat.nit [deleted file]
benchmarks/strings/utf_iteration_bench.nit [deleted file]
benchmarks/strings/utf_substr_bench.nit [deleted file]
bin/Makefile [new file with mode: 0644]
contrib/benitlux/src/benitlux_daily.nit
contrib/pep8analysis/src/flow_analysis/framework.nit
examples/calculator/src/calculator_android.nit
examples/mnit_dino/src/dino_android.nit
examples/mnit_simple/src/complete_simple_android.nit
lib/ai/examples/puzzle.nit
lib/ai/search.nit
lib/android/README.md
lib/android/aware.nit
lib/android/examples/src/ui_test.nit
lib/app/app_base.nit
lib/geometry/points_and_lines.nit
lib/github/github_curl.nit
lib/html/bootstrap.nit [new file with mode: 0644]
lib/ios/app.nit [new file with mode: 0644]
lib/ios/examples/hello_ios.nit [new file with mode: 0644]
lib/ios/ios.nit [new file with mode: 0644]
lib/ios/platform.nit [new file with mode: 0644]
lib/privileges/privileges.nit [moved from lib/privileges.nit with 100% similarity]
lib/pthreads/examples/threaded_example.nit [new file with mode: 0644]
lib/pthreads/pthreads.nit
lib/standard/collection/abstract_collection.nit
lib/standard/collection/array.nit
lib/standard/collection/sorter.nit
lib/standard/collection/union_find.nit
lib/standard/exec_nit.c
lib/standard/file.nit
lib/standard/string.nit
lib/template/examples/tmpl_composer.nit
src/compiler/abstract_compiler.nit
src/compiler/coloring.nit
src/compiler/compiler.nit
src/compiler/separate_compiler.nit
src/compiler/separate_erasure_compiler.nit
src/doc/doc_base.nit
src/doc/doc_phases/doc_graphs.nit
src/doc/doc_phases/doc_hierarchies.nit
src/doc/doc_phases/doc_html.nit
src/doc/doc_phases/doc_structure.nit
src/doc/html_templates/html_components.nit
src/doc/html_templates/html_model.nit
src/doc/html_templates/html_templates.nit
src/ffi/extern_classes.nit
src/frontend/check_annotation.nit
src/frontend/div_by_zero.nit
src/frontend/frontend.nit
src/frontend/no_warning.nit
src/frontend/parallelization_phase.nit [new file with mode: 0644]
src/frontend/serialization_phase.nit
src/highlight.nit
src/interpreter/naive_interpreter.nit
src/loader.nit
src/metrics/detect_covariance.nit
src/metrics/detect_variance_constraints.nit
src/metrics/rta_metrics.nit
src/model/mmodule.nit
src/model/model.nit
src/modelbuilder.nit
src/modelbuilder_base.nit
src/modelize/modelize_class.nit
src/modelize/modelize_property.nit
src/nitdbg_client.nit
src/nitni/nitni_callbacks.nit
src/parser/.gitignore [new file with mode: 0644]
src/parser/Makefile
src/parser/README.md
src/parser/org/nitlanguage/gen/TestParser.java [new file with mode: 0644]
src/phase.nit
src/platform/android.nit
src/platform/android_annotations.nit
src/platform/app_annotations.nit [new file with mode: 0644]
src/platform/emscripten.nit
src/platform/ios.nit [new file with mode: 0644]
src/platform/pnacl.nit
src/platform/xcode_templates.nit [new file with mode: 0644]
src/rapid_type_analysis.nit
src/semantize/auto_super_init.nit
src/semantize/typing.nit
src/test_phase.nit
src/toolcontext.nit
src/vm/virtual_machine.nit
tests/Linux.skip
tests/base_notnull.nit [new file with mode: 0644]
tests/base_notnull_lit.nit [new file with mode: 0644]
tests/error_virtual_type.nit [new file with mode: 0644]
tests/error_virtual_type2.nit [new file with mode: 0644]
tests/sav/base_as_notnull.res
tests/sav/base_as_notnull2.res
tests/sav/base_as_notnull2_alt1.res
tests/sav/base_as_notnull2_alt2.res
tests/sav/base_as_notnull2_alt3.res
tests/sav/base_as_notnull_alt1.res
tests/sav/base_as_notnull_alt2.res
tests/sav/base_as_notnull_alt3.res
tests/sav/base_as_notnull_alt4.res
tests/sav/base_as_notnull_alt5.res
tests/sav/base_as_notnull_alt6.res
tests/sav/base_as_notnull_alt7.res
tests/sav/base_as_notnull_int.res
tests/sav/base_eq_null_notnull.res
tests/sav/base_notnull.res [new file with mode: 0644]
tests/sav/base_notnull_1alt1.res [new file with mode: 0644]
tests/sav/base_notnull_1alt1_alt1.res [new file with mode: 0644]
tests/sav/base_notnull_1alt1_alt2.res [new file with mode: 0644]
tests/sav/base_notnull_1alt1_alt3.res [new file with mode: 0644]
tests/sav/base_notnull_1alt1_alt4.res [new file with mode: 0644]
tests/sav/base_notnull_alt1.res [new file with mode: 0644]
tests/sav/base_notnull_alt2.res [new file with mode: 0644]
tests/sav/base_notnull_alt3.res [new file with mode: 0644]
tests/sav/base_notnull_alt4.res [new file with mode: 0644]
tests/sav/base_notnull_lit.res [new file with mode: 0644]
tests/sav/base_notnull_lit_alt1.res [new file with mode: 0644]
tests/sav/base_notnull_lit_alt2.res [new file with mode: 0644]
tests/sav/base_null.res
tests/sav/base_upcast2_1alt1_alt10.res
tests/sav/base_upcast2_1alt1_alt7.res
tests/sav/base_upcast2_1alt1_alt8.res
tests/sav/base_upcast2_1alt1_alt9.res
tests/sav/base_upcast2_1alt2_alt10.res
tests/sav/base_upcast2_1alt2_alt6.res
tests/sav/base_upcast2_1alt2_alt8.res
tests/sav/base_upcast2_1alt2_alt9.res
tests/sav/base_upcast2_1alt3_alt10.res
tests/sav/base_upcast2_1alt3_alt7.res
tests/sav/base_upcast2_1alt3_alt9.res
tests/sav/base_upcast2_1alt4_alt10.res
tests/sav/base_upcast2_1alt4_alt7.res
tests/sav/base_upcast2_1alt4_alt8.res
tests/sav/base_upcast2_1alt5_alt7.res
tests/sav/base_upcast2_1alt5_alt8.res
tests/sav/base_var_type_evolution_null3.res
tests/sav/base_var_type_evolution_null3_alt1.res
tests/sav/base_virtual_type7.res
tests/sav/base_virtual_type_self_alt5.res
tests/sav/error_expr_not_ok_alt4.res
tests/sav/error_expr_not_ok_alt5.res
tests/sav/error_expr_not_ok_alt6.res
tests/sav/error_needed_method_alt4.res
tests/sav/error_needed_method_alt7.res
tests/sav/error_virtual_type2.res [new file with mode: 0644]
tests/sav/error_virtual_type2_alt1.res [new file with mode: 0644]
tests/sav/error_virtual_type2_alt2.res [new file with mode: 0644]
tests/sav/error_virtual_type2_alt3.res [new file with mode: 0644]
tests/sav/error_virtual_type2_alt4.res [new file with mode: 0644]
tests/sav/error_virtual_type2_alt5.res [new file with mode: 0644]
tests/sav/error_virtual_type2_alt6.res [new file with mode: 0644]
tests/sav/error_virtual_type_alt1.res [new file with mode: 0644]
tests/sav/error_virtual_type_alt2.res [new file with mode: 0644]
tests/sav/error_virtual_type_alt3.res [new file with mode: 0644]
tests/sav/error_virtual_type_alt4.res [new file with mode: 0644]
tests/sav/error_virtual_type_alt5.res [new file with mode: 0644]
tests/sav/hello_ios.res [new file with mode: 0644]
tests/sav/nitg-e/base_notnull_lit.res [new file with mode: 0644]
tests/sav/test_new_native_alt1.res
tests/sav/test_parser_args1.res
tests/sav/test_platform_ios.res [new file with mode: 0644]
tests/sav/threaded_example.res [new file with mode: 0644]
tests/test_platform_ios.nit [new file with mode: 0644]
tests/testosx.sh [new file with mode: 0755]
tests/tests.sh

diff --git a/VERSION b/VERSION
index 2c0a9c7..3d105a6 100644 (file)
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-v0.7.2
+v0.7.3
index 62d6a9c..ae91703 100755 (executable)
@@ -62,6 +62,7 @@ function run_compiler()
                run_command "$@" ../src/nit.nit -o "nit.$title.bin"
                bench_command "nit-queens" "nit queens.nit 8" "./nit.$title.bin" ../lib/ai/examples/queens.nit -q 8
                bench_command "nit-nitcc" "nit nitcc.nit calc.sablecc" "./nit.$title.bin" ../contrib/nitcc/src/nitcc.nit ../contrib/nitcc/examples/calc.sablecc
+               rm calc* 2> /dev/null # remove generated cruft
                run_command "$@" ../src/nitdoc.nit -o "nitdoc.$title.bin"
                rm -r out 2> /dev/null
                mkdir out 2> /dev/null
diff --git a/benchmarks/markdown/.gitignore b/benchmarks/markdown/.gitignore
new file mode 100644 (file)
index 0000000..ada48ff
--- /dev/null
@@ -0,0 +1,15 @@
+benches/gen_benches
+benches/out/
+
+engines/nitmd/nitmd
+engines/nitmd/nitmd-o
+
+engines/markdown4j/Markdown4j.class
+engines/markdown4j/markdown4j-2.2.jar
+
+engines/pandoc/pandoc
+engines/pandoc/pandoc.hi
+engines/pandoc/pandoc.o
+
+engines/txtmark/Txtmark.class
+engines/txtmark/txtmark-0.11.jar
diff --git a/benchmarks/markdown/Makefile b/benchmarks/markdown/Makefile
new file mode 100644 (file)
index 0000000..802fab6
--- /dev/null
@@ -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.
+
+all:
+       ./bench_markdown.sh all
+
+clean:
+       $(MAKE) clean -C benches
+       $(MAKE) clean -C engines
+       rm -rf out/
index a739cd8..29219c5 100644 (file)
@@ -11,6 +11,7 @@ Benches markdown parsers.
 * nitmd
 * txtmark 0.11 (https://github.com/rjeschke/txtmark)
 * markdown4j 2.2 (https://code.google.com/p/markdown4j/)
+* pandoc (last version installed from `cabal`)
 
 ## Benches
 
index 4cb0f15..aaa34f0 100755 (executable)
@@ -74,7 +74,7 @@ engdir="./engines"
 bncdir="./benches/out"
 mkdir -p $outdir
 
-s=50
+s=200
 
 function bench_nitmd()
 {
@@ -88,6 +88,18 @@ function bench_nitmd()
 }
 bench_nitmd
 
+function bench_nitmd-o()
+{
+       name="$FUNCNAME"
+       skip_test "$name" && return
+       prepare_res $outdir/nitmd-o.dat "nitmd-o" "nitmd-o"
+       for file in $bncdir/*.md; do
+               bench=`basename $file .md`
+               bench_command "$bench" "" "$engdir/nitmd/nitmd-o" "$file" "$s"
+       done
+}
+bench_nitmd-o
+
 function bench_txtmark()
 {
        name="$FUNCNAME"
@@ -112,6 +124,18 @@ function bench_markdown4j()
 }
 bench_markdown4j
 
+function bench_pandoc()
+{
+       name="$FUNCNAME"
+       skip_test "$name" && return
+       prepare_res $outdir/pandoc.dat "pandoc" "pandoc"
+       for file in $bncdir/*.md; do
+               name=`basename $file .md`
+               bench_command "$bench" "" "$engdir/pandoc/pandoc" "$file" "$s"
+       done
+}
+bench_pandoc
+
 if test "$#" -gt 0; then
     plot $outdir/bench_markdown.gnu
 fi
index 641c47e..4cb8c36 100644 (file)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+NITC=../../../bin/nitc
+
 all: out
 
 gen_benches:
-       nitc gen_benches.nit
+       $(NITC) gen_benches.nit
 
 out: gen_benches
        ./gen_benches ./plain.md -o ./out
index 588e744..7301d01 100644 (file)
@@ -14,7 +14,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-all: nitmd/nitmd txtmark/Txtmark.class markdown4j/Markdown4j.class
+all: nitmd/nitmd txtmark/Txtmark.class markdown4j/Markdown4j.class pandoc/pandoc
 
 nitmd/nitmd:
        make -C nitmd
@@ -25,7 +25,11 @@ txtmark/Txtmark.class:
 markdown4j/Markdown4j.class:
        make -C markdown4j
 
+pandoc/pandoc:
+       make -C pandoc
+
 clean:
        make -C nitmd clean
        make -C txtmark clean
        make -C markdown4j clean
+       make -C pandoc clean
index aa79fbc..256ddfe 100644 (file)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+NITC=../../../../bin/nitc
+
+all: nitmd nitmd-o
+
 nitmd:
-       nitc nitmd.nit
+       $(NITC) nitmd.nit
+
+nitmd-o:
+       $(NITC) --semi-global nitmd.nit -o $@
 
-test: nitmd
+test: all
        ./nitmd ../../benches/hello.md 5
+       ./nitmd-o ../../benches/hello.md 5
 
 clean:
-       rm -rf nitmd
+       rm -rf nitmd nitmd-o
diff --git a/benchmarks/markdown/engines/pandoc/Makefile b/benchmarks/markdown/engines/pandoc/Makefile
new file mode 100644 (file)
index 0000000..ca4a354
--- /dev/null
@@ -0,0 +1,27 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2015 Alexandre Terrasa <alexandre@moz-code.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.
+
+pandoc:
+       cabal install pandoc
+       ghc pandoc.hs -O
+
+test: pandoc
+       ./pandoc ../../benches/hello.md 5
+
+clean:
+       rm pandoc.hi
+       rm pandoc.o
+       rm pandoc
diff --git a/benchmarks/markdown/engines/pandoc/pandoc.hs b/benchmarks/markdown/engines/pandoc/pandoc.hs
new file mode 100644 (file)
index 0000000..5c5db42
--- /dev/null
@@ -0,0 +1,33 @@
+module Main where
+
+       import System.Environment (getArgs)
+       import Text.Pandoc
+
+       -- Reads a String and parses it as a Pandoc instance
+       readDoc :: String -> Pandoc
+       readDoc = readMarkdown def
+
+       -- Writes a Pandoc instances as a String
+       writeDoc :: Pandoc -> String
+       writeDoc = writeHtmlString def
+
+       -- Reads markdown, writes HTML and prints it in stdout
+       doBench :: String -> IO ()
+       doBench fileName        = do
+               content                 <- readFile fileName
+               let markdown    = readDoc content
+               let html                =  writeDoc markdown
+               print html
+
+       -- Executes `doBench` n times
+       loop :: Int -> String -> IO ()
+       loop 0 _ = return ()
+       loop n fileName = do
+               doBench fileName
+               loop (n  - 1) fileName
+               return ()
+
+       main :: IO ()
+       main = do
+               (fileName:count:_)      <- getArgs
+               loop (read count::Int) fileName
diff --git a/benchmarks/strings/.gitignore b/benchmarks/strings/.gitignore
new file mode 100644 (file)
index 0000000..0e224dc
--- /dev/null
@@ -0,0 +1,4 @@
+arraytos/
+string_concat/
+string_iter/
+string_substr/
diff --git a/benchmarks/strings/Makefile b/benchmarks/strings/Makefile
new file mode 100644 (file)
index 0000000..a6d89bf
--- /dev/null
@@ -0,0 +1,16 @@
+all:   concat iter substr array
+
+concat:
+       ./bench_strings.sh cct 10 10000000 1
+
+substr:
+       ./bench_strings.sh substr 10 10000000 10
+
+iter:
+       ./bench_strings.sh iter 10 10000000 10
+
+array:
+       ./bench_strings.sh array 10 10000000 10
+
+clean:
+       rm -rf arraytos/ string_concat/ string_iter/ string_substr/ 2>/dev/null
diff --git a/benchmarks/strings/README.md b/benchmarks/strings/README.md
new file mode 100644 (file)
index 0000000..b87b981
--- /dev/null
@@ -0,0 +1,41 @@
+# Strings
+
+Strings are a building block of programming.
+Since they are that necessary, we must keep them as performing as possible.
+
+This series of benchmarks works on different structures for handling strings on the most common operations done on them.
+
+## Structures
+
+Some more structures are susceptible to be added as the project advances.
+At the moment, what is available consists of
+
+* Flat strings
+* Flat buffers
+* Rope strings
+* Rope buffers
+
+A String is defined as an immutable string.
+A Buffer is defined as a mutable string.
+
+Flat strings are arrays of characters, the most basic implementation of a string.
+Ropes are a tree-like structure where strings are bound through concatenation nodes.
+
+## Tests
+
+`concat`: Benches the concatenation speed of strings and buffers.
+
+`iter`: Benches the time of iteration of a string, through iterators or indexed access
+
+`substr`: Benches the time required to produce a substring.
+
+`arraytos`: Special bench, it measures the speed of `Array::to_s` through the use of various strategies.
+
+## Usage
+
+To pass a series of benches you can use the `make` command to bench all the aforementioned tests with default values.
+
+Each bench will be executed 5 times and the mean time will be represented in the final graph.
+
+The alternative is to use `bench_strings.sh` with custom arguments to it.
+For more information on the arguments and the format, execute it with the -h option for help.
index d61b742..f18ece7 100644 (file)
@@ -13,6 +13,9 @@
 # To be used as a Mixin at compile-time for benchmarking purposes.
 module array_to_s_buffer
 
+intrude import standard::collection::array
+import standard::string
+
 redef class Array[E]
        redef fun to_s: String do
                var s = new FlatBuffer
index 0240d5b..7028e3f 100644 (file)
 # To be used as a Mixin at compile-time for benchmarking purposes.
 module array_to_s_flatstr
 
+intrude import standard::string
+
+redef class FlatString
+       redef fun +(o) do
+               var mlen = length
+               var slen = o.length
+               var nns = new NativeString(mlen + slen)
+               items.copy_to(nns, mlen, index_from, 0)
+               if o isa FlatString then
+                       o.items.copy_to(nns, slen, o.index_from, mlen)
+               else
+                       var pos = mlen
+                       for i in o.chars do
+                               nns[pos] = i
+                               pos += 1
+                       end
+               end
+               return nns.to_s_with_length(mlen)
+       end
+end
+
 redef class Array[E]
 
        redef fun to_s do
index ec81322..c5dbd00 100644 (file)
@@ -13,9 +13,8 @@
 # To be used as a Mixin at compile-time for benchmarking purposes.
 module array_to_s_man_buf
 
-redef class NativeArray[E]
-       new(length: Int) is intern
-end
+intrude import standard::collection::array
+import standard::string
 
 redef class Array[E]
        redef fun to_s: String do
index c162dff..9f86a8a 100644 (file)
 # To be used as a Mixin at compile-time for benchmarking purposes.
 module array_to_s_rope
 
+intrude import standard::collection::array
+intrude import standard::ropes
+
 redef class Array[E]
 
        redef fun to_s do
-               var i = 1
                var l = length
+               var it = _items
                if l == 0 then return ""
-               var s: String = new RopeString.from(self[0].to_s)
-               var its = _items
-               while i < l do
-                       var e = its[i]
-                       if e != null then s += e.to_s
-                       i += 1
+               if l == 1 then return it[0].to_s
+               var c = new Concat(it[0].to_s, it[1].to_s)
+               for i in [2 .. l[ do
+                       c = new Concat(c, it[i].to_s)
                end
-               return s
+               return c
        end
+
 end
diff --git a/benchmarks/strings/array_to_s_vars/array_to_s_rope_buf.nit b/benchmarks/strings/array_to_s_vars/array_to_s_rope_buf.nit
new file mode 100644 (file)
index 0000000..c7e3e7b
--- /dev/null
@@ -0,0 +1,32 @@
+# 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.
+
+# Implementation of Array::to_s with RopeBuffer exclusively
+#
+# To be used as a Mixin at compile-time for benchmarking purposes.
+module array_to_s_rope_buf
+
+intrude import standard::collection::array
+import standard::ropes
+
+redef class Array[E]
+       redef fun to_s: String do
+               var s = new RopeBuffer
+               var i = 0
+               var l = length
+               var its = _items
+               while i < l do
+                       var e = its[i]
+                       if e != null then s.append(e.to_s)
+                       i += 1
+               end
+               return s.to_s
+       end
+end
similarity index 53%
rename from benchmarks/bench_strings.sh
rename to benchmarks/strings/bench_strings.sh
index 16992e9..a710dc0 100755 (executable)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-source ./bench_common.sh
-source ./bench_plot.sh
+source ../bench_common.sh
+source ../bench_plot.sh
 
 # Default number of times a command must be run with bench_command
 # Can be overrided with 'the option -n'
-count=2
+count=5
 
 function usage()
 {
@@ -28,8 +28,6 @@ function usage()
        echo "  -h: this help"
        echo ""
        echo "Benches : "
-       echo "  all : all benches"
-       echo "    - usage : * max_nb_cct loops strlen"
        echo "  iter: bench iterations"
        echo "    - usage : iter max_nb_cct loops strlen"
        echo "  cct: concatenation benching"
@@ -40,21 +38,20 @@ function usage()
        echo "    - usage : array nb_cct loops max_arrlen"
 }
 
-function benches()
-{
-       bench_concat $@;
-       bench_iteration $@;
-       bench_substr $@;
-       bench_array $@;
-}
-
 function bench_array()
 {
+       if [ -d arraytos ]; then
+               rm arraytos/*
+       else
+               mkdir arraytos
+       fi
+       cd arraytos
+
        if $verbose; then
                echo "*** Benching Array.to_s performance ***"
        fi
 
-       ../bin/nitc --global ./strings/array_tos.nit -m ./strings/array_to_s_vars/array_to_s_flatstr.nit -m ../lib/standard/ropes.nit --make-flags "CFLAGS=\"-g -O2 -DNOBOEHM\""
+       ../../../bin/nitc --global ../array_tos.nit -m ../array_to_s_vars/array_to_s_rope.nit
 
        prepare_res arr_tos_ropes.out arr_tos_ropes ropes
        if $verbose; then
@@ -64,23 +61,10 @@ function bench_array()
                if $verbose; then
                        echo "String length = $i, Concats/loop = $1, Loops = $2"
                fi
-               bench_command $i ropes$i ./array_tos --loops $2 --strlen $i --ccts $1 "NIT_GC_CHOOSER=large"
+               bench_command $i ropes$i ./array_tos --loops $2 --strlen $i --ccts $1
        done
 
-       ../bin/nitc --global ./strings/array_tos.nit -m ./strings/array_to_s_vars/array_to_s_flatstr.nit -m ../lib/standard/ropes.nit -m ../lib/buffered_ropes.nit --make-flags "CFLAGS=\"-g -O2 -DNOBOEHM\""
-
-       prepare_res arr_tos_buf_ropes.out arr_tos_buf_ropes buffered_ropes
-       if $verbose; then
-               echo "Buffered Ropes :"
-       fi
-       for i in `seq 1 "$3"`; do
-               if $verbose; then
-                       echo "String length = $i, Concats/loop = $1, Loops = $2"
-               fi
-               bench_command $i buf_ropes$i ./array_tos --loops $2 --strlen $i --ccts $1 "NIT_GC_CHOOSER=large"
-       done
-
-       ../bin/nitc --global ./strings/array_tos.nit -m ./strings/array_to_s_vars/array_to_s_flatstr.nit --make-flags "CFLAGS=\"-g -O2 -DNOBOEHM\""
+       ../../../bin/nitc --global ../array_tos.nit -m ../array_to_s_vars/array_to_s_flatstr.nit
 
        prepare_res arr_tos_flat.out arr_tos_flat flatstring
        if $verbose; then
@@ -90,10 +74,10 @@ function bench_array()
                if $verbose; then
                        echo "String length = $i, Concats/loop = $1, Loops = $2"
                fi
-               bench_command $i flatstring$i ./array_tos --loops $2 --strlen $i --ccts $1 "NIT_GC_CHOOSER=large"
+               bench_command $i flatstring$i ./array_tos --loops $2 --strlen $i --ccts $1
        done
 
-       ../bin/nitc --global ./strings/array_tos.nit -m ./strings/array_to_s_vars/array_to_s_buffer.nit --make-flags "CFLAGS=\"-g -O2 -DNOBOEHM\""
+       ../../../bin/nitc --global ../array_tos.nit -m ../array_to_s_vars/array_to_s_buffer.nit
 
        prepare_res arr_tos_buf.out arr_tos_buf flatbuffer
        if $verbose; then
@@ -103,10 +87,10 @@ function bench_array()
                if $verbose; then
                        echo "String length = $i, Concats/loop = $1, Loops = $2"
                fi
-               bench_command $i flatbuffer$i ./array_tos --loops $2 --strlen $i --ccts $1 "NIT_GC_CHOOSER=large"
+               bench_command $i flatbuffer$i ./array_tos --loops $2 --strlen $i --ccts $1
        done
 
-       ../bin/nitc --global ./strings/array_tos.nit -m ./strings/array_to_s_vars/array_to_s_manual.nit --make-flags "CFLAGS=\"-g -O2 -DNOBOEHM\""
+       ../../../bin/nitc --global ../array_tos.nit -m ../array_to_s_vars/array_to_s_manual.nit
 
        prepare_res arr_tos_man.out arr_tos_man memmove
        if $verbose; then
@@ -116,10 +100,10 @@ function bench_array()
                if $verbose; then
                        echo "String length = $i, Concats/loop = $1, Loops = $2"
                fi
-               bench_command $i memmove$i ./array_tos --loops $2 --strlen $i --ccts $1 "NIT_GC_CHOOSER=large"
+               bench_command $i memmove$i ./array_tos --loops $2 --strlen $i --ccts $1
        done
 
-       ../bin/nitc --global ./strings/array_tos.nit -m ./strings/array_to_s_vars/array_to_s_man_buf.nit --make-flags "CFLAGS=\"-g -O2 -DNOBOEHM\""
+       ../../../bin/nitc --global ../array_tos.nit -m ../array_to_s_vars/array_to_s_man_buf.nit
 
        prepare_res arr_tos_man_buf.out arr_tos_man_buf flatbuf_with_capacity
        if $verbose; then
@@ -129,10 +113,10 @@ function bench_array()
                if $verbose; then
                        echo "String length = $i, Concats/loop = $1, Loops = $2"
                fi
-               bench_command $i flatbuf_with_capacity$i ./array_tos --loops $2 --strlen $i --ccts $1 "NIT_GC_CHOOSER=large"
+               bench_command $i flatbuf_with_capacity$i ./array_tos --loops $2 --strlen $i --ccts $1
        done
 
-       ../bin/nitc --global ./strings/array_tos.nit -m ./strings/array_to_s_vars/array_to_s_rope_buf.nit --make-flags "CFLAGS=\"-g -O2 -DNOBOEHM\""
+       ../../../bin/nitc --global ../array_tos.nit -m ../array_to_s_vars/array_to_s_rope_buf.nit
 
        prepare_res arr_tos_rope_buf.out arr_tos_rope_buf ropebuf
        if $verbose; then
@@ -142,16 +126,24 @@ function bench_array()
                if $verbose; then
                        echo "String length = $i, Concats/loop = $1, Loops = $2"
                fi
-               bench_command $i ropebuf$i ./array_tos --loops $2 --strlen $i --ccts $1 "NIT_GC_CHOOSER=large"
+               bench_command $i ropebuf$i ./array_tos --loops $2 --strlen $i --ccts $1
        done
 
        plot array_tos.gnu
+
+       cd ..
 }
 
 function bench_concat()
 {
-       ../bin/nitc --global ./strings/chain_concat.nit --make-flags "CFLAGS=\"-g -O2 -DNOBOEHM\""
-       ../bin/nitc --global ./strings/utf_chain_concat.nit --make-flags "CFLAGS=\"-g -O2 -DNOBOEHM\""
+       if [ -d string_concat ]; then
+               rm string_concat/*
+       else
+               mkdir string_concat
+       fi
+       cd string_concat
+
+       ../../../bin/nitc --global ../chain_concat.nit
 
        if $verbose; then
                echo "*** Benching concat performance ***"
@@ -165,7 +157,7 @@ function bench_concat()
                if $verbose; then
                        echo "String length = $i, Concats/loop = $2, Loops = $3"
                fi
-               bench_command $i flatstring$i ./chain_concat -m flatstr --loops $2 --strlen $3 --ccts $i "NIT_GC_CHOOSER=large"
+               bench_command $i flatstring$i ./chain_concat -m flatstr --loops $2 --strlen $3 --ccts $i
        done
 
        prepare_res concat_buf.out concat_buf flatbuffer
@@ -176,22 +168,9 @@ function bench_concat()
                if $verbose; then
                        echo "String length = $i, Concats/loop = $2, Loops = $3"
                fi
-               bench_command $i flatbuffer$i ./chain_concat -m flatbuf --loops $2 --strlen $3 --ccts $i "NIT_GC_CHOOSER=large"
+               bench_command $i flatbuffer$i ./chain_concat -m flatbuf --loops $2 --strlen $3 --ccts $i
        done
 
-       prepare_res concat_flatstr_utf8_noindex.out concat_flatstr_utf8_noindex flatstring_utf8_noindex
-       if $verbose; then
-               echo "FlatString UTF-8 (without index) :"
-       fi
-       for i in `seq 1 "$1"`; do
-               if $verbose; then
-                       echo "String length = $i, Concats/loop = $2, Loops = $3"
-               fi
-               bench_command $i flatstr_utf8_noindex$i ./utf_chain_concat -m flatstr_utf8_noindex --loops $2 --strlen $3 --ccts $i "NIT_GC_CHOOSER=large"
-       done
-
-       ../bin/nitc --global ./strings/chain_concat.nit -m ../lib/standard/ropes.nit --make-flags "CFLAGS=\"-g -O2 -DNOBOEHM\""
-
        prepare_res concat_ropes.out concat_ropes ropes
        if $verbose; then
                echo "Ropes :"
@@ -200,46 +179,39 @@ function bench_concat()
                if $verbose; then
                        echo "String length = $i, Concats/loop = $2, Loops = $3"
                fi
-               bench_command $i ropes$i ./chain_concat -m flatstr --loops $2 --strlen $3 --ccts $i "NIT_GC_CHOOSER=large"
+               bench_command $i ropes$i ./chain_concat -m ropestr --loops $2 --strlen $3 --ccts $i
        done
 
-       ../bin/nitc --global ./strings/chain_concat.nit -m ../lib/standard/ropes.nit -m ../lib/buffered_ropes.nit --make-flags "CFLAGS=\"-g -O2 -DNOBOEHM\""
-
        prepare_res concat_buf_ropes.out concat_buf_ropes buffered_ropes
        if $verbose; then
-               echo "buffered ropes :"
-       fi
-       for i in `seq 1 "$1"`; do
-               if $verbose; then
-                       echo "string length = $i, concats/loop = $2, loops = $3"
-               fi
-               bench_command $i buf_ropes$i ./chain_concat -m flatstr --loops $2 --strlen $3 --ccts $i "NIT_GC_CHOOSER=large"
-       done
-
-       ../bin/nitc --global ./strings/chain_cct_ropebuf.nit --make-flags "CFLAGS=\"-g -O2 -DNOBOEHM\""
-
-       prepare_res cct_buf_ropes.out cct_buf_ropes cctbuf_ropes
-       if $verbose; then
-               echo "buffered ropes :"
+               echo "Rope Buffer:"
        fi
        for i in `seq 1 "$1"`; do
                if $verbose; then
                        echo "string length = $i, concats/loop = $2, loops = $3"
                fi
-               bench_command $i cctbuf_ropes$i ./chain_cct_ropebuf --loops $2 --strlen $3 --ccts $i "NIT_GC_CHOOSER=large"
+               bench_command $i buf_ropes$i ./chain_concat -m ropebuf --loops $2 --strlen $3 --ccts $i
        done
 
        plot concat.gnu
+
+       cd ..
 }
 
 function bench_iteration()
 {
+       if [ -d string_iter ]; then
+               rm string_iter/*
+       else
+               mkdir string_iter
+       fi
+       cd string_iter
+
        if $verbose; then
                echo "*** Benching iteration performance ***"
        fi
 
-       ../bin/nitc --global ./strings/iteration_bench.nit --make-flags "CFLAGS=\"-g -O2 -DNOBOEHM\""
-       ../bin/nitc --global ./strings/utf_iteration_bench.nit --make-flags "CFLAGS=\"-g -O2 -DNOBOEHM\""
+       ../../../bin/nitc --global ../iteration_bench.nit
 
        prepare_res iter_flat_iter.out iter_flat_iter flatstring_iter
        if $verbose; then
@@ -249,7 +221,7 @@ function bench_iteration()
                if $verbose; then
                        echo "String base length = $1, Concats = $i, Loops = $3"
                fi
-               bench_command $i flatstr_iter$i ./iteration_bench -m flatstr --iter-mode iterator --loops $2 --strlen $3 --ccts $i "NIT_GC_CHOOSER=large"
+               bench_command $i flatstr_iter$i ./iteration_bench -m flatstr --iter-mode iterator --loops $2 --strlen $3 --ccts $i
        done
 
        prepare_res iter_flat_index.out iter_flat_index flatstring_index
@@ -260,7 +232,7 @@ function bench_iteration()
                if $verbose; then
                        echo "String base length = $1, Concats = $i, Loops = $3"
                fi
-               bench_command $i flatstr_index$i ./iteration_bench -m flatstr --iter-mode index --loops $2 --strlen $3 --ccts $i "NIT_GC_CHOOSER=large"
+               bench_command $i flatstr_index$i ./iteration_bench -m flatstr --iter-mode index --loops $2 --strlen $3 --ccts $i
        done
 
        prepare_res iter_buf_iter.out iter_buf_iter flatbuffer_iter
@@ -271,7 +243,7 @@ function bench_iteration()
                if $verbose; then
                        echo "String base length = $1, Concats = $i, Loops = $3"
                fi
-               bench_command $i flatbuf_iter$i ./iteration_bench -m flatbuf --iter-mode iterator --loops $2 --strlen $3 --ccts $i "NIT_GC_CHOOSER=large"
+               bench_command $i flatbuf_iter$i ./iteration_bench -m flatbuf --iter-mode iterator --loops $2 --strlen $3 --ccts $i
        done
 
        prepare_res iter_buf_index.out iter_buf_index flatbuffer_index
@@ -282,33 +254,9 @@ function bench_iteration()
                if $verbose; then
                        echo "String base length = $1, Concats = $i, Loops = $3"
                fi
-               bench_command $i flatbuf_index$i ./iteration_bench -m flatbuf --iter-mode index --loops $2 --strlen $3 --ccts $i "NIT_GC_CHOOSER=large"
+               bench_command $i flatbuf_index$i ./iteration_bench -m flatbuf --iter-mode index --loops $2 --strlen $3 --ccts $i
        done
 
-       prepare_res iter_flat_utf8_noindex_iter.out iter_flat_iter_utf8_noindex flatstring_utf8_noindex_iter
-       if $verbose; then
-               echo "FlatStrings by iterator :"
-       fi
-       for i in `seq 1 "$1"`; do
-               if $verbose; then
-                       echo "String base length = $1, Concats = $i, Loops = $3"
-               fi
-               bench_command $i flatstr_iter_utf8_noindex$i ./utf_iteration_bench -m flatstr_utf8_noindex --iter-mode iterator --loops $2 --strlen $3 --ccts $i "NIT_GC_CHOOSER=large"
-       done
-
-       prepare_res iter_flat_utf8_noindex_index.out iter_flat_index_utf8_noindex flatstring_utf8_noindex_index
-       if $verbose; then
-               echo "FlatStrings by index :"
-       fi
-       for i in `seq 1 "$1"`; do
-               if $verbose; then
-                       echo "String base length = $1, Concats = $i, Loops = $3"
-               fi
-               bench_command $i flatstr_index_utf8_noindex$i ./utf_iteration_bench -m flatstr_utf8_noindex --iter-mode index --loops $2 --strlen $3 --ccts $i "NIT_GC_CHOOSER=large"
-       done
-
-       ../bin/nitc --global ./strings/iteration_bench.nit -m ../lib/standard/ropes.nit --make-flags "CFLAGS=\"-g -O2 -DNOBOEHM\""
-
        prepare_res iter_ropes_iter.out iter_ropes_iter ropes_iter
        if $verbose; then
                echo "Ropes by iterator :"
@@ -317,7 +265,7 @@ function bench_iteration()
                if $verbose; then
                        echo "String base length = $1, Concats (depth of the rope) = $i, Loops = $3"
                fi
-               bench_command $i ropes_iter$i ./iteration_bench -m flatstr --iter-mode iterator --loops $2 --strlen $3 --ccts $i "NIT_GC_CHOOSER=large"
+               bench_command $i ropes_iter$i ./iteration_bench -m ropestr --iter-mode iterator --loops $2 --strlen $3 --ccts $i
        done
 
        prepare_res iter_ropes_index.out iter_ropes_index ropes_index
@@ -328,44 +276,50 @@ function bench_iteration()
                if $verbose; then
                        echo "String base length = $1, Concats (depth of the rope) = $i, Loops = $3"
                fi
-               bench_command $i ropes_index$i ./iteration_bench -m flatstr --iter-mode index --loops $2 --strlen $3 --ccts $i "NIT_GC_CHOOSER=large"
+               bench_command $i ropes_index$i ./iteration_bench -m ropestr --iter-mode index --loops $2 --strlen $3 --ccts $i
        done
 
-       ../bin/nitc --global ./strings/iteration_bench.nit -m ../lib/standard/ropes.nit -m ../lib/buffered_ropes.nit --make-flags "CFLAGS=\"-g -O2 -DNOBOEHM\""
-
        prepare_res iter_buf_ropes_iter.out iter_buf_ropes_iter buf_ropes_iter
        if $verbose; then
-               echo "Buffered Ropes by iterator :"
+               echo "RopeBuffer by iterator :"
        fi
        for i in `seq 1 "$1"`; do
                if $verbose; then
                        echo "String base length = $1, Concats (depth of the rope) = $i, Loops = $3"
                fi
-               bench_command $i buf_ropes_iter$i ./iteration_bench -m flatstr --iter-mode iterator --loops $2 --strlen $3 --ccts $i "NIT_GC_CHOOSER=large"
+               bench_command $i buf_ropes_iter$i ./iteration_bench -m ropebuf --iter-mode iterator --loops $2 --strlen $3 --ccts $i
        done
 
        prepare_res iter_buf_ropes_index.out iter_buf_ropes_index buf_ropes_index
        if $verbose; then
-               echo "Buffered Ropes by index :"
+               echo "RopeBuffer by index :"
        fi
        for i in `seq 1 "$1"`; do
                if $verbose; then
                        echo "String base length = $1, Concats (depth of the rope) = $i, Loops = $3"
                fi
-               bench_command $i buf_ropes_index$i ./iteration_bench -m flatstr --iter-mode index --loops $2 --strlen $3 --ccts $i "NIT_GC_CHOOSER=large"
+               bench_command $i buf_ropes_index$i ./iteration_bench -m ropebuf --iter-mode index --loops $2 --strlen $3 --ccts $i
        done
 
        plot iter.gnu
+
+       cd ..
 }
 
 function bench_substr()
 {
+       if [ -d string_substr ]; then
+               rm string_substr/*
+       else
+               mkdir string_substr
+       fi
+       cd string_substr
+
        if $verbose; then
                echo "*** Benching substring performance ***"
        fi
 
-       ../bin/nitc --global ./strings/substr_bench.nit --make-flags "CFLAGS=\"-g -O2 -DNOBOEHM\""
-       ../bin/nitc --global ./strings/utf_substr_bench.nit --make-flags "CFLAGS=\"-g -O2 -DNOBOEHM\""
+       ../../../bin/nitc --global ../substr_bench.nit
 
        prepare_res substr_flat.out substr_flat flatstring
        if $verbose; then
@@ -375,7 +329,7 @@ function bench_substr()
                if $verbose; then
                        echo "String length = $i, loops = $2, Loops = $3"
                fi
-               bench_command $i flatstring$i ./substr_bench -m flatstr --loops $2 --strlen $3 --ccts $i "NIT_GC_CHOOSER=large"
+               bench_command $i flatstring$i ./substr_bench -m flatstr --loops $2 --strlen $3 --ccts $i
        done
 
        prepare_res substr_buf.out substr_buf flatbuffer
@@ -386,22 +340,9 @@ function bench_substr()
                if $verbose; then
                        echo "String length = $i, loops = $2, Loops = $3"
                fi
-               bench_command $i flatbuffer$i ./substr_bench -m flatbuf --loops $2 --strlen $3 --ccts $i "NIT_GC_CHOOSER=large"
-       done
-
-       prepare_res substr_flat_utf8_noindex.out substr_flat_utf8_noindex flatstring_utf8_noindex
-       if $verbose; then
-               echo "FlatStrings UTF-8 (without index) :"
-       fi
-       for i in `seq 1 "$1"`; do
-               if $verbose; then
-                       echo "String length = $i, loops = $2, Loops = $3"
-               fi
-               bench_command $i flatstring_utf8_noindex$i ./utf_substr_bench -m flatstr_utf8_noindex --loops $2 --strlen $3 --ccts $i "NIT_GC_CHOOSER=large"
+               bench_command $i flatbuffer$i ./substr_bench -m flatbuf --loops $2 --strlen $3 --ccts $i
        done
 
-       ../bin/nitc --global ./strings/substr_bench.nit -m ../lib/standard/ropes.nit --make-flags "CFLAGS=\"-g -O2 -DNOBOEHM\""
-
        prepare_res substr_ropes.out substr_ropes ropes
        if $verbose; then
                echo "Ropes :"
@@ -410,22 +351,23 @@ function bench_substr()
                if $verbose; then
                        echo "String length = $i, loops = $2, Loops = $3"
                fi
-               bench_command $i ropes$i ./substr_bench -m flatstr --loops $2 --strlen $3 --ccts $i "NIT_GC_CHOOSER=large"
+               bench_command $i ropes$i ./substr_bench -m ropestr --loops $2 --strlen $3 --ccts $i
        done
 
-       ../bin/nitc --global ./strings/substr_bench.nit -m ../lib/standard/ropes.nit -m ../lib/buffered_ropes.nit --make-flags "CFLAGS=\"-g -O2 -DNOBOEHM\""
-
        prepare_res substr_buf_ropes.out substr_buf_ropes buf_ropes
        if $verbose; then
-               echo "Buffered Ropes :"
+               echo "RopeBuffers :"
        fi
        for i in `seq 1 "$1"`; do
                if $verbose; then
                        echo "String length = $i, loops = $2, Loops = $3"
                fi
-               bench_command $i buf_ropes$i ./substr_bench -m flatstr --loops $2 --strlen $3 --ccts $i "NIT_GC_CHOOSER=large"
+               bench_command $i buf_ropes$i ./substr_bench -m ropebuf --loops $2 --strlen $3 --ccts $i
        done
+
        plot substr.gnu
+
+       cd ..
 }
 
 stop=false
@@ -448,6 +390,5 @@ case "$1" in
        cct) shift; bench_concat $@ ;;
        substr) shift; bench_substr $@ ;;
        array) shift; bench_array $@ ;;
-       all) shift; benches $@ ;;
        *) usage; exit;;
 esac
index a45075f..a70dd14 100644 (file)
 # Benches measuring the performance of several concatenations on Text variants
 module chain_concat
 
+intrude import standard::ropes
 import opts
 
+redef class FlatString
+       redef fun +(o) do
+               var mlen = length
+               var slen = o.length
+               var nlen = mlen + slen
+               var ns = new NativeString(nlen + 1)
+               items.copy_to(ns, mlen, index_from, 0)
+               if o isa FlatString then
+                       o.items.copy_to(ns, slen, o.index_from, 0)
+               else
+                       var pos = mlen
+                       for i in o.chars do
+                               ns[pos] = i
+                               pos += 1
+                       end
+               end
+               return ns.to_s_with_length(nlen)
+       end
+end
+
 fun bench_flatstr(str_size: Int, nb_ccts: Int, loops: Int)
 do
        var lft = "a" * str_size
 
-       for i in [0..loops] do
-               var str: String = lft
-               for j in [0..nb_ccts] do
+       for i in [0 .. loops[ do
+               var str: String = ""
+               for j in [0 .. nb_ccts[ do
                        str += lft
                end
        end
 end
 
+fun bench_ropestr(str_size, nb_ccts, loops: Int) do
+       var lft = "a" * str_size
+
+       for i in [0 .. loops[ do
+               var str: String = ""
+               for j in [0 .. nb_ccts[ do
+                       str = new Concat(str, lft)
+               end
+       end
+end
+
 fun bench_flatbuf(str_size: Int, nb_ccts: Int, loops: Int)
 do
        var lft = "a" * str_size
 
-       for i in [0..loops] do
-               var buf = new FlatBuffer.from(lft)
-               for j in [0..nb_ccts] do
+       for i in [0 .. loops[ do
+               var buf = new FlatBuffer
+               for j in [0 .. nb_ccts[ do
+                       buf.append(lft)
+               end
+       end
+end
+
+fun bench_ropebuf(str_size: Int, nb_ccts: Int, loops: Int)
+do
+       var lft = "a" * str_size
+
+       for i in [0 .. loops[ do
+               var buf = new RopeBuffer
+               for j in [0 .. nb_ccts[ do
                        buf.append(lft)
                end
-               buf.to_s
        end
 end
 
 var opts = new OptionContext
-var mode = new OptionEnum(["flatstr", "flatbuf"], "Mode", -1, "-m")
+var mode = new OptionEnum(["flatstr", "ropestr", "flatbuf", "ropebuf"], "Mode", -1, "-m")
 var nb_ccts = new OptionInt("Number of concatenations per loop", -1, "--ccts")
 var loops = new OptionInt("Number of loops to be done", -1, "--loops")
 var strlen = new OptionInt("Length of the base string", -1, "--strlen")
@@ -57,7 +100,12 @@ var modval = mode.value
 if modval == 0 then
        bench_flatstr(strlen.value, nb_ccts.value, loops.value)
 else if modval == 1 then
+       bench_ropestr(strlen.value, nb_ccts.value, loops.value)
+else if modval == 2 then
        bench_flatbuf(strlen.value, nb_ccts.value, loops.value)
+else if modval == 3 then
+       bench_ropebuf(strlen.value, nb_ccts.value, loops.value)
+
 else
        opts.usage
        exit -1
index 0e36c49..b37ad26 100644 (file)
 module iteration_bench
 
 import opts
+intrude import standard::ropes
+
+redef class Concat
+       redef fun +(o) do
+               var s = o.to_s
+               return new Concat(self, s)
+       end
+end
+
+redef class FlatString
+       redef fun +(o) do
+               var s = o.to_s
+               var b = new FlatBuffer.with_capacity(length + s.length)
+               b.append self
+               for i in s.substrings do b.append i
+               return b.to_s
+       end
+end
 
 fun bench_flatstr_iter(nb_cct: Int, loops: Int, strlen: Int)
 do
        var a = "a" * strlen
-       var x = a
-       for i in [0 .. nb_cct] do x += a
+       a = a * nb_cct
        var cnt = 0
        var c: Char
        while cnt != loops do
-               for i in x do
+               for i in a do
                        c = i
                end
                cnt += 1
@@ -31,8 +48,40 @@ end
 fun bench_flatstr_index(nb_cct: Int, loops: Int, strlen: Int)
 do
        var a = "a" * strlen
-       var x = a
-       for i in [0 .. nb_cct] do x += a
+       a = a * nb_cct
+       var cnt = 0
+       var c: Char
+       var pos = 0
+       while cnt != loops do
+               pos = 0
+               while pos < a.length do
+                       c = a[pos]
+                       pos += 1
+               end
+               cnt += 1
+       end
+end
+
+fun bench_ropestr_iter(nb_cct: Int, loops: Int, strlen: Int)
+do
+       var a = "a" * strlen
+       var x: String = new Concat(a, a)
+       for i in [2 .. nb_cct[ do x = new Concat(x, a)
+       var cnt = 0
+       var c: Char
+       while cnt != loops do
+               for i in x do
+                       c = i
+               end
+               cnt += 1
+       end
+end
+
+fun bench_ropestr_index(nb_cct: Int, loops: Int, strlen: Int)
+do
+       var a = "a" * strlen
+       var x: String = new Concat(a, a)
+       for i in [2 .. nb_cct[ do x = new Concat(x, a)
        var cnt = 0
        var c: Char
        var pos = 0
@@ -49,8 +98,8 @@ end
 fun bench_flatbuf_iter(nb_cct: Int, loops: Int, strlen: Int)
 do
        var a = "a" * strlen
+       a = a * nb_cct
        var x = new FlatBuffer.from(a)
-       for i in [0 .. nb_cct] do x.append a
        var cnt = 0
        var c: Char
        while cnt != loops do
@@ -64,8 +113,41 @@ end
 fun bench_flatbuf_index(nb_cct: Int, loops: Int, strlen: Int)
 do
        var a = "a" * strlen
+       a = a * nb_cct
        var x = new FlatBuffer.from(a)
-       for i in [0 .. nb_cct] do x.append a
+       var cnt = 0
+       var c: Char
+       var pos = 0
+       while cnt != loops do
+               pos = 0
+               while pos < x.length do
+                       c = x[pos]
+                       pos += 1
+               end
+               cnt += 1
+       end
+end
+
+fun bench_ropebuf_iter(nb_cct: Int, loops: Int, strlen: Int)
+do
+       var a = "a" * strlen
+       var x = new RopeBuffer.from(a)
+       for i in [0 .. nb_cct[ do x.append a
+       var cnt = 0
+       var c: Char
+       while cnt != loops do
+               for i in x do
+                       c = i
+               end
+               cnt += 1
+       end
+end
+
+fun bench_ropebuf_index(nb_cct: Int, loops: Int, strlen: Int)
+do
+       var a = "a" * strlen
+       var x = new RopeBuffer.from(a)
+       for i in [0 .. nb_cct[ do x.append a
        var cnt = 0
        var c: Char
        var pos = 0
@@ -80,7 +162,7 @@ do
 end
 
 var opts = new OptionContext
-var mode = new OptionEnum(["flatstr", "flatbuf"], "Mode", -1, "-m")
+var mode = new OptionEnum(["flatstr", "flatbuf", "ropestr", "ropebuf"], "Mode", -1, "-m")
 var access_mode = new OptionEnum(["iterator", "index"], "Iteration mode", -1, "--iter-mode")
 var nb_ccts = new OptionInt("Number of concatenations done to the string (in the case of the rope, this will increase its depth)", -1, "--ccts")
 var loops = new OptionInt("Number of loops to be done", -1, "--loops")
@@ -115,6 +197,24 @@ else if modval == 1 then
                opts.usage
                exit(-1)
        end
+else if modval == 2 then
+       if iterval == 0 then
+               bench_ropestr_iter(nb_ccts.value, loops.value, strlen.value)
+       else if iterval == 1 then
+               bench_ropestr_index(nb_ccts.value, loops.value, strlen.value)
+       else
+               opts.usage
+               exit(-1)
+       end
+else if modval == 3 then
+       if iterval == 0 then
+               bench_ropebuf_iter(nb_ccts.value, loops.value, strlen.value)
+       else if iterval == 1 then
+               bench_ropebuf_index(nb_ccts.value, loops.value, strlen.value)
+       else
+               opts.usage
+               exit(-1)
+       end
 else
        opts.usage
        exit(-1)
index effb9ec..3727960 100644 (file)
 module substr_bench
 
 import opts
+intrude import standard::ropes
 
 fun bench_flatstr(nb_cct: Int, loops: Int, strlen: Int)
 do
        var a = "a" * strlen
-       var x = a
-       for i in [0 .. nb_cct] do x += a
+       a = a * nb_cct
+       var maxl = a.length - 1
        var cnt = 0
        while cnt != loops do
-               x.substring(0,5)
+               a.substring(maxl.rand, maxl.rand)
                cnt += 1
        end
 end
@@ -28,17 +29,44 @@ end
 fun bench_flatbuf(nb_cct: Int, loops: Int, strlen: Int)
 do
        var a = "a" * strlen
+       a = a * nb_cct
+       var maxl = a.length - 1
        var x = new FlatBuffer.from(a)
-       for i in [0 .. nb_cct] do x.append a
        var cnt = 0
        while cnt != loops do
-               x.substring(0,5)
+               x.substring(maxl.rand, maxl.rand)
+               cnt += 1
+       end
+end
+
+fun bench_ropestr(nb_cct: Int, loops: Int, strlen: Int)
+do
+       var a = "a" * strlen
+       var x = new Concat(a, a)
+       for i in [2 .. nb_cct[ do x = new Concat(x, a)
+       var maxl = x.length - 1
+       var cnt = 0
+       while cnt != loops do
+               x.substring(maxl.rand, maxl.rand)
+               cnt += 1
+       end
+end
+
+fun bench_ropebuf(nb_cct: Int, loops: Int, strlen: Int)
+do
+       var a = "a" * strlen
+       var x = new RopeBuffer.from(a)
+       for i in [1 .. nb_cct[ do x.append a
+       var maxl = x.length - 1
+       var cnt = 0
+       while cnt != loops do
+               x.substring(maxl.rand, maxl.rand)
                cnt += 1
        end
 end
 
 var opts = new OptionContext
-var mode = new OptionEnum(["flatstr", "flatbuf"], "Mode", -1, "-m")
+var mode = new OptionEnum(["flatstr", "flatbuf", "ropestr", "ropebuf"], "Mode", -1, "-m")
 var nb_ccts = new OptionInt("Number of concatenations done to the string (in the case of the rope, this will increase its depth)", -1, "--ccts")
 var loops = new OptionInt("Number of loops to be done", -1, "--loops")
 var strlen = new OptionInt("Length of the base string", -1, "--strlen")
@@ -52,11 +80,16 @@ if nb_ccts.value == -1 or loops.value == -1 or strlen.value == -1 then
 end
 
 var modval = mode.value
+srand_from(0)
 
 if modval == 0 then
        bench_flatstr(nb_ccts.value, loops.value, strlen.value)
 else if modval == 1 then
        bench_flatbuf(nb_ccts.value, loops.value, strlen.value)
+else if modval == 2 then
+       bench_ropestr(nb_ccts.value, loops.value, strlen.value)
+else if modval == 3 then
+       bench_ropebuf(nb_ccts.value, loops.value, strlen.value)
 else
        opts.usage
        exit(-1)
diff --git a/benchmarks/strings/utf_chain_concat.nit b/benchmarks/strings/utf_chain_concat.nit
deleted file mode 100644 (file)
index d720403..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-# 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.
-
-# Benches measuring the performance of several concatenations on Text variants
-module utf_chain_concat
-
-import opts
-import string_experimentations::utf8_noindex
-
-fun bench_flatstr(str_size: Int, nb_ccts: Int, loops: Int)
-do
-       var lft = "a" * str_size
-
-       for i in [0..loops] do
-               var str: String = lft
-               for j in [0..nb_ccts] do
-                       str += lft
-               end
-       end
-end
-
-var opts = new OptionContext
-var nb_ccts = new OptionInt("Number of concatenations per loop", -1, "--ccts")
-var loops = new OptionInt("Number of loops to be done", -1, "--loops")
-var strlen = new OptionInt("Length of the base string", -1, "--strlen")
-opts.add_option(nb_ccts, loops, strlen)
-
-opts.parse(args)
-
-if nb_ccts.value == -1 or loops.value == -1 or strlen.value == -1 then
-       opts.usage
-       exit -1
-end
-
-bench_flatstr(strlen.value, nb_ccts.value, loops.value)
diff --git a/benchmarks/strings/utf_iteration_bench.nit b/benchmarks/strings/utf_iteration_bench.nit
deleted file mode 100644 (file)
index 80277c0..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-# 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.
-
-# Benches for iteration on variants of Text
-module utf_iteration_bench
-
-import opts
-import string_experimentations::utf8_noindex
-
-fun bench_flatstr_iter(nb_cct: Int, loops: Int, strlen: Int)
-do
-       var a = "a" * strlen
-       var x = a.as(FlatString)
-       for i in [0 .. nb_cct] do x = (x + a).as(FlatString)
-       var cnt = 0
-       var c: UnicodeChar
-       while cnt != loops do
-               var it = new FlatStringIter(x)
-               for i in it do
-                       c = i
-               end
-               cnt += 1
-       end
-end
-
-fun bench_flatstr_index(nb_cct: Int, loops: Int, strlen: Int)
-do
-       var a = "a" * strlen
-       var x = a.as(FlatString)
-       for i in [0 .. nb_cct] do x = (x + a).as(FlatString)
-       var cnt = 0
-       var c: UnicodeChar
-       var pos = 0
-       while cnt != loops do
-               pos = 0
-               while pos < x.length do
-                       c = x.char_at(pos)
-                       pos += 1
-               end
-               cnt += 1
-       end
-end
-
-var opts = new OptionContext
-var access_mode = new OptionEnum(["iterator", "index"], "Iteration mode", -1, "--iter-mode")
-var nb_ccts = new OptionInt("Number of concatenations done to the string (in the case of the rope, this will increase its depth)", -1, "--ccts")
-var loops = new OptionInt("Number of loops to be done", -1, "--loops")
-var strlen = new OptionInt("Length of the base string", -1, "--strlen")
-opts.add_option(nb_ccts, loops, strlen, access_mode)
-
-opts.parse(args)
-
-if nb_ccts.value == -1 or loops.value == -1 or strlen.value == -1 then
-       opts.usage
-       exit(-1)
-end
-
-var iterval = access_mode.value
-
-if iterval == 0 then
-       bench_flatstr_iter(nb_ccts.value, loops.value, strlen.value)
-else if iterval == 1 then
-       bench_flatstr_index(nb_ccts.value, loops.value, strlen.value)
-else
-       opts.usage
-       exit(-1)
-end
diff --git a/benchmarks/strings/utf_substr_bench.nit b/benchmarks/strings/utf_substr_bench.nit
deleted file mode 100644 (file)
index 7d71a8b..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-# 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.
-
-# Benches on the substring operation on variants of Text
-module utf_substr_bench
-
-import opts
-import string_experimentations::utf8_noindex
-
-fun bench_flatstr(nb_cct: Int, loops: Int, strlen: Int)
-do
-       var a = "a" * strlen
-       var x = a
-       for i in [0 .. nb_cct] do x += a
-       var cnt = 0
-       while cnt != loops do
-               x.substring(0,5)
-               cnt += 1
-       end
-end
-
-var opts = new OptionContext
-var nb_ccts = new OptionInt("Number of concatenations done to the string (in the case of the rope, this will increase its depth)", -1, "--ccts")
-var loops = new OptionInt("Number of loops to be done", -1, "--loops")
-var strlen = new OptionInt("Length of the base string", -1, "--strlen")
-opts.add_option(nb_ccts, loops, strlen)
-
-opts.parse(args)
-
-if nb_ccts.value == -1 or loops.value == -1 or strlen.value == -1 then
-       opts.usage
-       exit(-1)
-end
-
-bench_flatstr(nb_ccts.value, loops.value, strlen.value)
diff --git a/bin/Makefile b/bin/Makefile
new file mode 100644 (file)
index 0000000..45a278a
--- /dev/null
@@ -0,0 +1,27 @@
+# Copyright 2013 Alexandre Terrasa <alexandre@moz-code.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: run
+
+run: hello_world.jar
+       java -jar hello_world.jar
+
+hello_world.jar: nitj
+       NIT_DIR= ./nitj ../examples/hello_world.nit
+
+nitj:
+       NIT_DIR= ./nitg ../src/nitj.nit
+
+clean:
+       rm -rf -- hello_world.jar .nit_jcompile 2> /dev/null || true
index 35aa64c..bb6d1fa 100644 (file)
@@ -230,11 +230,11 @@ if not opts.errors.is_empty or opts.help.value == true then
 end
 
 var ben = new Benitlux("sherbrooke")
-ben.run(opts.send_emails.value or else false)
+ben.run(opts.send_emails.value)
 
 # The parsing logic for the wellington locaiton is active (to gather data)
 # but the web interface do not allow to subscribe to its mailing list.
 #
 # TODO revamp mailing list Web interface
 ben = new Benitlux("wellington")
-ben.run(opts.send_emails.value or else false)
+ben.run(opts.send_emails.value)
index e32246c..338836b 100644 (file)
@@ -52,7 +52,7 @@ class FlowAnalysis[S]
                        end
 
                        if current_in != null then
-                               in_set(block) = current_in.as(not null)
+                               in_set(block) = current_in
                        else
                                continue
                        end
@@ -61,7 +61,7 @@ class FlowAnalysis[S]
 
                        var old_out = out_set(block)
                        for line in block.lines do
-                               self.current_in = current_in.as(not null)
+                               self.current_in = current_in
                                self.current_out = empty_set
                                pre_line_visit(line)
                                enter_visit(line)
index ec7b374..1b1e686 100644 (file)
@@ -18,7 +18,7 @@
 module calculator_android is
        app_name "app.nit Calc."
        app_version(0, 1, git_revision)
-       java_package "org.nitlanguage.calculator"
+       app_namespace "org.nitlanguage.calculator"
 
        # Lock in portrait mode
        android_manifest_activity """android:screenOrientation="portrait""""
index aac6d47..be92d49 100644 (file)
@@ -15,7 +15,7 @@
 # limitations under the License.
 
 module dino_android is
-       java_package("org.nitlanguage.dino")
+       app_namespace "org.nitlanguage.dino"
 end
 
 import dino
index 8700ab2..f8cff4f 100644 (file)
@@ -15,8 +15,8 @@
 # limitations under the License.
 
 module complete_simple_android is
-       java_package("org.nitlanguage.test_all")
-       target_api_version(19)
+       app_namespace "org.nitlanguage.test_all"
+       target_api_version 19
 end
 
 import test_bundle
index 83c4b4c..0583035 100644 (file)
@@ -103,7 +103,7 @@ class PuzzleProblem
                if x < width-1 then res.add(1)
                if y >= 1 then res.add(-width)
                if y < width-1 then res.add(width)
-               return res.as_random.take_all
+               return res
        end
 
        # Return the state where the tile at hole+action has moved
index 69b5c0d..f406949 100644 (file)
@@ -731,7 +731,7 @@ class SearchNode[S: Object, A]
                print "result:{state}"
                for n in path do
                        var a = n.action
-                       if a != null then print "    + {a or else ""}"
+                       if a != null then print "    + {a}"
                        print "  {n.steps}: {n.state} ({n.cost}$)"
                end
        end
index 41f4830..fb11c65 100644 (file)
@@ -32,7 +32,7 @@ as the launcher name.
 
     Example: `app_name "My App"`
 
-* `java_package` specifies the package used by the generated Java
+* `app_namespace` specifies the package used by the generated Java
 classes and the APK file. Once the application is published, this
 value should not be changed. By default, the compiler will use
 the package `org.nitlanguage.{module_name}`.
index bb512d2..fec387d 100644 (file)
@@ -20,7 +20,6 @@
 # used to tag `ldflags` annotations.
 module aware is
        new_annotation android
-       new_annotation java_package
        new_annotation min_api_version
        new_annotation max_api_version
        new_annotation target_api_version
index f6c2a1b..bdb06c5 100644 (file)
@@ -16,9 +16,9 @@
 
 # Test for app.nit's UI services
 module ui_test is
-       app_name("app.nit UI test")
+       app_name "app.nit UI test"
        app_version(0, 1, git_revision)
-       java_package("org.nitlanguage.ui_test")
+       app_namespace "org.nitlanguage.ui_test"
        android_manifest_activity """android:theme="@android:style/Theme.Light""""
 end
 
index a528d57..f892033 100644 (file)
@@ -16,6 +16,7 @@
 
 module app_base is
        new_annotation app_name
+       new_annotation app_namespace
        new_annotation app_version
 end
 
index 14a67fb..303aae1 100644 (file)
@@ -55,9 +55,13 @@ end
 
 # An abstract 2d line segment
 interface ILine[N: Numeric]
+       # The type of points that ends the segment
        type P: IPoint[N]
 
+       # The point that is the left-end of the segment
        fun point_left: P is abstract
+
+       # The point that is the right-end of the segment
        fun point_right: P is abstract
 
        redef fun to_s do return "{point_left}--{point_right}"
index cc12923..8e70600 100644 (file)
@@ -82,7 +82,7 @@ class GithubCurl
                        if obj isa JsonObject then
                                if obj.keys.has("message") then
                                        var title = "GithubAPIError"
-                                       var msg = obj["message"].to_s or else ""
+                                       var msg = obj["message"].to_s
                                        var err = new GithubError(msg, title)
                                        err.json["requested_uri"] = uri
                                        err.json["status_code"] = response.status_code
diff --git a/lib/html/bootstrap.nit b/lib/html/bootstrap.nit
new file mode 100644 (file)
index 0000000..66befa3
--- /dev/null
@@ -0,0 +1,466 @@
+# 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.
+
+# HTML templates for Bootstrap components.
+#
+# See http://getbootstrap.com/components/
+module bootstrap
+
+import template
+
+# Bootstrap component abstraction.
+#
+# Mainly used to factoryze CSS treatments.
+# Can be used in the future to handle generic stuff like attributes or escaping.
+#
+# TODO merge with html::HTMTag without init conflict?
+# HTMLTag requires the main init to pass a tagname,
+# this was so much verbose here.
+abstract class BSComponent
+       super Template
+
+       # CSS classes to add on this element.
+       var css_classes = new Array[String]
+
+       # Render `self` css clases as a `class` attribute.
+       fun render_css_classes: String do
+               if css_classes.is_empty then return ""
+               return " class=\"{css_classes.join(" ")}\""
+       end
+end
+
+# A `<a>` tag.
+#
+# Not really a Bootstrap component but used in other components
+# that it required its own abstraction.
+#
+# Example:
+# ~~~
+# var lnk = new Link("http://nitlanguage.org", "Nit")
+# assert lnk.write_to_string == "<a href=\"http://nitlanguage.org\">Nit</a>"
+# ~~~
+#
+# Creates a link with a title attribute:
+# ~~~
+# lnk = new Link.with_title("http://nitlanguage.org", "Nit", "Nit homepage")
+# assert lnk.write_to_string == "<a href=\"http://nitlanguage.org\" title=\"Nit homepage\">Nit</a>"
+# ~~~
+class Link
+       super BSComponent
+
+       # URL pointed by this link.
+       var href: String is writable
+
+       # Displayed text.
+       var text: Writable is writable
+
+       # Optional title.
+       var title: nullable String is noinit, writable
+
+       # Creates a link with a `title` attribute.
+       init with_title(href: String, text: Writable, title: nullable String) do
+               self.href = href
+               self.text = text
+               self.title = title
+       end
+
+       redef fun rendering do
+               add "<a{render_css_classes} href=\"{href}\""
+               if title != null then add " title=\"{title.write_to_string}\""
+               add ">{text}</a>"
+       end
+end
+
+# A `<h1>` to `<h6>` tag.
+#
+# Not really a Bootstrap component but used in other components
+# that it required its own abstraction.
+#
+# Example:
+# ~~~
+# var h1 = new Header(1, "Title")
+# assert h1.write_to_string == "<h1>Title</h1>"
+# ~~~
+#
+# With subtext:
+# ~~~
+# var h6 = new Header.with_subtext(6, "Title", "with subtext")
+# assert h6.write_to_string == "<h6>Title<small>with subtext</small></h6>"
+# ~~~
+class Header
+       super BSComponent
+
+       # Header level between 1 and 6.
+       var level: Int
+
+       # Displayed text.
+       var text: Writable
+
+       # Optional subtext.
+       var subtext: nullable Writable is noinit, writable
+
+       # Creates a link with a `title` attribute.
+       init with_subtext(level: Int, text: Writable, subtext: String) do
+               self.level = level
+               self.text = text
+               self.subtext = subtext
+       end
+
+       redef fun rendering do
+               add "<h{level}{render_css_classes}>{text.write_to_string}"
+               if subtext != null then add "<small>{subtext.write_to_string}</small>"
+               add "</h{level}>"
+       end
+end
+
+# An abstract HTML list.
+#
+# Many Bootstrap components are built around a HTML list.
+#
+# Used to factorize behavior between OrderedList and UnorderedList.
+abstract class HTMLList
+       super BSComponent
+
+       # A list contains `<li>` tags as children.
+       #
+       # See ListItem.
+       var items = new Array[ListItem]
+
+       # Adds a new ListItem to `self`.
+       fun add_li(item: ListItem) do items.add item
+
+       # Does `self` contains no items?
+       fun is_empty: Bool do return items.is_empty
+end
+
+# A `<ol>` list tag.
+#
+# Example:
+#
+# ~~~
+# var lst = new OrderedList
+# lst.add_li(new ListItem("foo"))
+# lst.add_li(new ListItem("bar"))
+# lst.add_li(new ListItem("baz"))
+#
+# assert lst.write_to_string == """
+# <ol>
+# <li>foo</li>
+# <li>bar</li>
+# <li>baz</li>
+# </ol>
+# """
+# ~~~
+class OrderedList
+       super HTMLList
+
+       redef fun rendering do
+               addn "<ol{render_css_classes}>"
+               for item in items do add item
+               addn "</ol>"
+       end
+end
+
+# A `<ul>` list tag.
+#
+# Example:
+#
+# ~~~
+# var lst = new UnorderedList
+# lst.add_li(new ListItem("foo"))
+# lst.add_li(new ListItem("bar"))
+# lst.add_li(new ListItem("baz"))
+#
+# assert lst.write_to_string == """
+# <ul>
+# <li>foo</li>
+# <li>bar</li>
+# <li>baz</li>
+# </ul>
+# """
+# ~~~
+class UnorderedList
+       super HTMLList
+
+       redef fun rendering do
+               addn "<ul{render_css_classes}>"
+               for item in items do add item
+               addn "</ul>"
+       end
+end
+
+# A `<li>` tag.
+class ListItem
+       super BSComponent
+
+       # Content to display in this list item.
+       var text: Writable is writable
+
+       redef fun rendering do addn "<li{render_css_classes}>{text.write_to_string}</li>"
+end
+
+# A Boostrap icon.
+#
+# See http://getbootstrap.com/components/#glyphicons
+#
+# Example:
+#
+# ~~~
+# var icon = new BSIcon("star")
+# assert icon.write_to_string == "<span class=\"glyphicon glyphicon-star\" aria-hidden=\"true\"></span>"
+# ~~~
+class BSIcon
+       super BSComponent
+
+       # Glyphicon name to display.
+       #
+       # See full list at http://getbootstrap.com/components/#glyphicons.
+       var icon: String
+
+       init do css_classes.add "glyphicon glyphicon-{icon}"
+
+       redef fun rendering do
+               add "<span{render_css_classes} aria-hidden=\"true\"></span>"
+       end
+end
+
+# A Bootstrap breadcrumbs component.
+#
+# See http://getbootstrap.com/components/#breadcrumbs
+#
+# Example:
+#
+# ~~~
+# var bc = new BSBreadCrumbs
+# bc.add_li(new ListItem("foo"))
+# bc.add_li(new ListItem("bar"))
+# bc.add_li(new ListItem("baz"))
+#
+# assert bc.write_to_string == """
+# <ol class=\"breadcrumbs\">
+# <li>foo</li>
+# <li>bar</li>
+# <li class=\"active\">baz</li>
+# </ol>
+# """
+# ~~~
+class BSBreadCrumbs
+       super OrderedList
+
+       init do css_classes.add "breadcrumbs"
+
+       redef fun rendering do
+               items.last.css_classes.add "active"
+               super
+       end
+end
+
+# A Bootstrap label component.
+#
+# See http://getbootstrap.com/components/#labels
+#
+# Example:
+#
+# ~~~
+# var lbl = new BSLabel("danger", "Danger!")
+# assert lbl.write_to_string == "<span class=\"label label-danger\">Danger!</span>"
+# ~~~
+class BSLabel
+       super BSComponent
+
+       # Class used to change the color of the label.
+       #
+       # Can be one of `default`, `primary`, `success`, `info`, `warning` or `danger`.
+       var color: String
+
+       # Text to display in the label.
+       var text: Writable
+
+       init do css_classes.add "label label-{color}"
+
+       redef fun rendering do
+               add "<span{render_css_classes}>{text.write_to_string}</span>"
+       end
+end
+
+# A Bootstrap badge component.
+#
+# See http://getbootstrap.com/components/#badges
+#
+# Example:
+#
+# ~~~
+# var b = new BSBadge("42 messages")
+# assert b.write_to_string == "<span class=\"badge\">42 messages</span>"
+# ~~~
+class BSBadge
+       super BSComponent
+
+       # Text to display in the label.
+       var text: Writable
+
+       init do css_classes.add "badge"
+
+       redef fun rendering do
+               add "<span{render_css_classes}>{text.write_to_string}</span>"
+       end
+end
+
+# A Bootstrap page header component.
+#
+# See http://getbootstrap.com/components/#page-header
+#
+# Example:
+#
+# ~~~
+# var h = new BSPageHeader("Welcome")
+# assert h.write_to_string == """
+# <div class=\"page-header\">
+# Welcome
+# </div>
+# """
+# ~~~
+class BSPageHeader
+       super BSComponent
+
+       # Text to display as title.
+       var text: Writable
+
+       init do css_classes.add "page-header"
+
+       redef fun rendering do
+               addn "<div{render_css_classes}>"
+               addn text.write_to_string
+               addn "</div>"
+       end
+end
+
+# A Bootstrap alert component.
+#
+# See http://getbootstrap.com/components/#alerts
+#
+# Example:
+#
+# ~~~
+# var alert = new BSAlert("danger", "Danger!")
+# assert alert.write_to_string == """
+# <div class="alert alert-danger">
+# Danger!
+# </div>
+# """
+# ~~~
+class BSAlert
+       super BSComponent
+
+       # Class used to change the color of the alert.
+       #
+       # Can be one of `primary`, `success`, `info`, `warning` or `danger`.
+       var color: String
+
+       # Text to display in the alert.
+       var text: Writable
+
+       # Can the alert be dismissed by clicking the close button?
+       #
+       # See http://getbootstrap.com/components/#alerts-dismissible
+       #
+       # Default is `false`.
+       var is_dismissible = false
+
+       init do css_classes.add "alert alert-{color}"
+
+       redef fun rendering do
+               addn "<div{render_css_classes}>"
+               if is_dismissible then
+                       add "<button type=\"button\" class=\"close\" data-dismiss=\"alert\""
+                       add "aria-label=\"Close\"><span aria-hidden=\"true\">&times;</span>"
+                       addn "</button>"
+               end
+               addn text.write_to_string
+               addn "</div>"
+       end
+end
+
+# A Bootstrap panel component.
+#
+# See http://getbootstrap.com/components/#panels
+#
+# Example:
+#
+# ~~~
+# var p = new BSPanel("default", "Panel content")
+#
+# assert p.write_to_string == """
+# <div class="panel panel-default">
+# <div class="panel-body">
+# Panel content
+# </div>
+# </div>
+# """
+# ~~~
+#
+# Panel with heading:
+#
+# ~~~
+# p = new BSPanel("danger", "Panel content")
+# p.heading = "Panel heading"
+#
+# assert p.write_to_string == """
+# <div class="panel panel-danger">
+# <div class="panel-heading">
+# Panel heading
+# </div>
+# <div class="panel-body">
+# Panel content
+# </div>
+# </div>
+# """
+# ~~~
+class BSPanel
+       super BSComponent
+
+       # Panel color.
+       #
+       # Can be one of `default`, `primary`, `success`, `info`, `warning` or `danger`.
+       var color: String
+
+       # Panel header if any.
+       var heading: nullable Writable is noinit, writable
+
+       # Body to display in the panel.
+       var body: Writable
+
+       # Panel footer is any.
+       var footer: nullable Writable is noinit, writable
+
+       init do css_classes.add "panel panel-{color}"
+
+       redef fun rendering do
+               addn "<div{render_css_classes}>"
+               if heading != null then
+                       addn "<div class=\"panel-heading\">"
+                       addn heading.write_to_string
+                       addn "</div>"
+               end
+               addn "<div class=\"panel-body\">"
+               addn body.write_to_string
+               addn "</div>"
+               if footer != null then
+                       addn "<div class=\"panel-footer\">"
+                       addn footer.write_to_string
+                       addn "</div>"
+               end
+               addn "</div>"
+       end
+end
diff --git a/lib/ios/app.nit b/lib/ios/app.nit
new file mode 100644 (file)
index 0000000..0e337bc
--- /dev/null
@@ -0,0 +1,191 @@
+# 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.
+
+# Basic structure for Nit apps on iOS
+module app
+
+import platform
+import ::app
+
+in "ObjC Header" `{
+       #import <UIKit/UIKit.h>
+
+       // Our interface to the iOS system
+       @interface AppDelegate: UIResponder <UIApplicationDelegate>
+
+               // The main window
+               @property (strong, nonatomic) UIWindow *window;
+       @end
+`}
+
+in "ObjC" `{
+
+       // Global reference to the App from app.nit
+       App app_nit_ios_app;
+
+       // Our own C argc and argv
+       int app_nit_ios_argc;
+       char **app_nit_ios_argv;
+
+       @implementation AppDelegate
+
+       - (BOOL)application:(UIApplication *)application
+               willFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
+
+               // Set aside `application` to be used from Nit
+               App_ui_application__assign(app_nit_ios_app, application);
+               App_app_delegate__assign(app_nit_ios_app, self);
+
+               // Complete the callback
+               return App_will_finish_launching_with_options(app_nit_ios_app);
+       }
+
+       - (BOOL)application:(UIApplication *)application
+               didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
+
+               return App_did_finish_launching_with_options(app_nit_ios_app);
+       }
+
+       - (void)applicationWillResignActive:(UIApplication *)application {
+               App_will_resign_active(app_nit_ios_app);
+       }
+
+       - (void)applicationDidEnterBackground:(UIApplication *)application {
+               App_did_enter_background(app_nit_ios_app);
+       }
+
+       - (void)applicationWillEnterForeground:(UIApplication *)application {
+               App_will_enter_foreground(app_nit_ios_app);
+       }
+
+       - (void)applicationDidBecomeActive:(UIApplication *)application {
+               App_did_become_active(app_nit_ios_app);
+       }
+
+       - (void)applicationWillTerminate:(UIApplication *)application {
+               App_will_terminate(app_nit_ios_app);
+       }
+
+       @end
+`}
+
+# Application interface to the iOS system
+extern class AppDelegate in "ObjC" `{ AppDelegate * `}
+end
+
+# Graphical application to which events are sent
+extern class UIApplication in "ObjC" `{ UIApplication * `}
+end
+
+redef class App
+
+       # Main graphical application
+       var ui_application: UIApplication
+
+       # Application interface to the iOS system
+       var app_delegate: AppDelegate
+
+       # Copy back to C the command line arguments
+       #
+       # Nit extracts the first arguments from the `args` sequence,
+       # so we need to add it back. That's why Nit's `args` is smaller than in C.
+       private fun register_args(program_name: NativeString, argc: Int,
+       argv: Sequence[String]) import Sequence[String].[], String.to_cstring in "ObjC" `{
+               app_nit_ios_argc = argc+1;
+
+               // TODO copy or pin the strings when needed
+               app_nit_ios_argv = malloc(argc * sizeof(char*));
+               app_nit_ios_argv[0] = program_name;
+               for (int i = 0; i < argc; i ++) {
+                       String arg = Sequence_of_String__index(argv, i);
+                       app_nit_ios_argv[i+1] = String_to_cstring(arg);
+               }
+       `}
+
+       # Register `self` globally in C so it can be retrieved from iOS callbacks
+       private fun register_globally in "ObjC" `{
+               App_incr_ref(recv);
+               app_nit_ios_app = recv;
+       `}
+
+       # Entry point to the iOS framework
+       private fun ui_application_main: Bool import did_finish_launching_with_options,
+       will_finish_launching_with_options,
+       will_resign_active, did_enter_background, will_enter_foreground,
+       did_become_active, will_terminate, ui_application=, app_delegate= in "ObjC" `{
+
+               @autoreleasepool {
+                       return UIApplicationMain(app_nit_ios_argc, app_nit_ios_argv,
+                               nil, NSStringFromClass([AppDelegate class]));
+               }
+       `}
+
+       # The application is about to launch
+       #
+       # Redef this method to set the very first custom code to be executed.
+       fun will_finish_launching_with_options: Bool do return true
+
+       # The application just launched but is not yet displayed to the user
+       #
+       # Redef this method to customize the behavior.
+       fun did_finish_launching_with_options: Bool do return true
+
+       # The application is about to move from active to inactive state
+       #
+       # This can occur for certain types of temporary interruptions
+       # (such as an incoming phone call or SMS message) or when the
+       # user quits the application and it begins the transition to
+       # the background state.
+       #
+       # Redef this method to pause ongoing tasks, disable timers, and
+       # throttle down OpenGL ES frame rates. Games should use this
+       # method to pause.
+       fun will_resign_active do end
+
+       # The application just left foreground it can be suspended at any time
+       #
+       # Redef this method to release shared resources, save user data,
+       # invalidate timers, and store application state to restore your
+       # application to its current state in case it is terminated later.
+       #
+       # If your application supports background execution, this method
+       # is called instead of `will_terminate` when the user quits.
+       fun did_enter_background do end
+
+       # The application will enter the foreground
+       #
+       # Called as part of the transition from the background to the
+       # inactive state.
+       #
+       # Redef to und changes made on entering the background.
+       fun will_enter_foreground do end
+
+       # The application just became active
+       #
+       # Redef to restart any tasks that were paused (or not yet started) while
+       # the application was inactive. If the application was previously
+       # in the background, optionally refresh the user interface.
+       fun did_become_active do end
+
+       # The application is about to terminate (not suspended)
+       #
+       # Redef to save data if appropriate.
+       fun will_terminate do end
+end
+
+app.register_args(program_name.to_cstring, args.length, args)
+app.register_globally
+
+var ret = app.ui_application_main
+exit if ret then 0 else 1
diff --git a/lib/ios/examples/hello_ios.nit b/lib/ios/examples/hello_ios.nit
new file mode 100644 (file)
index 0000000..3269906
--- /dev/null
@@ -0,0 +1,54 @@
+# 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.
+
+# Simple iOS app with a single label
+module hello_ios is
+       app_name "Hello iOS"
+       app_namespace "nit.app.hello_ios"
+       app_version(0, 5, git_revision)
+end
+
+import ios
+
+redef class App
+       redef fun did_finish_launching_with_options
+       do
+               return app_delegate.hello_world
+       end
+end
+
+redef class AppDelegate
+
+       # Print and show "Hello World!"
+       private fun hello_world: Bool in "ObjC" `{
+
+               // Print to the console
+               NSLog(@"Hello World!");
+
+               // Display "Hello world!" on the screen
+               recv.window = [[UIWindow alloc] initWithFrame:
+               [[UIScreen mainScreen] bounds]];
+               recv.window.backgroundColor = [UIColor whiteColor];
+
+               UILabel *label = [[UILabel alloc] init];
+               label.text = @"Hello World!";
+               label.center = CGPointMake(100, 100);
+               [label sizeToFit];
+
+               [recv.window addSubview: label];
+               [recv.window makeKeyAndVisible];
+
+               return YES;
+       `}
+end
diff --git a/lib/ios/ios.nit b/lib/ios/ios.nit
new file mode 100644 (file)
index 0000000..9d5079d
--- /dev/null
@@ -0,0 +1,19 @@
+# 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.
+
+# iOS services for Nit app on iOS
+module ios
+
+import platform
+import app
diff --git a/lib/ios/platform.nit b/lib/ios/platform.nit
new file mode 100644 (file)
index 0000000..47d1536
--- /dev/null
@@ -0,0 +1,16 @@
+# 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.
+
+# Triggers compilation for the iOS platform
+module platform is platform "ios"
diff --git a/lib/pthreads/examples/threaded_example.nit b/lib/pthreads/examples/threaded_example.nit
new file mode 100644 (file)
index 0000000..175c753
--- /dev/null
@@ -0,0 +1,30 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2015 Romain Chanoir <romain.chanoir@viacesi.fr>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# test for threaded annotation
+module threaded_example
+
+import pthreads
+
+# the "is threaded" annotation makes this fun run on an other thread
+fun foo is threaded do
+       sys.nanosleep(1,0)
+       print "threaded"
+end
+
+foo
+print "main"
+sys.nanosleep(2,0)
index 5d6b80d..8b8de1f 100644 (file)
@@ -19,6 +19,7 @@ module pthreads is
        cflags "-pthread"
        ldflags "-pthread"
        pkgconfig "bdw-gc"
+       new_annotation threaded
 end
 
 #
index d51e710..1b1e71e 100644 (file)
@@ -66,6 +66,14 @@ interface Collection[E]
        #     assert [1..1[.is_empty   == true
        fun is_empty: Bool do return length == 0
 
+       # Alias for `not is_empty`.
+       #
+       # Some people prefer to have conditions grammatically easier to read.
+       #
+       #     assert [1,2,3].not_empty  == true
+       #     assert [1..1[.not_empty   == false
+       fun not_empty: Bool do return not self.is_empty
+
        # Number of items in the collection.
        #
        #     assert [10,20,30].length == 3
index 233621e..3cc0b57 100644 (file)
@@ -13,7 +13,9 @@
 
 # This module introduces the standard array structure.
 # It also implements two other abstract collections : ArrayMap and ArraySet
-module array
+module array is
+       no_warning "useless-type-test" # to avoid warning with nitc while compiling with c_src
+end
 
 import abstract_collection
 
index cfcc376..00c45a3 100644 (file)
@@ -250,6 +250,81 @@ interface Comparator
 
 end
 
+redef class MapRead[K,V]
+       # Return an array of all values sorted with their keys using `comparator`.
+       #
+       # ~~~
+       # var map = new HashMap[Int, String]
+       # map[10] = "ten"
+       # map[2]  = "two"
+       # map[1]  = "one"
+       # assert map.values_sorted_by_key(default_comparator) == ["one", "two", "ten"]
+       # assert map.values_sorted_by_key(alpha_comparator) == ["one", "ten", "two"]
+       # ~~~
+       fun values_sorted_by_key(comparator: Comparator): Array[V]
+       do
+               var keys = self.keys.to_a
+               comparator.sort(keys)
+               return [for k in keys do self[k]]
+       end
+
+       # Return an array of all keys sorted with their values using `comparator`.
+       #
+       # ~~~
+       # var map = new HashMap[String, Int]
+       # map["ten"] = 10
+       # map["two"] = 2
+       # map["one"] = 1
+       # assert map.keys_sorted_by_values(default_comparator) == ["one", "two", "ten"]
+       # assert map.keys_sorted_by_values(alpha_comparator) == ["one", "ten", "two"]
+       # ~~~
+       #
+       # See: `to_map_comparator` to get the comparator used internally.
+       fun keys_sorted_by_values(comparator: Comparator): Array[K]
+       do
+               var keys = self.keys.to_a
+               var map_cmp = to_map_comparator(comparator)
+               map_cmp.sort(keys)
+               return keys
+       end
+
+       # A comparator that compares things with their values in self.
+       #
+       # See `MapComparator` for details.
+       fun to_map_comparator(comparator: Comparator): MapComparator[K, V] do return new MapComparator[K,V](self, comparator)
+end
+
+# A comparator that compares things with their values in a map.
+#
+# ~~~
+# var map = new HashMap[String, Int]
+# map["ten"] = 10
+# map["two"] = 2
+# map["one"] = 1
+#
+# var map_cmp = map.to_map_comparator(default_comparator)
+# var a = ["ten", "one", "two"]
+# map_cmp.sort(a)
+# assert a == ["one", "two", "ten"]
+# map_cmp = map.to_map_comparator(alpha_comparator)
+# map_cmp.sort(a)
+# assert a == ["one", "ten", "two"]
+# ~~~
+class MapComparator[K,V]
+       super Comparator
+
+       # What is compared are the keys of the values
+       redef type COMPARED: K
+
+       # The map that associates compared elements to the value used to compare them
+       var map: MapRead[K,V]
+
+       # The comparator used to compare values
+       var comparator: Comparator
+
+       redef fun compare(a,b) do return comparator.compare(map[a], map[b])
+end
+
 # This comparator uses the operator `<=>` to compare objects.
 # see `default_comparator` for an easy-to-use general stateless default comparator.
 class DefaultComparator
index 4df80b5..12c9c86 100644 (file)
@@ -33,10 +33,46 @@ import hash_collection
 # The methods `in_same_subset`, `to_partitions`, and their variations are offered instead.
 class DisjointSet[E]
        super SimpleCollection[E]
+       super Cloneable
 
        # The node in the hiearchical structure for each element
        private var nodes = new HashMap[E, DisjointSetNode]
 
+       # Copy constructor
+       init from(other: DisjointSet[E])
+       do
+               # Associate a root node in other to the associated root node in self
+               var map = new HashMap[DisjointSetNode, DisjointSetNode]
+               for e, v in other.nodes do
+                       # Create the associated node
+                       var n2 = new DisjointSetNode
+                       nodes[e] = n2
+
+                       # Get the root node in other and the associated one in self
+                       var p = other.find(e)
+                       var p2 = map.get_or_null(p)
+                       if p2 == null then
+                               # if no associated root node, then a new subset is created
+                               map[p] = n2.parent
+                               number_of_subsets += 1
+                       else
+                               # else attach the new node to the subset of the root node
+                               n2.parent = p2
+                       end
+               end
+       end
+
+       # Shallow copy
+       #
+       #     var s = new DisjointSet[Int]
+       #     s.add_all([1,2,3,4,5])
+       #     s.union_all([1,4,5])
+       #     var s2 = s.clone
+       #     assert s2.number_of_subsets == 3
+       #     assert s2.all_in_same_subset([1,4,5]) == true
+       #     assert s2.in_same_subset(1,2) == false
+       redef fun clone do return new DisjointSet[E].from(self)
+
        # The number of subsets in the partition
        #
        #     var s = new DisjointSet[Int]
index 5b5ffbb..93f5f9b 100644 (file)
@@ -149,4 +149,5 @@ int string_NativeString_NativeString_system_0(const char *cmd) {
                // cmd exited on SIGINT: in my opinion the user wants the main to be discontinued
                kill(getpid(), SIGINT);
        }
+       return status;
 }
index a2856ae..81341ad 100644 (file)
@@ -47,6 +47,21 @@ abstract class FileStream
        # File descriptor of this file
        fun fd: Int do return _file.fileno
 
+       redef fun close
+       do
+               if _file == null then return
+               if _file.address_is_null then
+                       if last_error != null then return
+                       last_error = new IOError("Cannot close unopened file")
+                       return
+               end
+               var i = _file.io_close
+               if i != 0 then
+                       last_error = new IOError("Close failed due to error {sys.errno.strerror}")
+               end
+               _file = null
+       end
+
        # Sets the buffering mode for the current FileStream
        #
        # If the buf_size is <= 0, its value will be 512 by default
@@ -89,11 +104,9 @@ class FileReader
 
        redef fun close
        do
-               if _file == null or _file.address_is_null then return
-               var i = _file.io_close
+               super
                _buffer.clear
                end_reached = true
-               _file = null
        end
 
        redef fun fill_buffer
@@ -122,6 +135,7 @@ class FileReader
                end
        end
 
+       # Creates a new File stream from a file descriptor
        init from_fd(fd: Int) do
                self.path = ""
                prepare_buffer(1)
@@ -154,19 +168,8 @@ class FileWriter
 
        redef fun close
        do
-               if _file == null then return
-               if _file.address_is_null then
-                       if last_error != null then return
-                       last_error = new IOError("Cannot close unopened write stream")
-                       _is_writable = false
-                       return
-               end
-               var i = _file.io_close
-               if i != 0 then
-                       last_error = new IOError("Close failed due to error {sys.errno.strerror}")
-               end
+               super
                _is_writable = false
-               _file = null
        end
        redef var is_writable = false
 
index 4892f95..409b4ed 100644 (file)
@@ -531,6 +531,14 @@ abstract class Text
        #
        #     assert "abAB12<>&".escape_to_c         == "abAB12<>&"
        #     assert "\n\"'\\".escape_to_c         == "\\n\\\"\\'\\\\"
+       #
+       # Most non-printable characters (bellow ASCII 32) are escaped to an octal form `\nnn`.
+       # Three digits are always used to avoid following digits to be interpreted as an element
+       # of the octal sequence.
+       #
+       #     assert "{0.ascii}{1.ascii}{8.ascii}{31.ascii}{32.ascii}".escape_to_c == "\\000\\001\\010\\037 "
+       #
+       # The exceptions are the common `\t` and `\n`.
        fun escape_to_c: String
        do
                var b = new FlatBuffer
@@ -538,8 +546,10 @@ abstract class Text
                        var c = chars[i]
                        if c == '\n' then
                                b.append("\\n")
+                       else if c == '\t' then
+                               b.append("\\t")
                        else if c == '\0' then
-                               b.append("\\0")
+                               b.append("\\000")
                        else if c == '"' then
                                b.append("\\\"")
                        else if c == '\'' then
@@ -547,7 +557,17 @@ abstract class Text
                        else if c == '\\' then
                                b.append("\\\\")
                        else if c.ascii < 32 then
-                               b.append("\\{c.ascii.to_base(8, false)}")
+                               b.add('\\')
+                               var oct = c.ascii.to_base(8, false)
+                               # Force 3 octal digits since it is the
+                               # maximum allowed in the C specification
+                               if oct.length == 1 then
+                                       b.add('0')
+                                       b.add('0')
+                               else if oct.length == 2 then
+                                       b.add('0')
+                               end
+                               b.append(oct)
                        else
                                b.add(c)
                        end
@@ -844,6 +864,23 @@ abstract class FlatText
        # Real items, used as cache for to_cstring is called
        private var real_items: nullable NativeString = null
 
+       # Returns a char* starting at position `index_from`
+       #
+       # WARNING: If you choose to use this service, be careful of the following.
+       #
+       # Strings and NativeString are *ideally* always allocated through a Garbage Collector.
+       # Since the GC tracks the use of the pointer for the beginning of the char*, it may be
+       # deallocated at any moment, rendering the pointer returned by this function invalid.
+       # Any access to freed memory may very likely cause undefined behaviour or a crash.
+       # (Failure to do so will most certainly result in long and painful debugging hours)
+       #
+       # The only safe use of this pointer is if it is ephemeral (e.g. read in a C function
+       # then immediately return).
+       #
+       # As always, do not modify the content of the String in C code, if this is what you want
+       # copy locally the char* as Nit Strings are immutable.
+       private fun fast_cstring: NativeString is abstract
+
        redef var length: Int = 0
 
        redef fun output
@@ -1099,6 +1136,8 @@ class FlatString
                return native.to_s_with_length(self.length)
        end
 
+       redef fun fast_cstring do return items.fast_cstring(index_from)
+
        redef fun substring(from, count)
        do
                assert count >= 0
@@ -1547,6 +1586,8 @@ class FlatBuffer
 
        private var capacity: Int = 0
 
+       redef fun fast_cstring do return items.fast_cstring(0)
+
        redef fun substrings do return new FlatSubstringsIter(self)
 
        # Re-copies the `NativeString` into a new one and sets it as the new `Buffer`
@@ -2269,6 +2310,12 @@ extern class NativeString `{ char* `}
        # Creates a new NativeString with a capacity of `length`
        new(length: Int) is intern
 
+       # Returns a char* starting at `index`.
+       #
+       # WARNING: Unsafe for extern code, use only for temporary
+       # pointer manipulation purposes (e.g. write to file or such)
+       fun fast_cstring(index: Int): NativeString is intern
+
        # Get char at `index`.
        fun [](index: Int): Char is intern
 
index 6160b1a..3150c5f 100644 (file)
@@ -55,8 +55,6 @@ class TmplComposer
        # Short name
        var name: String
 
-       init(name: String) do self.name = name
-
        redef fun rendering do add "- {name}\n"
 end
 
@@ -69,13 +67,6 @@ class TmplComposerDetail
        var birth: Int
        var death: Int
 
-       init(firstname, lastname: String, birth, death: Int) do
-               self.firstname = firstname
-               self.lastname = lastname
-               self.birth = birth
-               self.death = death
-       end
-
        redef fun rendering do add """
 
 COMPOSER: {{{firstname}}} {{{lastname}}}
index 658f0e7..3956744 100644 (file)
@@ -23,6 +23,7 @@ import platform
 import c_tools
 private import annotation
 import mixin
+import counter
 
 # Add compiling options
 redef class ToolContext
@@ -121,20 +122,30 @@ redef class ModelBuilder
        protected fun write_and_make(compiler: AbstractCompiler)
        do
                var platform = compiler.target_platform
-               var toolchain = platform.toolchain(toolcontext)
+               var toolchain = platform.toolchain(toolcontext, compiler)
                compile_dir = toolchain.compile_dir
-               toolchain.write_and_make compiler
+               toolchain.write_and_make
        end
 end
 
 redef class Platform
        # The specific tool-chain associated to the platform
-       fun toolchain(toolcontext: ToolContext): Toolchain do return new MakefileToolchain(toolcontext)
+       fun toolchain(toolcontext: ToolContext, compiler: AbstractCompiler): Toolchain
+       do
+               return new MakefileToolchain(toolcontext, compiler)
+       end
 end
 
+# Build toolchain for a specific target program, varies per `Platform`
 class Toolchain
+
+       # Toolcontext
        var toolcontext: ToolContext
 
+       # Compiler of the target program
+       var compiler: AbstractCompiler
+
+       # Directory where to generate all C files
        fun compile_dir: String
        do
                var compile_dir = toolcontext.opt_compile_dir.value
@@ -142,13 +153,15 @@ class Toolchain
                return compile_dir
        end
 
-       fun write_and_make(compiler: AbstractCompiler) is abstract
+       # Write all C files and compile them
+       fun write_and_make is abstract
 end
 
+# Default toolchain using a Makefile
 class MakefileToolchain
        super Toolchain
 
-       redef fun write_and_make(compiler)
+       redef fun write_and_make
        do
                var compile_dir = compile_dir
 
@@ -161,11 +174,11 @@ class MakefileToolchain
                compile_dir.mkdir
 
                var cfiles = new Array[String]
-               write_files(compiler, compile_dir, cfiles)
+               write_files(compile_dir, cfiles)
 
                # Generate the Makefile
 
-               write_makefile(compiler, compile_dir, cfiles)
+               write_makefile(compile_dir, cfiles)
 
                var time1 = get_time
                self.toolcontext.info("*** END WRITING C: {time1-time0} ***", 2)
@@ -177,13 +190,14 @@ class MakefileToolchain
                time0 = time1
                self.toolcontext.info("*** COMPILING C ***", 1)
 
-               compile_c_code(compiler, compile_dir)
+               compile_c_code(compile_dir)
 
                time1 = get_time
                self.toolcontext.info("*** END COMPILING C: {time1-time0} ***", 2)
        end
 
-       fun write_files(compiler: AbstractCompiler, compile_dir: String, cfiles: Array[String])
+       # Write all source files to the `compile_dir`
+       fun write_files(compile_dir: String, cfiles: Array[String])
        do
                var platform = compiler.target_platform
                if self.toolcontext.opt_stacktrace.value == "nitstack" and platform.supports_libunwind then compiler.build_c_to_nit_bindings
@@ -280,17 +294,14 @@ class MakefileToolchain
                self.toolcontext.info("Total C source files to compile: {cfiles.length}", 2)
        end
 
-       fun makefile_name(mainmodule: MModule): String do return "{mainmodule.c_name}.mk"
+       # Get the name of the Makefile to use
+       fun makefile_name: String do return "{compiler.mainmodule.c_name}.mk"
 
-       fun default_outname(mainmodule: MModule): String
+       # Get the default name of the executable to produce
+       fun default_outname: 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
+               var mainmodule = compiler.mainmodule.first_real_mmodule
+               return mainmodule.name
        end
 
        # Combine options and platform informations to get the final path of the outfile
@@ -298,13 +309,14 @@ class MakefileToolchain
        do
                var res = self.toolcontext.opt_output.value
                if res != null then return res
-               res = default_outname(mainmodule)
+               res = default_outname
                var dir = self.toolcontext.opt_dir.value
                if dir != null then return dir.join_path(res)
                return res
        end
 
-       fun write_makefile(compiler: AbstractCompiler, compile_dir: String, cfiles: Array[String])
+       # Write the Makefile
+       fun write_makefile(compile_dir: String, cfiles: Array[String])
        do
                var mainmodule = compiler.mainmodule
                var platform = compiler.target_platform
@@ -319,7 +331,7 @@ class MakefileToolchain
                        # 2. copy the binary at the right place in the `all` goal.
                        outpath = mainmodule.c_name
                end
-               var makename = makefile_name(mainmodule)
+               var makename = makefile_name
                var makepath = "{compile_dir}/{makename}"
                var makefile = new FileWriter.open(makepath)
 
@@ -444,9 +456,10 @@ endif
                makepath.file_copy_to "{compile_dir}/Makefile"
        end
 
-       fun compile_c_code(compiler: AbstractCompiler, compile_dir: String)
+       # The C code is generated, compile it to an executable
+       fun compile_c_code(compile_dir: String)
        do
-               var makename = makefile_name(compiler.mainmodule)
+               var makename = makefile_name
 
                var makeflags = self.toolcontext.opt_make_flags.value
                if makeflags == null then makeflags = ""
@@ -589,6 +602,8 @@ abstract class AbstractCompiler
                self.header.add_decl("#include <stdlib.h>")
                self.header.add_decl("#include <stdio.h>")
                self.header.add_decl("#include <string.h>")
+               self.header.add_decl("#include <sys/types.h>\n")
+               self.header.add_decl("#include <unistd.h>\n")
                self.header.add_decl("#include \"gc_chooser.h\"")
                self.header.add_decl("#ifdef ANDROID")
                self.header.add_decl("  #include <android/log.h>")
@@ -1021,14 +1036,6 @@ extern void nitni_global_ref_decr( struct nitni_ref *ref ) {
        end
 
        fun finalize_ffi_for_module(mmodule: MModule) do mmodule.finalize_ffi(self)
-
-       # Division facility
-       # Avoid division by zero by returning the string "n/a"
-       fun div(a,b:Int):String
-       do
-               if b == 0 then return "n/a"
-               return ((a*10000/b).to_f / 100.0).to_precision(2)
-       end
 end
 
 # A file unit (may be more than one file if
@@ -2190,6 +2197,9 @@ redef class AMethPropdef
                        else if pname == "atoi" then
                                v.ret(v.new_expr("atoi({arguments[0]});", ret.as(not null)))
                                return true
+                       else if pname == "fast_cstring" then
+                               v.ret(v.new_expr("{arguments[0]} + {arguments[1]}", ret.as(not null)))
+                               return true
                        else if pname == "new" then
                                v.ret(v.new_expr("(char*)nit_alloc({arguments[1]})", ret.as(not null)))
                                return true
@@ -2360,7 +2370,7 @@ redef class AAttrPropdef
                var oldnode = v.current_node
                v.current_node = self
                var old_frame = v.frame
-               var frame = new StaticFrame(v, self.mpropdef.as(not null), recv.mcasttype.as_notnullable.as(MClassType), [recv])
+               var frame = new StaticFrame(v, self.mpropdef.as(not null), recv.mcasttype.undecorate.as(MClassType), [recv])
                v.frame = frame
 
                var value
index b2f4837..e2afc48 100644 (file)
@@ -17,7 +17,7 @@ module coloring
 import poset
 
 # Build a conflict graph from a POSet
-class POSetConflictGraph[E: Object]
+class POSetConflictGraph[E]
 
        # Core is composed by:
        #  * elements that have mutiple direct parents
@@ -45,13 +45,18 @@ class POSetConflictGraph[E: Object]
        # REQUIRE: is_colored
        var conflicts = new HashMap[E, Set[E]]
 
+       # The associated poset
        var poset: POSet[E]
 
+       # The linearisation order to visit elements in the poset
+       var order: Array[E] is noinit
+
        init do
                extract_core
                extract_border
                extract_crown
                compute_conflicts
+               order = poset.linearize(poset)
        end
 
        # Compute the set of elements forming the core of the poset hierarchy.
@@ -116,10 +121,14 @@ class POSetConflictGraph[E: Object]
                #print "border: {border.join(" ")} ({border.length})"
                #print "crown: {crown.join(" ")} ({crown.length})"
                print "conflicts:"
-               for e, c in conflicts do print "  {e}: {c.join(" ")}"
+               for e, c in conflicts do print "  {e or else "NULL"}: {c.join(" ")}"
        end
 end
 
+redef class POSet[E]
+       fun to_conflict_graph: POSetConflictGraph[E] do return new POSetConflictGraph[E](self)
+end
+
 # Colorize elements from a POSet
 # Two elements from a POSet cannot have the same color if they share common subelements
 #
@@ -265,6 +274,166 @@ class POSetColorer[E: Object]
        end
 end
 
+# Colorize elements `E` introduced by holders `H` in a `POSet`.
+#
+# Two elements cannot have the same color if they are introduced or inherited by a same holder.
+class POSetGroupColorer[H: Object, E: Object]
+
+       # The associated conflict graph containing the poset.
+       #
+       # The conflict graph is used instead of the original poset so that the conflict graph can be reused
+       # in different coloration based on the same poset.
+       var graph: POSetConflictGraph[H]
+
+       # The elements to color.
+       #
+       # For each holder, the collection of introduced elements is given.
+       #
+       # A single element must not be introduced in more than one holder.
+       var buckets: Map[H, Collection[E]]
+
+       # The associated poset.
+       #
+       # alias for `graph.poset`
+       fun poset: POSet[H] do return graph.poset
+
+       # The resulting coloring
+       #
+       # Each element from buckets is associated to its own color
+       var colors: Map[E, Int] is lazy do
+               for h in graph.poset do
+                       used_colors[h] = new HashSet[Int]
+               end
+               compute_colors
+               return colors_cache
+       end
+
+       # Resulting colors
+       private var colors_cache = new HashMap[E, Int]
+
+       # Set of known used colors
+       private var used_colors = new HashMap[H, HashSet[Int]]
+
+       # Build table layout of elements `E` for the holder `h`.
+       #
+       # `null` is used to fill places without elements (holes).
+       fun build_layout(h: H): Array[nullable E]
+       do
+               var table = new Array[nullable E]
+               for s in poset[h].greaters do
+                       var bucket = buckets.get_or_null(s)
+                       if bucket == null then continue
+                       for e in bucket do
+                               var color = colors[e]
+                               if table.length <= color then
+                                       for i in [table.length .. color[ do
+                                               table[i] = null
+                                       end
+                               else
+                                       assert table[color] == null else print "in {h}, for {color}: {table[color] or else ""} vs {e}"
+                               end
+                               table[color] = e
+                       end
+               end
+               return table
+       end
+
+       # Colorize core, border and crown in that order
+       private fun compute_colors do
+               colors_cache.clear
+               colorize_core
+               colorize_set(graph.border)
+               colorize_set(graph.crown)
+       end
+
+       # Core elements cannot have the same color than:
+       #  * one of their parents
+       #  * one of their conflicting elements
+       private fun colorize_core do
+               for h in graph.order do
+                       if not graph.core.has(h) then continue
+
+                       var color = inherit_color(h)
+                       var mincolor = color
+                       var bucket = buckets.get_or_null(h)
+                       if bucket == null then continue
+                       var conflicts = graph.conflicts[h]
+                       var parents = poset[h].greaters
+                       for e in bucket do
+                               color = next_free_color(color, parents)
+                               color = next_free_color(color, conflicts)
+                               colors_cache[e] = color
+                               used_colors[h].add color
+                               #print "{h}: color[{color}] <- {e}"
+                               if mincolor == color then mincolor += 1
+                               color += 1
+                       end
+                       min_colors[h] = mincolor
+               end
+       end
+
+       # Other elements inherit color from their direct parents
+       private fun colorize_set(set: Set[H]) do
+               for h in graph.order do
+                       if not set.has(h) then continue
+
+                       var color = inherit_color(h)
+                       var mincolor = color
+                       var bucket = buckets.get_or_null(h)
+                       if bucket == null then continue
+                       var parents = poset[h].greaters
+                       for e in bucket do
+                               color = next_free_color(color, parents)
+                               colors_cache[e] = color
+                               used_colors[h].add color
+                               #print "{h}: color[{color}] <- {e} (set)"
+                               if mincolor == color then mincolor += 1
+                               color += 1
+                       end
+                       min_colors[h] = mincolor
+               end
+       end
+
+       # Get the first available free color.
+       private fun inherit_color(h: H): Int
+       do
+               var res = 0
+               for p in poset[h].direct_greaters do
+                       var m = min_colors[p]
+                       if m > res then res = m
+               end
+               min_colors[h] = res
+               return res
+       end
+
+       # The first available color for each holder.
+       #
+       # Is used by children to start their coloring.
+       #
+       # Is updated at the end of a coloring step.
+       private var min_colors = new HashMap[H, Int]
+
+       private fun next_free_color(color: Int, set: Collection[H]): Int do
+               loop
+                       for h in set do
+                               if used_colors[h].has(color) then
+                                       #print "\tin {h}, {color} is used"
+                                       color += 1
+                                       continue label
+                               end
+                       end
+                       break
+               end label
+               return color
+       end
+
+       # Used for debugging only
+       fun pretty_print do
+               print "colors:"
+               for e, c in colors do print "  {e}: {c}"
+       end
+end
+
 # Colorize a collection of buckets
 # Two elements cannot have the same color if they both appear in the same bucket
 # No coloring order is garantied
index ea60c0a..c013295 100644 (file)
@@ -22,3 +22,4 @@ import compiler_ffi
 import platform::android
 import platform::pnacl
 import platform::emscripten
+import platform::ios
index ecfcc8e..34e7be4 100644 (file)
@@ -59,6 +59,8 @@ redef class ToolContext
        var opt_colo_dead_methods = new OptionBool("Force colorization of dead methods", "--colo-dead-methods")
        # --tables-metrics
        var opt_tables_metrics = new OptionBool("Enable static size measuring of tables used for vft, typing and resolution", "--tables-metrics")
+       # --type-poset
+       var opt_type_poset = new OptionBool("Build a poset of types to create more condensed tables.", "--type-poset")
 
        redef init
        do
@@ -72,6 +74,7 @@ redef class ToolContext
                self.option_context.add_option(self.opt_inline_coloring_numbers, opt_inline_some_methods, opt_direct_call_monomorph, opt_skip_dead_methods, opt_semi_global)
                self.option_context.add_option(self.opt_colo_dead_methods)
                self.option_context.add_option(self.opt_tables_metrics)
+               self.option_context.add_option(self.opt_type_poset)
        end
 
        redef fun process_options(args)
@@ -146,8 +149,6 @@ class SeparateCompiler
        private var type_ids: Map[MType, Int] is noinit
        private var type_colors: Map[MType, Int] is noinit
        private var opentype_colors: Map[MType, Int] is noinit
-       protected var method_colors: Map[PropertyLayoutElement, Int] is noinit
-       protected var attr_colors: Map[MAttribute, Int] is noinit
 
        init do
                var file = new_file("nit.common")
@@ -305,170 +306,147 @@ class SeparateCompiler
 
        private var color_consts_done = new HashSet[Object]
 
+       # The conflict graph of classes used for coloration
+       var class_conflict_graph: POSetConflictGraph[MClass] is noinit
+
        # colorize classe properties
        fun do_property_coloring do
 
                var rta = runtime_type_analysis
 
-               # Layouts
-               var poset = mainmodule.flatten_mclass_hierarchy
-               var mclasses = new HashSet[MClass].from(poset)
-               var colorer = new POSetColorer[MClass]
-               colorer.colorize(poset)
-
-               # The dead methods, still need to provide a dead color symbol
-               var dead_methods = new Array[MMethod]
+               # Class graph
+               var mclasses = mainmodule.flatten_mclass_hierarchy
+               class_conflict_graph = mclasses.to_conflict_graph
 
-               # lookup properties to build layout with
+               # Prepare to collect elements to color and build layout with
                var mmethods = new HashMap[MClass, Set[PropertyLayoutElement]]
                var mattributes = new HashMap[MClass, Set[MAttribute]]
+
+               # The dead methods and super-call, still need to provide a dead color symbol
+               var dead_methods = new Array[PropertyLayoutElement]
+
                for mclass in mclasses do
                        mmethods[mclass] = new HashSet[PropertyLayoutElement]
                        mattributes[mclass] = new HashSet[MAttribute]
-                       for mprop in self.mainmodule.properties(mclass) do
-                               if mprop isa MMethod then
-                                       if not modelbuilder.toolcontext.opt_colo_dead_methods.value and rta != null and not rta.live_methods.has(mprop) then
-                                               dead_methods.add(mprop)
-                                               continue
-                                       end
-                                       mmethods[mclass].add(mprop)
-                               else if mprop isa MAttribute then
-                                       mattributes[mclass].add(mprop)
-                               end
+               end
+
+               # Pre-collect known live things
+               if rta != null then
+                       for m in rta.live_methods do
+                               mmethods[m.intro_mclassdef.mclass].add m
+                       end
+                       for m in rta.live_super_sends do
+                               var mclass = m.mclassdef.mclass
+                               mmethods[mclass].add m
                        end
                end
 
-               # Collect all super calls (dead or not)
-               var all_super_calls = new HashSet[MMethodDef]
-               for mmodule in self.mainmodule.in_importation.greaters do
-                       for mclassdef in mmodule.mclassdefs do
-                               for mpropdef in mclassdef.mpropdefs do
-                                       if not mpropdef isa MMethodDef then continue
-                                       if mpropdef.has_supercall then
-                                               all_super_calls.add(mpropdef)
+               for m in mainmodule.in_importation.greaters do for cd in m.mclassdefs do
+                       var mclass = cd.mclass
+                       # Collect methods ad attributes
+                       for p in cd.intro_mproperties do
+                               if p isa MMethod then
+                                       if rta == null then
+                                               mmethods[mclass].add p
+                                       else if not rta.live_methods.has(p) then
+                                               dead_methods.add p
                                        end
+                               else if p isa MAttribute then
+                                       mattributes[mclass].add p
                                end
                        end
-               end
 
-               # lookup super calls and add it to the list of mmethods to build layout with
-               var super_calls
-               if rta != null then
-                       super_calls = rta.live_super_sends
-               else
-                       super_calls = all_super_calls
-               end
-
-               for mmethoddef in super_calls do
-                       var mclass = mmethoddef.mclassdef.mclass
-                       mmethods[mclass].add(mmethoddef)
-                       for descendant in mclass.in_hierarchy(self.mainmodule).smallers do
-                               mmethods[descendant].add(mmethoddef)
+                       # Collect all super calls (dead or not)
+                       for mpropdef in cd.mpropdefs do
+                               if not mpropdef isa MMethodDef then continue
+                               if mpropdef.has_supercall then
+                                       if rta == null then
+                                               mmethods[mclass].add mpropdef
+                                       else if not rta.live_super_sends.has(mpropdef) then
+                                               dead_methods.add mpropdef
+                                       end
+                               end
                        end
                end
 
                # methods coloration
-               var meth_colorer = new POSetBucketsColorer[MClass, PropertyLayoutElement](poset, colorer.conflicts)
-               method_colors = meth_colorer.colorize(mmethods)
-               method_tables = build_method_tables(mclasses, super_calls)
+               var meth_colorer = new POSetGroupColorer[MClass, PropertyLayoutElement](class_conflict_graph, mmethods)
+               var method_colors = meth_colorer.colors
                compile_color_consts(method_colors)
 
-               # attribute null color to dead methods and supercalls
-               for mproperty in dead_methods do
-                       compile_color_const(new_visitor, mproperty, -1)
-               end
-               for mpropdef in all_super_calls do
-                       if super_calls.has(mpropdef) then continue
-                       compile_color_const(new_visitor, mpropdef, -1)
-               end
+               # give null color to dead methods and supercalls
+               for mproperty in dead_methods do compile_color_const(new_visitor, mproperty, -1)
 
-               # attributes coloration
-               var attr_colorer = new POSetBucketsColorer[MClass, MAttribute](poset, colorer.conflicts)
-               attr_colors = attr_colorer.colorize(mattributes)
-               attr_tables = build_attr_tables(mclasses)
+               # attribute coloration
+               var attr_colorer = new POSetGroupColorer[MClass, MAttribute](class_conflict_graph, mattributes)
+               var attr_colors = attr_colorer.colors#ize(poset, mattributes)
                compile_color_consts(attr_colors)
-       end
 
-       fun build_method_tables(mclasses: Set[MClass], super_calls: Set[MMethodDef]): Map[MClass, Array[nullable MPropDef]] do
-               var tables = new HashMap[MClass, Array[nullable MPropDef]]
+               # Build method and attribute tables
+               method_tables = new HashMap[MClass, Array[nullable MPropDef]]
+               attr_tables = new HashMap[MClass, Array[nullable MProperty]]
                for mclass in mclasses do
-                       var table = new Array[nullable MPropDef]
-                       tables[mclass] = table
+                       if not mclass.has_new_factory and (mclass.kind == abstract_kind or mclass.kind == interface_kind) then continue
+                       if rta != null and not rta.live_classes.has(mclass) then continue
 
-                       var mproperties = self.mainmodule.properties(mclass)
                        var mtype = mclass.intro.bound_mtype
 
-                       for mproperty in mproperties do
-                               if not mproperty isa MMethod then continue
-                               if not method_colors.has_key(mproperty) then continue
-                               var color = method_colors[mproperty]
-                               if table.length <= color then
-                                       for i in [table.length .. color[ do
-                                               table[i] = null
-                                       end
-                               end
-                               table[color] = mproperty.lookup_first_definition(mainmodule, mtype)
-                       end
-
-                       for supercall in super_calls do
-                               if not mtype.collect_mclassdefs(mainmodule).has(supercall.mclassdef) then continue
-
-                               var color = method_colors[supercall]
-                               if table.length <= color then
-                                       for i in [table.length .. color[ do
-                                               table[i] = null
-                                       end
+                       # Resolve elements in the layout to get the final table
+                       var meth_layout = meth_colorer.build_layout(mclass)
+                       var meth_table = new Array[nullable MPropDef].with_capacity(meth_layout.length)
+                       method_tables[mclass] = meth_table
+                       for e in meth_layout do
+                               if e == null then
+                                       meth_table.add null
+                               else if e isa MMethod then
+                                       # Standard method call of `e`
+                                       meth_table.add e.lookup_first_definition(mainmodule, mtype)
+                               else if e isa MMethodDef then
+                                       # Super-call in the methoddef `e`
+                                       meth_table.add e.lookup_next_definition(mainmodule, mtype)
+                               else
+                                       abort
                                end
-                               var mmethoddef = supercall.lookup_next_definition(mainmodule, mtype)
-                               table[color] = mmethoddef
                        end
 
+                       # Do not need to resolve attributes as only the position is used
+                       attr_tables[mclass] = attr_colorer.build_layout(mclass)
                end
-               return tables
-       end
 
-       fun build_attr_tables(mclasses: Set[MClass]): Map[MClass, Array[nullable MPropDef]] do
-               var tables = new HashMap[MClass, Array[nullable MPropDef]]
-               for mclass in mclasses do
-                       var table = new Array[nullable MPropDef]
-                       tables[mclass] = table
 
-                       var mproperties = self.mainmodule.properties(mclass)
-                       var mtype = mclass.intro.bound_mtype
-
-                       for mproperty in mproperties do
-                               if not mproperty isa MAttribute then continue
-                               if not attr_colors.has_key(mproperty) then continue
-                               var color = attr_colors[mproperty]
-                               if table.length <= color then
-                                       for i in [table.length .. color[ do
-                                               table[i] = null
-                                       end
-                               end
-                               table[color] = mproperty.lookup_first_definition(mainmodule, mtype)
-                       end
-               end
-               return tables
        end
 
        # colorize live types of the program
-       private fun do_type_coloring: POSet[MType] do
+       private fun do_type_coloring: Collection[MType] do
                # Collect types to colorize
                var live_types = runtime_type_analysis.live_types
                var live_cast_types = runtime_type_analysis.live_cast_types
 
-               # Compute colors
-               var poset = poset_from_mtypes(live_types, live_cast_types)
-               var colorer = new POSetColorer[MType]
-               colorer.colorize(poset)
-               type_ids = colorer.ids
-               type_colors = colorer.colors
-               type_tables = build_type_tables(poset)
+               var res = new HashSet[MType]
+               res.add_all live_types
+               res.add_all live_cast_types
+
+               if modelbuilder.toolcontext.opt_type_poset.value then
+                       # Compute colors with a type poset
+                       var poset = poset_from_mtypes(live_types, live_cast_types)
+                       var colorer = new POSetColorer[MType]
+                       colorer.colorize(poset)
+                       type_ids = colorer.ids
+                       type_colors = colorer.colors
+                       type_tables = build_type_tables(poset)
+               else
+                       # Compute colors using the class poset
+                       # Faster to compute but the number of holes can degenerate
+                       compute_type_test_layouts(live_types, live_cast_types)
+
+                       type_ids = new HashMap[MType, Int]
+                       for x in res do type_ids[x] = type_ids.length + 1
+               end
 
                # VT and FT are stored with other unresolved types in the big resolution_tables
                self.compute_resolution_tables(live_types)
 
-               return poset
+               return res
        end
 
        private fun poset_from_mtypes(mtypes, cast_types: Set[MType]): POSet[MType] do
@@ -480,14 +458,14 @@ class SeparateCompiler
 
                var mtypes_by_class = new MultiHashMap[MClass, MType]
                for e in mtypes do
-                       var c = e.as_notnullable.as(MClassType).mclass
+                       var c = e.undecorate.as(MClassType).mclass
                        mtypes_by_class[c].add(e)
                        poset.add_node(e)
                end
 
                var casttypes_by_class = new MultiHashMap[MClass, MType]
                for e in cast_types do
-                       var c = e.as_notnullable.as(MClassType).mclass
+                       var c = e.undecorate.as(MClassType).mclass
                        casttypes_by_class[c].add(e)
                        poset.add_node(e)
                end
@@ -527,6 +505,48 @@ class SeparateCompiler
                return tables
        end
 
+
+       private fun compute_type_test_layouts(mtypes: Set[MClassType], cast_types: Set[MType]) do
+               # Group cast_type by their classes
+               var bucklets = new HashMap[MClass, Set[MType]]
+               for e in cast_types do
+                       var c = e.undecorate.as(MClassType).mclass
+                       if not bucklets.has_key(c) then
+                               bucklets[c] = new HashSet[MType]
+                       end
+                       bucklets[c].add(e)
+               end
+
+               # Colorize cast_types from the class hierarchy
+               var colorer = new POSetGroupColorer[MClass, MType](class_conflict_graph, bucklets)
+               type_colors = colorer.colors
+
+               var layouts = new HashMap[MClass, Array[nullable MType]]
+               for c in runtime_type_analysis.live_classes do
+                       layouts[c] = colorer.build_layout(c)
+               end
+
+               # Build the table for each live type
+               for t in mtypes do
+                       # A live type use the layout of its class
+                       var c = t.mclass
+                       var layout = layouts[c]
+                       var table = new Array[nullable MType].with_capacity(layout.length)
+                       type_tables[t] = table
+
+                       # For each potential super-type in the layout
+                       for sup in layout do
+                               if sup == null then
+                                       table.add null
+                               else if t.is_subtype(mainmodule, null, sup) then
+                                       table.add sup
+                               else
+                                       table.add null
+                               end
+                       end
+               end
+       end
+
        # resolution_tables is used to perform a type resolution at runtime in O(1)
        private fun compute_resolution_tables(mtypes: Set[MType]) do
                # During the visit of the body of classes, live_unresolved_types are collected
@@ -534,21 +554,26 @@ class SeparateCompiler
                # Collect all live_unresolved_types (visited in the body of classes)
 
                # Determinate fo each livetype what are its possible requested anchored types
-               var mtype2unresolved = new HashMap[MClassType, Set[MType]]
+               var mtype2unresolved = new HashMap[MClass, Set[MType]]
                for mtype in self.runtime_type_analysis.live_types do
-                       var set = new HashSet[MType]
+                       var mclass = mtype.mclass
+                       var set = mtype2unresolved.get_or_null(mclass)
+                       if set == null then
+                               set = new HashSet[MType]
+                               mtype2unresolved[mclass] = set
+                       end
                        for cd in mtype.collect_mclassdefs(self.mainmodule) do
                                if self.live_unresolved_types.has_key(cd) then
                                        set.add_all(self.live_unresolved_types[cd])
                                end
                        end
-                       mtype2unresolved[mtype] = set
                end
 
                # Compute the table layout with the prefered method
-               var colorer = new BucketsColorer[MType, MType]
+               var colorer = new BucketsColorer[MClass, MType]
+
                opentype_colors = colorer.colorize(mtype2unresolved)
-               resolution_tables = self.build_resolution_tables(mtype2unresolved)
+               resolution_tables = self.build_resolution_tables(self.runtime_type_analysis.live_types, mtype2unresolved)
 
                # Compile a C constant for each collected unresolved type.
                # Either to a color, or to -1 if the unresolved type is dead (no live receiver can require it)
@@ -573,9 +598,10 @@ class SeparateCompiler
                #print ""
        end
 
-       fun build_resolution_tables(elements: Map[MClassType, Set[MType]]): Map[MClassType, Array[nullable MType]] do
+       fun build_resolution_tables(elements: Set[MClassType], map: Map[MClass, Set[MType]]): Map[MClassType, Array[nullable MType]] do
                var tables = new HashMap[MClassType, Array[nullable MType]]
-               for mclasstype, mtypes in elements do
+               for mclasstype in elements do
+                       var mtypes = map[mclasstype.mclass]
                        var table = new Array[nullable MType]
                        for mtype in mtypes do
                                var color = opentype_colors[mtype]
@@ -716,7 +742,7 @@ class SeparateCompiler
 
                # resolution table (for receiver)
                if is_live then
-                       var mclass_type = mtype.as_notnullable
+                       var mclass_type = mtype.undecorate
                        assert mclass_type isa MClassType
                        if resolution_tables[mclass_type].is_empty then
                                v.add_decl("NULL, /*NO RESOLUTIONS*/")
@@ -749,7 +775,7 @@ class SeparateCompiler
 
        fun compile_type_resolution_table(mtype: MType) do
 
-               var mclass_type = mtype.as_notnullable.as(MClassType)
+               var mclass_type = mtype.undecorate.as(MClassType)
 
                # extern const struct resolution_table_X resolution_table_X
                self.provide_declaration("resolution_table_{mtype.c_name}", "extern const struct types resolution_table_{mtype.c_name};")
@@ -788,8 +814,6 @@ class SeparateCompiler
                var mtype = mclass.intro.bound_mtype
                var c_name = mclass.c_name
 
-               var vft = self.method_tables[mclass]
-               var attrs = self.attr_tables[mclass]
                var v = new_visitor
 
                var rta = runtime_type_analysis
@@ -803,7 +827,8 @@ class SeparateCompiler
                        v.add_decl("const struct class class_{c_name} = \{")
                        v.add_decl("{self.box_kind_of(mclass)}, /* box_kind */")
                        v.add_decl("\{")
-                       for i in [0 .. vft.length[ do
+                       var vft = self.method_tables.get_or_null(mclass)
+                       if vft != null then for i in [0 .. vft.length[ do
                                var mpropdef = vft[i]
                                if mpropdef == null then
                                        v.add_decl("NULL, /* empty */")
@@ -932,13 +957,20 @@ class SeparateCompiler
                else
                        var res = v.new_named_var(mtype, "self")
                        res.is_exact = true
-                       v.add("{res} = nit_alloc(sizeof(struct instance) + {attrs.length}*sizeof(nitattribute_t));")
+                       var attrs = self.attr_tables.get_or_null(mclass)
+                       if attrs == null then
+                               v.add("{res} = nit_alloc(sizeof(struct instance));")
+                       else
+                               v.add("{res} = nit_alloc(sizeof(struct instance) + {attrs.length}*sizeof(nitattribute_t));")
+                       end
                        v.add("{res}->type = type;")
                        hardening_live_type(v, "type")
                        v.require_declaration("class_{c_name}")
                        v.add("{res}->class = &class_{c_name};")
-                       self.generate_init_attr(v, res, mtype)
-                       v.set_finalizer res
+                       if attrs != null then
+                               self.generate_init_attr(v, res, mtype)
+                               v.set_finalizer res
+                       end
                        v.add("return {res};")
                end
                v.add("\}")
@@ -1017,7 +1049,7 @@ class SeparateCompiler
        private var type_tables: Map[MType, Array[nullable MType]] = new HashMap[MType, Array[nullable MType]]
        private var resolution_tables: Map[MClassType, Array[nullable MType]] = new HashMap[MClassType, Array[nullable MType]]
        protected var method_tables: Map[MClass, Array[nullable MPropDef]] = new HashMap[MClass, Array[nullable MPropDef]]
-       protected var attr_tables: Map[MClass, Array[nullable MPropDef]] = new HashMap[MClass, Array[nullable MPropDef]]
+       protected var attr_tables: Map[MClass, Array[nullable MProperty]] = new HashMap[MClass, Array[nullable MProperty]]
 
        redef fun display_stats
        do
@@ -1974,7 +2006,7 @@ class SeparateCompilerVisitor
 
        fun can_be_primitive(value: RuntimeVariable): Bool
        do
-               var t = value.mcasttype.as_notnullable
+               var t = value.mcasttype.undecorate
                if not t isa MClassType then return false
                var k = t.mclass.kind
                return k == interface_kind or t.is_c_primitive
@@ -2266,7 +2298,7 @@ class SeparateRuntimeFunction
                        var v2 = compiler.new_visitor
                        v2.add "{c_ret} {n2}{c_sig} \{"
                        v2.require_declaration(m.const_color)
-                       var call = "(({c_funptrtype})({selfvar}->class->vft[{m.const_color}]))({arguments.join(", ")});"
+                       var call = "(({c_funptrtype})({v2.class_info(selfvar)}->vft[{m.const_color}]))({arguments.join(", ")});"
                        if ret != null then
                                v2.add "return {call}"
                        else
@@ -2283,7 +2315,7 @@ class SeparateRuntimeFunction
                        var v2 = compiler.new_visitor
                        v2.add "{c_ret} {n2}{c_sig} \{"
                        v2.require_declaration(m.const_color)
-                       var call = "(({c_funptrtype})({selfvar}->class->vft[{m.const_color}]))({arguments.join(", ")});"
+                       var call = "(({c_funptrtype})({v2.class_info(selfvar)}->vft[{m.const_color}]))({arguments.join(", ")});"
                        if ret != null then
                                v2.add "return {call}"
                        else
index 2a7f0fa..b8b2c0a 100644 (file)
@@ -199,8 +199,6 @@ class SeparateErasureCompiler
                var mtype = mclass.intro.bound_mtype
                var c_name = mclass.c_name
 
-               var vft = self.method_tables[mclass]
-               var attrs = self.attr_tables[mclass]
                var class_table = self.class_tables[mclass]
                var v = self.new_visitor
 
@@ -230,7 +228,8 @@ class SeparateErasureCompiler
                        end
                        v.add_decl("&type_table_{c_name},")
                        v.add_decl("\{")
-                       for i in [0 .. vft.length[ do
+                       var vft = self.method_tables.get_or_null(mclass)
+                       if vft != null then for i in [0 .. vft.length[ do
                                var mpropdef = vft[i]
                                if mpropdef == null then
                                        v.add_decl("NULL, /* empty */")
@@ -355,11 +354,18 @@ class SeparateErasureCompiler
 
                        var res = v.new_named_var(mtype, "self")
                        res.is_exact = true
-                       v.add("{res} = nit_alloc(sizeof(struct instance) + {attrs.length}*sizeof(nitattribute_t));")
+                       var attrs = self.attr_tables.get_or_null(mclass)
+                       if attrs == null then
+                               v.add("{res} = nit_alloc(sizeof(struct instance));")
+                       else
+                               v.add("{res} = nit_alloc(sizeof(struct instance) + {attrs.length}*sizeof(nitattribute_t));")
+                       end
                        v.require_declaration("class_{c_name}")
                        v.add("{res}->class = &class_{c_name};")
-                       self.generate_init_attr(v, res, mtype)
-                       v.set_finalizer res
+                       if attrs != null then
+                               self.generate_init_attr(v, res, mtype)
+                               v.set_finalizer res
+                       end
                        v.add("return {res};")
                end
                v.add("\}")
index e947ee2..64b2022 100644 (file)
@@ -68,7 +68,7 @@ end
 abstract class DocComposite
 
        # Parent element.
-       var parent: nullable DocComposite = null
+       var parent: nullable DocComposite = null is writable
 
        # Does `self` have a `parent`?
        fun is_root: Bool do return parent == null
@@ -85,6 +85,7 @@ abstract class DocComposite
        #
        # Shortcut for `children.add`.
        fun add_child(child: DocComposite) do
+               child.parent = self
                children.add child
        end
 end
index aff25d4..66ef564 100644 (file)
@@ -41,7 +41,8 @@ class GraphPhase
                        if article == null then continue
                        # FIXME avoid diff
                        # page.root.add article
-                       page.root.children[1].children.insert(article, 0)
+                       article.parent = page.root.children.first.children[1]
+                       page.root.children.first.children[1].children.insert(article, 0)
                end
        end
 end
index 39ad273..23da906 100644 (file)
@@ -47,7 +47,8 @@ redef class MModulePage
                var clients = self.clients.to_a
                v.name_sorter.sort(clients)
                section.add_child new HierarchyListArticle(mentity, "Clients", clients)
-               root.children.insert(section, 1)
+               section.parent = root.children.first
+               root.children.first.children.insert(section, 1)
        end
 end
 
@@ -66,7 +67,8 @@ redef class MClassPage
                var descendants = self.descendants.to_a
                v.name_sorter.sort(descendants)
                section.add_child new HierarchyListArticle(mentity, "Descendants", descendants)
-               root.children.insert(section, 1)
+               section.parent = root.children.first
+               root.children.first.children.insert(section, 1)
        end
 end
 
index a11e187..7d38bc0 100644 (file)
@@ -191,7 +191,7 @@ redef class DocPage
 
        # Build top menu template if any.
        fun init_topmenu(v: RenderHTMLPhase, doc: DocModel) do
-               topmenu = new TplTopMenu(html_url)
+               topmenu = new DocTopMenu
                var brand = v.ctx.opt_custom_brand.value
                if brand != null then
                        var tpl = new Template
@@ -200,8 +200,13 @@ redef class DocPage
                        tpl.add "</span>"
                        topmenu.brand = tpl
                end
-               topmenu.add_link new TplLink("index.html", "Overview")
-               topmenu.add_link new TplLink("search.html", "Index")
+               var title = "Overview"
+               if v.ctx.opt_custom_title.value != null then
+                       title = v.ctx.opt_custom_title.value.to_s
+               end
+               topmenu.add_li new ListItem(new Link("index.html", title))
+               topmenu.add_li new ListItem(new Link("search.html", "Index"))
+               topmenu.active_item = topmenu.items.first
        end
 
        # Build page sidebar if any.
@@ -257,6 +262,12 @@ end
 redef class SearchPage
        redef var html_url = "search.html"
        redef fun init_title(v, doc) do title = "Index"
+
+       redef fun init_topmenu(v, doc) do
+               super
+               topmenu.active_item = topmenu.items.last
+       end
+
        redef fun init_sidebar(v, doc) do end
 
        # TODO this should be done in StructurePhase.
@@ -314,7 +325,7 @@ end
 
 redef class MEntityPage
        redef var html_url is lazy do return mentity.nitdoc_url
-       redef fun init_title(v, doc) do title = mentity.nitdoc_name
+       redef fun init_title(v, doc) do title = mentity.html_name
        redef fun init_content(v, doc) do add_section root.start_rendering(v, doc, self)
 end
 
@@ -327,9 +338,10 @@ redef class MGroupPage
                super
                var mproject = mentity.mproject
                if not mentity.is_root then
-                       topmenu.add_link new TplLink(mproject.nitdoc_url, mproject.nitdoc_name)
+                       topmenu.add_li new ListItem(new Link(mproject.nitdoc_url, mproject.html_name))
                end
-               topmenu.add_link new TplLink(html_url, mproject.nitdoc_name)
+               topmenu.add_li new ListItem(new Link(html_url, mproject.html_name))
+               topmenu.active_item = topmenu.items.last
        end
 
        redef fun init_sidebar(v, doc) do
@@ -366,8 +378,9 @@ redef class MModulePage
        redef fun init_topmenu(v, doc) do
                super
                var mproject = mentity.mproject
-               topmenu.add_link new TplLink(mproject.nitdoc_url, mproject.nitdoc_name)
-               topmenu.add_link new TplLink(mentity.nitdoc_url, mentity.nitdoc_name)
+               topmenu.add_li new ListItem(new Link(mproject.nitdoc_url, mproject.html_name))
+               topmenu.add_li new ListItem(new Link(mentity.nitdoc_url, mentity.html_name))
+               topmenu.active_item = topmenu.items.last
        end
 
        # Class list to display in sidebar
@@ -404,15 +417,12 @@ end
 
 redef class MClassPage
 
-       redef fun init_title(v, doc) do
-               title = "{mentity.nitdoc_name}{mentity.tpl_signature.write_to_string}"
-       end
-
        redef fun init_topmenu(v, doc) do
                super
                var mproject = mentity.intro_mmodule.mgroup.mproject
-               topmenu.add_link new TplLink("{mproject.nitdoc_url}", "{mproject.nitdoc_name}")
-               topmenu.add_link new TplLink(html_url, mentity.nitdoc_name)
+               topmenu.add_li new ListItem(new Link(mproject.nitdoc_url, mproject.html_name))
+               topmenu.add_li new ListItem(new Link(html_url, mentity.html_name))
+               topmenu.active_item = topmenu.items.last
        end
 
        redef fun init_sidebar(v, doc) do
@@ -442,7 +452,7 @@ redef class MClassPage
                        classes.add "inherit"
                        var cls_url = mprop.intro.mclassdef.mclass.nitdoc_url
                        var def_url = "{cls_url}#{mprop.nitdoc_id}"
-                       var lnk = new TplLink(def_url, mprop.nitdoc_name)
+                       var lnk = new TplLink(def_url, mprop.html_name)
                        var mdoc = mprop.intro.mdoc_or_fallback
                        if mdoc != null then lnk.title = mdoc.short_comment
                        var item = new Template
@@ -486,7 +496,7 @@ end
 
 redef class MPropertyPage
        redef fun init_title(v, doc) do
-               title = "{mentity.nitdoc_name}{mentity.tpl_signature.write_to_string}"
+               title = "{mentity.html_name}{mentity.tpl_signature.write_to_string}"
        end
 
        redef fun init_topmenu(v, doc) do
@@ -494,9 +504,10 @@ redef class MPropertyPage
                var mmodule = mentity.intro_mclassdef.mmodule
                var mproject = mmodule.mgroup.mproject
                var mclass = mentity.intro_mclassdef.mclass
-               topmenu.add_link new TplLink("{mproject.nitdoc_url}", "{mproject.nitdoc_name}")
-               topmenu.add_link new TplLink("{mclass.nitdoc_url}", "{mclass.nitdoc_name}")
-               topmenu.add_link new TplLink(html_url, mentity.nitdoc_name)
+               topmenu.add_li new ListItem(new Link(mproject.nitdoc_url, mproject.html_name))
+               topmenu.add_li new ListItem(new Link(mclass.nitdoc_url, mclass.html_name))
+               topmenu.add_li new ListItem(new Link(html_url, mentity.html_name))
+               topmenu.active_item = topmenu.items.last
        end
 end
 
@@ -515,18 +526,16 @@ redef class DocRoot
        fun start_rendering(v: RenderHTMLPhase, doc: DocModel, page: MEntityPage): TplSection do
                var section = new TplSection("top")
                var mentity = page.mentity
-               section.title = mentity.nitdoc_name
+               section.title = mentity.html_name
                section.subtitle = mentity.tpl_declaration
                # FIXME ugly hack to avoid diff
                if mentity isa MGroup and mentity.is_root then
-                       section.title = mentity.mproject.nitdoc_name
+                       section.title = mentity.mproject.html_name
                        section.subtitle = mentity.mproject.tpl_declaration
-               else if mentity isa MClass then
-                       section.title = "{mentity.nitdoc_name}{mentity.tpl_signature.write_to_string}"
                else if mentity isa MProperty then
-                       section.title = "{mentity.nitdoc_name}{mentity.intro.tpl_signature.write_to_string}"
+                       section.title = "{mentity.html_name}{mentity.intro.tpl_signature.write_to_string}"
                        section.subtitle = mentity.tpl_namespace
-                       section.summary_title = mentity.nitdoc_name
+                       section.summary_title = mentity.html_name
                end
                render(v, doc, page, section)
                return section
@@ -561,10 +570,10 @@ redef class ConcernSection
                var title = new Template
                if mmodule == page.mentity then
                        title.add "in "
-                       section.summary_title = "in {mmodule.nitdoc_name}"
+                       section.summary_title = "in {mmodule.html_name}"
                else
                        title.add "from "
-                       section.summary_title = "from {mmodule.nitdoc_name}"
+                       section.summary_title = "from {mmodule.html_name}"
                end
                title.add mmodule.tpl_namespace
                section.title = title
@@ -575,7 +584,13 @@ redef class ConcernSection
                title.add "in "
                title.add mmodule.tpl_namespace
                section.title = title
-               section.summary_title = "in {mmodule.nitdoc_name}"
+               section.summary_title = "in {mmodule.html_name}"
+       end
+end
+
+redef class MEntitySection
+       redef fun render(v, doc, page, parent) do
+               for child in children do child.render(v, doc, page, parent)
        end
 end
 
@@ -690,14 +705,14 @@ redef class DefinitionArticle
                else
                        var cls_url = mprop.intro.mclassdef.mclass.nitdoc_url
                        var def_url = "{cls_url}#{mprop.nitdoc_id}"
-                       var lnk = new TplLink.with_title(def_url, mprop.nitdoc_name,
+                       var lnk = new TplLink.with_title(def_url, mprop.html_name,
                                        "Go to introduction")
                        title.add "redef "
                        title.add lnk
                end
                article.title = title
                article.title_classes.add "signature"
-               article.summary_title = "{mprop.nitdoc_name}"
+               article.summary_title = "{mprop.html_name}"
                article.subtitle = mpropdef.tpl_namespace
                if mpropdef.mdoc_or_fallback != null then
                        article.content = mpropdef.mdoc_or_fallback.tpl_comment
index 1e0d773..9c32c8c 100644 (file)
@@ -50,10 +50,12 @@ end
 
 redef class MGroupPage
        redef fun apply_structure(v, doc) do
+               var section = new MEntitySection(mentity)
+               root.add_child section
                if mentity.is_root then
-                       root.add_child new IntroArticle(mentity.mproject)
+                       section.add_child new IntroArticle(mentity.mproject)
                else
-                       root.add_child new IntroArticle(mentity)
+                       section.add_child new IntroArticle(mentity)
                end
                var concerns = self.concerns
                if concerns == null or concerns.is_empty then return
@@ -63,12 +65,12 @@ redef class MGroupPage
                concerns.sort_with(v.concerns_sorter)
                mentity.mproject.booster_rank = 0
                mentity.booster_rank = 0
-               root.add_child new ConcernsArticle(mentity, concerns)
+               section.add_child new ConcernsArticle(mentity, concerns)
                for mentity in concerns do
                        if mentity isa MModule then
-                               root.add_child new DefinitionArticle(mentity)
+                               section.add_child new DefinitionArticle(mentity)
                        else
-                               root.add_child new ConcernSection(mentity)
+                               section.add_child new ConcernSection(mentity)
                        end
                end
        end
@@ -76,7 +78,9 @@ end
 
 redef class MModulePage
        redef fun apply_structure(v, doc) do
-               root.add_child new IntroArticle(mentity)
+               var section = new MEntitySection(mentity)
+               root.add_child section
+               section.add_child new IntroArticle(mentity)
                var concerns = self.concerns
                if concerns == null or concerns.is_empty then return
                # FIXME avoid diff
@@ -87,10 +91,10 @@ redef class MModulePage
                mentity.mgroup.mproject.booster_rank = 0
                mentity.mgroup.booster_rank = 0
                mentity.booster_rank = 0
-               root.add_child new ConcernsArticle(mentity, concerns)
+               section.add_child new ConcernsArticle(mentity, concerns)
                # reference list
                for mentity in concerns do
-                       var section = new ConcernSection(mentity)
+                       var ssection = new ConcernSection(mentity)
                        if mentity isa MModule then
                                var mclasses = mclasses_for_mmodule(mentity).to_a
                                v.name_sorter.sort(mclasses)
@@ -104,10 +108,10 @@ redef class MModulePage
                                        for mclassdef in mclassdefs do
                                                article.add_child(new DefinitionArticle(mclassdef))
                                        end
-                                       section.add_child article
+                                       ssection.add_child article
                                end
                        end
-                       root.add_child section
+                       section.add_child ssection
                end
        end
 
@@ -136,7 +140,9 @@ end
 
 redef class MClassPage
        redef fun apply_structure(v, doc) do
-               root.add_child new IntroArticle(mentity)
+               var section = new MEntitySection(mentity)
+               root.add_child section
+               section.add_child new IntroArticle(mentity)
                var concerns = self.concerns
                if concerns == null or concerns.is_empty then return
                # FIXME diff hack
@@ -147,9 +153,9 @@ redef class MClassPage
                mentity.intro_mmodule.mgroup.mproject.booster_rank = 0
                mentity.intro_mmodule.mgroup.booster_rank = 0
                mentity.intro_mmodule.booster_rank = 0
-               root.add_child new ConcernsArticle(mentity, concerns)
+               section.add_child new ConcernsArticle(mentity, concerns)
                for mentity in concerns do
-                       var section = new ConcernSection(mentity)
+                       var ssection = new ConcernSection(mentity)
                        if mentity isa MModule then
                                var mprops = mproperties_for(mentity)
                                var by_kind = new PropertiesByKind.with_elements(mprops)
@@ -157,12 +163,12 @@ redef class MClassPage
                                        v.name_sorter.sort(group)
                                        for mprop in group do
                                                for mpropdef in mpropdefs_for(mprop, mentity) do
-                                                       section.add_child new DefinitionArticle(mpropdef)
+                                                       ssection.add_child new DefinitionArticle(mpropdef)
                                                end
                                        end
                                end
                        end
-                       root.add_child section
+                       section.add_child ssection
                end
        end
 
@@ -196,7 +202,9 @@ end
 
 redef class MPropertyPage
        redef fun apply_structure(v, doc) do
-               root.add_child new IntroArticle(mentity)
+               var section = new MEntitySection(mentity)
+               root.add_child section
+               section.add_child new IntroArticle(mentity)
                var concerns = self.concerns
                if concerns == null or concerns.is_empty then return
                # FIXME diff hack
@@ -207,18 +215,18 @@ redef class MPropertyPage
                mentity.intro.mclassdef.mmodule.mgroup.mproject.booster_rank = 0
                mentity.intro.mclassdef.mmodule.mgroup.booster_rank = 0
                mentity.intro.mclassdef.mmodule.booster_rank = 0
-               root.add_child new ConcernsArticle(mentity, concerns)
+               section.add_child new ConcernsArticle(mentity, concerns)
                for mentity in concerns do
-                       var section = new ConcernSection(mentity)
+                       var ssection = new ConcernSection(mentity)
                        if mentity isa MModule then
                                # Add mproperties
                                var mpropdefs = mpropdefs_for(mentity).to_a
                                v.name_sorter.sort(mpropdefs)
                                for mpropdef in mpropdefs do
-                                       section.add_child new DefinitionArticle(mpropdef)
+                                       ssection.add_child new DefinitionArticle(mpropdef)
                                end
                        end
-                       root.add_child section
+                       section.add_child ssection
                end
        end
 
@@ -258,6 +266,14 @@ abstract class MEntityArticle
        super DocArticle
 end
 
+# A section about a Mentity.
+#
+# Used to regroup content about a MEntity.
+class MEntitySection
+       super MEntityComposite
+       super DocSection
+end
+
 # An introduction article about a MEntity.
 #
 # Used at the top of a documentation page to introduce the documented MEntity.
index c3126f7..e65059b 100644 (file)
@@ -24,70 +24,6 @@ import json::static
 # general layout elements
 #########################
 
-# Top menu bar template
-class TplTopMenu
-       super Template
-
-       # Brand link to display in first position of the top menu
-       private var brand: nullable Writable = null is writable
-       # Elements of the topmenu
-       private var elts = new Array[Writable]
-
-       # The page url where the top menu is displayed.
-       #
-       # Used to select the active link.
-       private var current_url: String
-
-       # Add a new link to the menu.
-       fun add_link(content: TplLink) do
-               var is_active = content.href == current_url
-               add_item(content, is_active)
-       end
-
-       # Add a content between `<li>` tags
-       fun add_item(content: Writable, is_active: Bool) do
-               var tpl = new Template
-               tpl.add "<li"
-               if is_active then
-                       tpl.add " class=\"active\""
-               end
-               tpl.add ">"
-               tpl.add content
-               tpl.addn "</li>"
-               add_raw(tpl)
-       end
-
-       # Add a raw content to the menu
-       fun add_raw(content: Writable) do
-               elts.add content
-       end
-
-       redef fun rendering do
-               if brand == null and elts.is_empty then return
-               addn "<nav id='topmenu' class='navbar navbar-default navbar-fixed-top' role='navigation'>"
-               addn " <div class='container-fluid'>"
-               addn "  <div class='navbar-header'>"
-               add "   <button type='button' class='navbar-toggle' "
-               addn "       data-toggle='collapse' data-target='#topmenu-collapse'>"
-               addn "    <span class='sr-only'>Toggle menu</span>"
-               addn "    <span class='icon-bar'></span>"
-               addn "    <span class='icon-bar'></span>"
-               addn "    <span class='icon-bar'></span>"
-               addn "   </button>"
-               if brand != null then add brand.as(not null)
-               addn "  </div>"
-               addn "  <div class='collapse navbar-collapse' id='topmenu-collapse'>"
-               if not elts.is_empty then
-                       addn "<ul class='nav navbar-nav'>"
-                       for elt in elts do add elt
-                       addn "</ul>"
-               end
-               addn "  </div>"
-               addn " </div>"
-               addn "</nav>"
-       end
-end
-
 # A sidebar template
 class TplSidebar
        super Template
index 15b2963..2908fad 100644 (file)
@@ -45,9 +45,20 @@ redef class MEntity
        # URL of this entity’s Nitdoc page.
        fun nitdoc_url: String is abstract
 
+       # Returns the mentity name without short signature.
+       #
+       # * MProject: `foo`
+       # * MGroup: `foo`
+       # * MModule: `foo`
+       # * MClass: `Foo[E]`
+       # * MClassDef: `Foo[E]`
+       # * MProperty: `foo(e)`
+       # * MPropdef: `foo(e)`
+       var html_name: String is lazy do return name.html_escape
+
        # A template link to the mentity `nitdoc_id`
        fun tpl_anchor: TplLink do
-               var tpl = new TplLink("#{nitdoc_id}", nitdoc_name)
+               var tpl = new TplLink("#{nitdoc_id}", html_name)
                var mdoc = mdoc_or_fallback
                if mdoc != null then
                        tpl.title = mdoc.short_comment
@@ -57,7 +68,7 @@ redef class MEntity
 
        # A template link to the mentity `nitdoc_url`
        fun tpl_link: TplLink do
-               var tpl = new TplLink(nitdoc_url, nitdoc_name)
+               var tpl = new TplLink(nitdoc_url, html_name)
                var mdoc = mdoc_or_fallback
                if mdoc != null then
                        tpl.title = mdoc.short_comment
@@ -80,7 +91,7 @@ redef class MEntity
                var tpl = new TplArticle.with_title(nitdoc_id, tpl_title)
                tpl.title_classes.add "signature"
                tpl.subtitle = tpl_namespace
-               tpl.summary_title = nitdoc_name
+               tpl.summary_title = html_name
                return tpl
        end
 
@@ -252,6 +263,22 @@ redef class MClass
        redef fun nitdoc_url do return "class_{nitdoc_id}.html"
        redef fun mdoc_or_fallback do return intro.mdoc
 
+       # Format: `Foo[E]`
+       redef var html_name is lazy do
+               var tpl = new Template
+               tpl.add name.html_escape
+               if arity > 0 then
+                       tpl.add "["
+                       var parameter_names = new Array[String]
+                       for p in mparameters do
+                               parameter_names.add(p.html_name)
+                       end
+                       tpl.add parameter_names.join(", ")
+                       tpl.add "]"
+               end
+               return tpl.write_to_string
+       end
+
        redef fun tpl_declaration do return intro.tpl_declaration
        redef fun tpl_definition do return intro.tpl_definition
 
@@ -268,7 +295,6 @@ redef class MClass
                var title = new Template
                title.add tpl_icon
                title.add tpl_link
-               title.add tpl_signature
                return title
        end
 
@@ -280,7 +306,7 @@ redef class MClass
                        tpl.add "["
                        var parameter_names = new Array[String]
                        for p in mparameters do
-                               parameter_names.add(p.nitdoc_name)
+                               parameter_names.add(p.html_name)
                        end
                        tpl.add parameter_names.join(", ")
                        tpl.add "]"
@@ -288,12 +314,6 @@ redef class MClass
                return tpl
        end
 
-       redef fun tpl_article do
-               var tpl = super
-               tpl.summary_title = "{nitdoc_name}{tpl_signature.write_to_string}"
-               return tpl
-       end
-
        redef fun tpl_css_classes do return intro.tpl_css_classes
 end
 
@@ -314,7 +334,7 @@ redef class MClassDef
 
        redef fun tpl_article do
                var tpl = new TplArticle(nitdoc_id)
-               tpl.summary_title = "in {mmodule.nitdoc_name}"
+               tpl.summary_title = "in {mmodule.html_name}"
                tpl.title = tpl_declaration
                tpl.title_classes.add "signature"
                var title = new Template
@@ -332,7 +352,6 @@ redef class MClassDef
                var title = new Template
                title.add tpl_icon
                title.add tpl_link
-               title.add tpl_signature
                return title
        end
 
@@ -350,7 +369,7 @@ redef class MClassDef
                if not mparameters.is_empty then
                        tpl.add "["
                        for i in [0..mparameters.length[ do
-                               tpl.add "{mparameters[i].nitdoc_name}: "
+                               tpl.add "{mparameters[i].html_name}: "
                                tpl.add bound_mtype.arguments[i].tpl_signature
                                if i < mparameters.length - 1 then tpl.add ", "
                        end
@@ -428,7 +447,7 @@ redef class MPropDef
 
        redef fun tpl_article do
                var tpl = new TplArticle(nitdoc_id)
-               tpl.summary_title = "in {mclassdef.nitdoc_name}"
+               tpl.summary_title = "in {mclassdef.html_name}"
                var title = new Template
                title.add "in "
                title.add mclassdef.tpl_link
@@ -577,7 +596,9 @@ end
 redef class MGenericType
        redef fun tpl_signature do
                var tpl = new Template
-               tpl.add tpl_link
+               var lnk = tpl_link
+               lnk.text = mclass.name.html_escape
+               tpl.add lnk
                tpl.add "["
                for i in [0..arguments.length[ do
                        tpl.add arguments[i].tpl_signature
index 83c1842..53fc0cf 100644 (file)
@@ -16,6 +16,7 @@
 module html_templates
 
 import html_model
+import html::bootstrap
 
 # Renders the page as HTML.
 redef class DocPage
@@ -31,7 +32,7 @@ redef class DocPage
        var body_attrs = new Array[TagAttribute]
 
        # Top menu template if any.
-       var topmenu: TplTopMenu is writable, noinit
+       var topmenu: DocTopMenu is writable, noinit
 
        # Sidebar template if any.
        var sidebar: nullable TplSidebar = null is writable
@@ -74,13 +75,6 @@ redef class DocPage
                addn ">"
        end
 
-       # Renders the topmenu template.
-       private fun render_topmenu do
-               addn " <div class='row'>"
-               add topmenu
-               addn " </div>"
-       end
-
        # Renders the sidebar template.
        #
        # Sidebar is automatically populated with a summary of all sections
@@ -129,7 +123,9 @@ redef class DocPage
        redef fun rendering do
                render_head
                addn "<div class='container-fluid'>"
-               render_topmenu
+               addn " <div class='row'>"
+               add topmenu
+               addn " </div>"
                addn " <div class='row' id='content'>"
                if sidebar != null then
                        addn "<div class='col col-xs-3 col-lg-2'>"
@@ -148,3 +144,55 @@ redef class DocPage
                render_footer
        end
 end
+
+# Top menu bar template.
+#
+# FIXME should be a Bootstrap component template
+# At this moment, the topmenu structure stills to specific to Nitdoc to use the
+# generic component.
+class DocTopMenu
+       super UnorderedList
+
+       # Brand link to display in first position of the top menu.
+       #
+       # This is where you want to put your logo.
+       var brand: nullable Writable is noinit, writable
+
+       # Active menu item.
+       #
+       # Depends on the current page, this allows to hilighted the current item.
+       #
+       # FIXME should be using Boostrap breadcrumbs component.
+       # This will still like this to avoid diff and be changed in further fixes
+       # when we will modify the output.
+       var active_item: nullable ListItem is noinit, writable
+
+       redef fun rendering do
+               addn "<nav id='topmenu' class='navbar navbar-default navbar-fixed-top' role='navigation'>"
+               addn " <div class='container-fluid'>"
+               addn "  <div class='navbar-header'>"
+               add "   <button type='button' class='navbar-toggle' "
+               addn "       data-toggle='collapse' data-target='#topmenu-collapse'>"
+               addn "    <span class='sr-only'>Toggle menu</span>"
+               addn "    <span class='icon-bar'></span>"
+               addn "    <span class='icon-bar'></span>"
+               addn "    <span class='icon-bar'></span>"
+               addn "   </button>"
+               if brand != null then
+                       add "<span class='navbar-brand'>"
+                       add brand.write_to_string
+                       add "</span>"
+               end
+               addn "  </div>"
+               addn "  <div class='collapse navbar-collapse' id='topmenu-collapse'>"
+               addn "   <ul class='nav navbar-nav'>"
+               for item in items do
+                       if item == active_item then item.css_classes.add "active"
+                       add item.write_to_string
+               end
+               addn "   </ul>"
+               addn "  </div>"
+               addn " </div>"
+               addn "</nav>"
+       end
+end
index bc4f0c4..4e8f45d 100644 (file)
@@ -68,10 +68,11 @@ private class ExternClassesTypingPhaseModel
                if not nclassdef isa AStdClassdef then return
 
                var mclassdef = nclassdef.mclassdef
-               var mclass = nclassdef.mclass
+               if mclassdef == null then return
+               var mclass = mclassdef.mclass
 
                # We only need to do this once per class
-               if mclass.intro != mclassdef then return
+               if not mclassdef.is_intro then return
 
                if mclass.kind != extern_kind then return
 
index 36244f6..ffba4ad 100644 (file)
@@ -40,7 +40,7 @@ private class CheckAnnotationPhase
        do
                # Get the mmodule
                var mmodule = nmodule.mmodule
-               assert mmodule != null
+               if mmodule == null then return
                self.mmodule = mmodule
 
                # If no decl block then quit
@@ -112,7 +112,7 @@ platform
                if primtives_annotations.has(name) then return
 
                var mmodule = self.mmodule
-               assert mmodule != null
+               if mmodule == null then return
 
                # Lazily build the full user-list
                var annots = user_annotations.get_or_null(mmodule)
index 4a8cfb4..6001f01 100644 (file)
@@ -37,7 +37,8 @@ private class DivByZeroPhase
        redef fun process_nmodule(nmodule)
        do
                # The AST node is not enough, we need also the associated model element
-               var mmodule = nmodule.mmodule.as(not null)
+               var mmodule = nmodule.mmodule
+               if mmodule == null then return
                # For the specific job we have, the simpler it to launch a visitor on
                # all elements of the AST.
                var visitor = new DivByZeroVisitor(toolcontext, mmodule)
index 9d39890..28e36bd 100644 (file)
@@ -25,6 +25,7 @@ import serialization_phase
 import deriving
 import check_annotation
 import glsl_validation
+import parallelization_phase
 
 redef class ToolContext
        # FIXME: there is conflict in linex in nitc, so use this trick to force invocation
@@ -42,6 +43,7 @@ redef class ToolContext
                # Code genrated by the serialization phase must be analyzed for literals
                phases.add_edge(literal_phase, serialization_phase_pre_model)
                phases.add_edge(modelize_class_phase, serialization_phase_pre_model)
+               phases.add_edge(modelize_class_phase, parallelization_phase)
                return true
        end
 end
index 931440e..bc59d8c 100644 (file)
@@ -30,7 +30,7 @@ private class NoWarningPhase
        do
                # Get the mmodule
                var mmodule = nmodule.mmodule
-               assert mmodule != null
+               if mmodule == null then return
 
                var source = nmodule.location.file
 
diff --git a/src/frontend/parallelization_phase.nit b/src/frontend/parallelization_phase.nit
new file mode 100644 (file)
index 0000000..7da80ff
--- /dev/null
@@ -0,0 +1,110 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2015 Romain Chanoir <romain.chanoir@viacesi.fr>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+# Phase generating threads for functions annotated with `threaded` annotation
+module parallelization_phase
+
+private import parser_util
+import modelize
+import astbuilder
+private import annotation
+
+redef class ToolContext
+       # Transforms a function annotated with "threaded"
+       var parallelization_phase: Phase = new ParallelizationPhase(self, null)
+end
+
+private class ParallelizationPhase
+       super Phase
+
+       redef fun process_annotated_node(nmethdef, nat)
+       do
+               if nat.n_atid.n_id.text != "threaded" then return
+
+               if not nmethdef isa AMethPropdef then
+                       toolcontext.error(nmethdef.location, "Syntax error: only a method can be threaded.")
+                       return
+               end
+               if nmethdef.n_signature.n_params.length != 0 then
+                       toolcontext.error(nmethdef.location, "Syntax error: parametrized method not supported yet.")
+                       return
+               end
+               if nmethdef.n_signature.n_type != null then
+                       toolcontext.error(nmethdef.location, "Syntax error: method with a return value not supported yet.")
+                       return
+               end
+
+               # Get the module associated with this method
+               var amod = nmethdef.parent.parent
+               assert amod isa AModule
+
+               # Construct the name of the generated class
+               var modulename = amod.n_moduledecl.n_name.n_id.text
+               var classname = "Threaded" + modulename
+
+               # Try to get the name of the class
+               if nmethdef.parent isa AStdClassdef then
+                       classname += nmethdef.parent.as(AStdClassdef).n_id.text
+               end
+
+               # Try to get the name of the method
+               if nmethdef.n_methid isa AIdMethid then
+                       classname += nmethdef.n_methid.as(AIdMethid).n_id.text
+               end
+
+               # Create a string corresponding to the threaded class
+               var s ="""
+class {{{classname}}}
+       super Thread
+
+       redef fun main do
+       end
+end
+"""
+
+               # Parse newly obtained classdef
+               var classdef = toolcontext.parse_classdef(s).as(AStdClassdef)
+
+               # Get the `main` fun of the class
+               var mainfun : nullable AMethPropdef = null
+               for prop in classdef.n_propdefs do
+                       if prop isa AMethPropdef then mainfun = prop
+               end
+               assert mainfun != null
+
+               # Make the statements from `main` fun be the statements from the "threaded" fun
+               mainfun.n_block = nmethdef.n_block
+
+               # Add "return null" to the end of the `main` function
+               var s_nullreturn = "return null"
+               var nullreturn = toolcontext.parse_something(s_nullreturn)
+               assert nullreturn isa AExpr
+               mainfun.n_block.as(ABlockExpr).n_expr.add(nullreturn)
+
+               # Create new body for the annotated fun
+               var s_newbody ="""
+var thread = new {{{classname}}}
+thread.start
+"""
+
+               var newbody = toolcontext.parse_something(s_newbody)
+               nmethdef.n_block = newbody.as(ABlockExpr)
+
+               # Add the new class to the module
+               amod.n_classdefs.add(classdef)
+       end
+end
index 2b68eea..0d7e4ec 100644 (file)
@@ -184,7 +184,9 @@ private class SerializationPhasePostModel
        redef fun process_nmodule(nmodule)
        do
                for npropdef in nmodule.inits_to_retype do
-                       var v = new PreciseTypeVisitor(npropdef, npropdef.mpropdef.mclassdef, toolcontext)
+                       var mpropdef = npropdef.mpropdef
+                       if mpropdef == null then continue # skip error
+                       var v = new PreciseTypeVisitor(npropdef, mpropdef.mclassdef, toolcontext)
                        npropdef.accept_precise_type_visitor v
                end
        end
index ecc4c7d..39a042a 100644 (file)
@@ -510,6 +510,33 @@ redef class MNullableType
        end
 end
 
+redef class MNotNullType
+       redef fun infobox(v)
+       do
+               return mtype.infobox(v)
+       end
+       redef fun linkto
+       do
+               var res = new HTMLTag("span")
+               res.append("not null ").add(mtype.linkto)
+               return res
+       end
+end
+
+redef class MNullType
+       redef fun infobox(v)
+       do
+               var res = new HInfoBox(v, to_s)
+               return res
+       end
+       redef fun linkto
+       do
+               var res = new HTMLTag("span")
+               res.append("null")
+               return res
+       end
+end
+
 redef class MSignature
        redef fun linkto
        do
@@ -870,8 +897,8 @@ redef class AType
        do
                var mt = mtype
                if mt == null then return null
-               mt = mt.as_notnullable
-               if mt isa MVirtualType or mt isa MParameterType then
+               mt = mt.undecorate
+               if mt isa MFormalType then
                        res.add_class("nc_vt")
                end
                return mt.infobox(v)
index 21118ab..272219f 100644 (file)
@@ -1016,6 +1016,9 @@ redef class AMethPropdef
                                return v.int_instance(res)
                        else if pname == "atof" then
                                return v.float_instance(recvval.to_f)
+                       else if pname == "fast_cstring" then
+                               var ns = recvval.to_cstring.to_s.substring_from(args[1].to_i)
+                               return v.native_string_instance(ns)
                        end
                else if cname == "String" then
                        var cs = v.send(v.force_get_primitive_method("to_cstring", args.first.mtype), [args.first])
index 492584b..9876bc4 100644 (file)
@@ -72,8 +72,9 @@ redef class ModelBuilder
                        if nmodule == null then continue # Skip error
                        # Load imported module
                        build_module_importation(nmodule)
-
-                       mmodules.add(nmodule.mmodule.as(not null))
+                       var mmodule = nmodule.mmodule
+                       if mmodule == null then continue # skip error
+                       mmodules.add mmodule
                end
                var time1 = get_time
                self.toolcontext.info("*** END PARSE: {time1-time0} ***", 2)
@@ -100,16 +101,28 @@ redef class ModelBuilder
                                if nmodule == null then continue # Skip error
                                # Load imported module
                                build_module_importation(nmodule)
-
-                               res.add(nmodule.mmodule.as(not null))
+                               var mmodule = nmodule.mmodule
+                               if mmodule == null then continue # Skip error
+                               res.add mmodule
                        end
                end
                return res
        end
 
        # Load a bunch of modules and groups.
-       # Each name can be a module or a group.
-       # If it is a group then recursively all its modules are parsed.
+       #
+       # Each name can be:
+       #
+       # * a path to a module, a group or a directory of projects.
+       # * a short name of a module or a group that are looked in the `paths` (-I)
+       #
+       # Then, for each entry, if it is:
+       #
+       # * a module, then is it parser and returned.
+       # * a group then recursively all its modules are parsed.
+       # * a directory of projects then all the modules of all projects are parsed.
+       # * else an error is displayed.
+       #
        # See `parse` for details.
        fun parse_full(names: Sequence[String]): Array[MModule]
        do
@@ -118,17 +131,48 @@ redef class ModelBuilder
                self.toolcontext.info("*** PARSE ***", 1)
                var mmodules = new ArraySet[MModule]
                for a in names do
+                       # Case of a group
                        var mgroup = self.get_mgroup(a)
                        if mgroup != null then
                                mmodules.add_all parse_group(mgroup)
                                continue
                        end
+
+                       # Case of a directory that is not a group
+                       var stat = a.to_path.stat
+                       if stat != null and stat.is_dir then
+                               self.toolcontext.info("look in directory {a}", 2)
+                               var fs = a.files
+                               # Try each entry as a group or a module
+                               for f in fs do
+                                       var af = a/f
+                                       mgroup = get_mgroup(af)
+                                       if mgroup != null then
+                                               mmodules.add_all parse_group(mgroup)
+                                               continue
+                                       end
+                                       var mp = identify_file(af)
+                                       if mp != null then
+                                               var nmodule = self.load_module(af)
+                                               if nmodule == null then continue # Skip error
+                                               build_module_importation(nmodule)
+                                               var mmodule = nmodule.mmodule
+                                               if mmodule == null then continue # Skip error
+                                               mmodules.add mmodule
+                                       else
+                                               self.toolcontext.info("ignore file {af}", 2)
+                                       end
+                               end
+                               continue
+                       end
+
                        var nmodule = self.load_module(a)
                        if nmodule == null then continue # Skip error
                        # Load imported module
                        build_module_importation(nmodule)
-
-                       mmodules.add(nmodule.mmodule.as(not null))
+                       var mmodule = nmodule.mmodule
+                       if mmodule == null then continue # Skip error
+                       mmodules.add mmodule
                end
                var time1 = get_time
                self.toolcontext.info("*** END PARSE: {time1-time0} ***", 2)
@@ -222,7 +266,7 @@ redef class ModelBuilder
                if res == null then return null # Forward error
                # Load imported module
                build_module_importation(res)
-               return res.mmodule.as(not null)
+               return res.mmodule
        end
 
        # Search a module `name` from path `lookpaths`.
@@ -350,12 +394,15 @@ redef class ModelBuilder
                        return mgroups[rdp]
                end
 
-               # Hack, a group is determined by:
+               # Hack, a group is determined by one of the following:
                # * the presence of a honomymous nit file
                # * the fact that the directory is named `src`
+               # * the fact that there is a sub-directory named `src`
                var pn = rdp.basename(".nit")
                var mp = dirpath.join_path(pn + ".nit").simplify_path
 
+               # dirpath2 is the root directory
+               # dirpath is the src subdirectory directory, if any, else it is the same that dirpath2
                var dirpath2 = dirpath
                if not mp.file_exists then
                        if pn == "src" then
@@ -363,12 +410,17 @@ redef class ModelBuilder
                                dirpath2 = rdp.dirname
                                pn = dirpath2.basename("")
                        else
-                               return null
+                               # Check a `src` subdirectory
+                               dirpath = dirpath2 / "src"
+                               if not dirpath.file_exists then
+                                       # All rules failed, so return null
+                                       return null
+                               end
                        end
                end
 
                # check parent directory
-               var parentpath = dirpath.join_path("..").simplify_path
+               var parentpath = dirpath2.join_path("..").simplify_path
                var parent = get_mgroup(parentpath)
 
                var mgroup
@@ -382,15 +434,22 @@ redef class ModelBuilder
                        mgroup = new MGroup(pn, parent.mproject, parent)
                        toolcontext.info("found sub group `{mgroup.full_name}` at {dirpath}", 2)
                end
-               var readme = dirpath2.join_path("README.md")
+
+               # search documentation
+               # in src first so the documentation of the project code can be distinct for the documentation of the project usage
+               var readme = dirpath.join_path("README.md")
+               if not readme.file_exists then readme = dirpath.join_path("README")
+               if not readme.file_exists then readme = dirpath2.join_path("README.md")
                if not readme.file_exists then readme = dirpath2.join_path("README")
                if readme.file_exists then
                        var mdoc = load_markdown(readme)
                        mgroup.mdoc = mdoc
                        mdoc.original_mentity = mgroup
                end
+
                mgroup.filepath = dirpath
-               mgroups[rdp] = mgroup
+               mgroups[module_absolute_path(dirpath)] = mgroup
+               mgroups[module_absolute_path(dirpath2)] = mgroup
                return mgroup
        end
 
@@ -613,24 +672,33 @@ redef class ModelBuilder
                        if aimport.n_name.n_quad != null then mgroup = null # Start from top level
                        for grp in aimport.n_name.n_path do
                                var path = search_mmodule_by_name(grp, mgroup, grp.text)
-                               if path == null then return # Skip error
+                               if path == null then
+                                       nmodule.mmodule = null # invalidate the module
+                                       return # Skip error
+                               end
                                mgroup = path.mgroup
                        end
                        var mod_name = aimport.n_name.n_id.text
                        var sup = self.get_mmodule_by_name(aimport.n_name, mgroup, mod_name)
-                       if sup == null then continue # Skip error
+                       if sup == null then
+                               nmodule.mmodule = null # invalidate the module
+                               continue # Skip error
+                       end
                        aimport.mmodule = sup
                        imported_modules.add(sup)
                        var mvisibility = aimport.n_visibility.mvisibility
                        if mvisibility == protected_visibility then
                                error(aimport.n_visibility, "Error: only properties can be protected.")
+                               nmodule.mmodule = null # invalidate the module
                                return
                        end
                        if sup == mmodule then
                                error(aimport.n_name, "Error: Dependency loop in module {mmodule}.")
+                               nmodule.mmodule = null # invalidate the module
                        end
                        if sup.in_importation < mmodule then
                                error(aimport.n_name, "Error: Dependency loop between modules {mmodule} and {sup}.")
+                               nmodule.mmodule = null # invalidate the module
                                return
                        end
                        mmodule.set_visibility_for(sup, mvisibility)
@@ -638,7 +706,9 @@ redef class ModelBuilder
                if stdimport then
                        var mod_name = "standard"
                        var sup = self.get_mmodule_by_name(nmodule, null, mod_name)
-                       if sup != null then # Skip error
+                       if sup == null then
+                               nmodule.mmodule = null # invalidate the module
+                       else # Skip error
                                imported_modules.add(sup)
                                mmodule.set_visibility_for(sup, public_visibility)
                        end
index dd7c36d..9090658 100644 (file)
@@ -130,8 +130,8 @@ private class DetectCovariancePhase
        # Returns true if the test concern real generic covariance
        fun count_types(node, elem: ANode, sub, sup: MType, mmodule: MModule, anchor: nullable MClassType): Bool
        do
-               sub = sub.as_notnullable
-               sup = sup.as_notnullable
+               sub = sub.undecorate
+               sup = sup.undecorate
 
                # Category of the target type
                if sub isa MGenericType then
@@ -254,8 +254,8 @@ private class DetectCovariancePhase
        fun count_cast(node: ANode, sub, sup: MType, mmodule: MModule, anchor: nullable MClassType)
        do
                var nsup = sup
-               sup = sup.as_notnullable
-               sub = sub.as_notnullable
+               sup = sup.undecorate
+               sub = sub.undecorate
 
                if sub == nsup then
                        cpt_cast_pattern.inc("monomorphic cast!?!")
@@ -445,7 +445,7 @@ redef class MType
                # Now the case of direct null and nullable is over.
 
                # If `sub` is a formal type, then it is accepted if its bound is accepted
-               while sub isa MParameterType or sub isa MVirtualType do
+               while sub isa MFormalType do
                        #print "3.is {sub} a {sup}?"
 
                        # A unfixed formal type can only accept itself
@@ -469,7 +469,7 @@ redef class MType
                assert sub isa MClassType # It is the only remaining type
 
                # A unfixed formal type can only accept itself
-               if sup isa MParameterType or sup isa MVirtualType then
+               if sup isa MFormalType then
                        return false
                end
 
index 3665376..1f0205e 100644 (file)
@@ -113,7 +113,7 @@ class DetectVarianceConstraints
                                        if pd isa MMethodDef then
                                                # Parameters (contravariant)
                                                for p in pd.msignature.mparameters do
-                                                       var t = p.mtype.as_notnullable
+                                                       var t = p.mtype.undecorate
                                                        if not t.need_anchor then
                                                                # OK
                                                        else if t isa MParameterType then
@@ -129,7 +129,7 @@ class DetectVarianceConstraints
                                                # Return (covariant)
                                                var t = pd.msignature.return_mtype
                                                if t != null and t.need_anchor then
-                                                       t = t.as_notnullable
+                                                       t = t.undecorate
                                                        if t isa MParameterType then
                                                                covar_pt.add(t)
                                                        else if t isa MVirtualType then
@@ -144,7 +144,7 @@ class DetectVarianceConstraints
                                                # Attribute (invariant)
                                                var t = pd.static_mtype
                                                if t != null and t.need_anchor then
-                                                       t = t.as_notnullable
+                                                       t = t.undecorate
                                                        if t isa MParameterType then
                                                                covar_pt.add t
                                                                contravar_pt.add t
@@ -161,7 +161,7 @@ class DetectVarianceConstraints
                                                # Virtual type bound (covariant)
                                                var t = pd.bound
                                                if t != null and t.need_anchor then
-                                                       t = t.as_notnullable
+                                                       t = t.undecorate
                                                        if t isa MParameterType then
                                                                covar_pt.add t
                                                        else if t isa MVirtualType then
@@ -223,7 +223,7 @@ class DetectVarianceConstraints
                        # Process the generic types in a covariant position
                        for c in covar_classes do for i in [0..c.mclass.arity[ do
                                # The type used in the argument
-                               var ta = c.arguments[i].as_notnullable
+                               var ta = c.arguments[i].undecorate
                                # The associated formal parameter
                                var tp = c.mclass.mparameters[i]
 
@@ -259,7 +259,7 @@ class DetectVarianceConstraints
                        # Process the generic types in a contravariant position
                        for c in contravar_classes do for i in [0..c.mclass.arity[ do
                                # The type used in the argument
-                               var ta = c.arguments[i].as_notnullable
+                               var ta = c.arguments[i].undecorate
                                # The associated formal parameter
                                var tp = c.mclass.mparameters[i]
 
index 1527731..00f9d02 100644 (file)
@@ -374,7 +374,7 @@ redef class RapidTypeAnalysis
                super
                tnlc.values.inc(mtype)
 
-               mtype = mtype.as_notnullable
+               mtype = mtype.undecorate
                if mtype isa MClassType then
                        cnlc.values.inc(mtype.mclass)
                end
@@ -385,7 +385,7 @@ end
 
 redef class MType
        private fun signature_depth: Int do
-               var mtype = self.as_notnullable
+               var mtype = self.undecorate
                if not mtype isa MGenericType then return 0
 
                var depth = 0
index d88a0ba..ef548a8 100644 (file)
@@ -243,5 +243,15 @@ class MModule
        # Is `self` a unit test module used by `nitunit`?
        var is_test_suite: Bool = false is writable
 
+       # Get the first non `is_fictive` module greater than self
+       fun first_real_mmodule: MModule
+       do
+               var mmodule = self
+               while mmodule.is_fictive do
+                       mmodule = mmodule.in_importation.direct_greaters.first
+               end
+               return mmodule
+       end
+
        redef fun parent_concern do return mgroup
 end
index 3a64638..62c3db4 100644 (file)
@@ -251,7 +251,9 @@ redef class MModule
        fun get_primitive_class(name: String): MClass
        do
                var cla = self.model.get_mclasses_by_name(name)
-               if cla == null then
+               # Filter classes by introducing module
+               if cla != null then cla = [for c in cla do if self.in_importation <= c.intro_mmodule then c]
+               if cla == null or cla.is_empty then
                        if name == "Bool" and self.model.get_mclasses_by_name("Object") != null then
                                # Bool is injected because it is needed by engine to code the result
                                # of the implicit casts.
@@ -261,11 +263,11 @@ redef class MModule
                                cladef.add_in_hierarchy
                                return c
                        end
-                       print("Fatal Error: no primitive class {name}")
+                       print("Fatal Error: no primitive class {name} in {self}")
                        exit(1)
                end
                if cla.length != 1 then
-                       var msg = "Fatal Error: more than one primitive class {name}:"
+                       var msg = "Fatal Error: more than one primitive class {name} in {self}:"
                        for c in cla do msg += " {c.full_name}"
                        print msg
                        #exit(1)
@@ -433,8 +435,17 @@ class MClass
        #
        # Warning: such a definition may not exist in the early life of the object.
        # In this case, the method will abort.
+       #
+       # Use `try_intro` instead
        var intro: MClassDef is noinit
 
+       # The definition that introduces the class or null if not yet known.
+       #
+       # See `intro`
+       fun try_intro: nullable MClassDef do
+               if isset _intro then return _intro else return null
+       end
+
        # Return the class `self` in the class hierarchy of the module `mmodule`.
        #
        # SEE: `MModule::flatten_mclass_hierarchy`
@@ -477,6 +488,9 @@ class MClass
        end
 
        private var get_mtype_cache = new HashMap[Array[MType], MGenericType]
+
+       # Is there a `new` factory to allow the pseudo instantiation?
+       var has_new_factory = false is writable
 end
 
 
@@ -624,7 +638,7 @@ class MClassDef
        var in_hierarchy: nullable POSetElement[MClassDef] = null
 
        # Is the definition the one that introduced `mclass`?
-       fun is_intro: Bool do return mclass.intro == self
+       fun is_intro: Bool do return isset mclass._intro and mclass.intro == self
 
        # All properties introduced by the classdef
        var intro_mproperties = new Array[MProperty]
@@ -694,6 +708,8 @@ abstract class MType
                if sup isa MNullableType then
                        sup_accept_null = true
                        sup = sup.mtype
+               else if sup isa MNotNullType then
+                       sup = sup.mtype
                else if sup isa MNullType then
                        sup_accept_null = true
                end
@@ -701,16 +717,20 @@ abstract class MType
                # Can `sub` provide null or not?
                # Thus we can match with `sup_accept_null`
                # Also discard the nullable marker if it exists
+               var sub_reject_null = false
                if sub isa MNullableType then
                        if not sup_accept_null then return false
                        sub = sub.mtype
+               else if sub isa MNotNullType then
+                       sub_reject_null = true
+                       sub = sub.mtype
                else if sub isa MNullType then
                        return sup_accept_null
                end
                # Now the case of direct null and nullable is over.
 
                # If `sub` is a formal type, then it is accepted if its bound is accepted
-               while sub isa MParameterType or sub isa MVirtualType do
+               while sub isa MFormalType do
                        #print "3.is {sub} a {sup}?"
 
                        # A unfixed formal type can only accept itself
@@ -718,12 +738,16 @@ abstract class MType
 
                        assert anchor != null
                        sub = sub.lookup_bound(mmodule, anchor)
+                       if sub_reject_null then sub = sub.as_notnull
 
                        #print "3.is {sub} a {sup}?"
 
                        # Manage the second layer of null/nullable
                        if sub isa MNullableType then
-                               if not sup_accept_null then return false
+                               if not sup_accept_null and not sub_reject_null then return false
+                               sub = sub.mtype
+                       else if sub isa MNotNullType then
+                               sub_reject_null = true
                                sub = sub.mtype
                        else if sub isa MNullType then
                                return sup_accept_null
@@ -731,10 +755,10 @@ abstract class MType
                end
                #print "4.is {sub} a {sup}? <- no more resolution"
 
-               assert sub isa MClassType # It is the only remaining type
+               assert sub isa MClassType else print "{sub} <? {sub}" # It is the only remaining type
 
                # A unfixed formal type can only accept itself
-               if sup isa MParameterType or sup isa MVirtualType then
+               if sup isa MFormalType then
                        return false
                end
 
@@ -985,16 +1009,25 @@ abstract class MType
                return res
        end
 
-       # Return the not nullable version of the type
-       # Is the type is already not nullable, then self is returned.
+       # Remove the base type of a decorated (proxy) type.
+       # Is the type is not decorated, then self is returned.
        #
-       # Note: this just remove the `nullable` notation, but the result can still contains null.
+       # Most of the time it is used to return the not nullable version of a nullable type.
+       # In this case, this just remove the `nullable` notation, but the result can still contains null.
        # For instance if `self isa MNullType` or self is a formal type bounded by a nullable type.
-       fun as_notnullable: MType
+       # If you really want to exclude the `null` value, then use `as_notnull`
+       fun undecorate: MType
        do
                return self
        end
 
+       # Returns the not null version of the type.
+       # That is `self` minus the `null` value.
+       #
+       # For most types, this return `self`.
+       # For formal types, this returns a special `MNotNullType`
+       fun as_notnull: MType do return self
+
        private var as_nullable_cache: nullable MType = null
 
 
@@ -1256,9 +1289,19 @@ class MGenericType
        end
 end
 
+# A formal type (either virtual of parametric).
+#
+# The main issue with formal types is that they offer very little information on their own
+# and need a context (anchor and mmodule) to be useful.
+abstract class MFormalType
+       super MType
+
+       redef var as_notnull = new MNotNullType(self) is lazy
+end
+
 # A virtual formal type.
 class MVirtualType
-       super MType
+       super MFormalType
 
        # The property associated with the type.
        # Its the definitions of this property that determine the bound or the virtual type.
@@ -1299,7 +1342,7 @@ class MVirtualType
        redef fun lookup_fixed(mmodule: MModule, resolved_receiver: MType): MType
        do
                assert not resolved_receiver.need_anchor
-               resolved_receiver = resolved_receiver.as_notnullable
+               resolved_receiver = resolved_receiver.undecorate
                assert resolved_receiver isa MClassType # It is the only remaining type
 
                var prop = lookup_single_definition(mmodule, resolved_receiver)
@@ -1386,7 +1429,7 @@ end
 # Note that parameter types are shared among class refinements.
 # Therefore parameter only have an internal name (see `to_s` for details).
 class MParameterType
-       super MType
+       super MFormalType
 
        # The generic class where the parameter belong
        var mclass: MClass
@@ -1408,7 +1451,7 @@ class MParameterType
        redef fun lookup_bound(mmodule: MModule, resolved_receiver: MType): MType
        do
                assert not resolved_receiver.need_anchor
-               resolved_receiver = resolved_receiver.as_notnullable
+               resolved_receiver = resolved_receiver.undecorate
                assert resolved_receiver isa MClassType # It is the only remaining type
                var goalclass = self.mclass
                if resolved_receiver.mclass == goalclass then
@@ -1436,7 +1479,7 @@ class MParameterType
        redef fun lookup_fixed(mmodule: MModule, resolved_receiver: MType): MType
        do
                assert not resolved_receiver.need_anchor
-               resolved_receiver = resolved_receiver.as_notnullable
+               resolved_receiver = resolved_receiver.undecorate
                assert resolved_receiver isa MClassType # It is the only remaining type
                var res = self.resolve_for(resolved_receiver.mclass.mclass_type, resolved_receiver, mmodule, false)
                return res
@@ -1508,33 +1551,24 @@ class MParameterType
        end
 end
 
-# A type prefixed with "nullable"
-class MNullableType
+# A type that decorates another type.
+#
+# The point of this class is to provide a common implementation of sevices that just forward to the original type.
+# Specific decorator are expected to redefine (or to extend) the default implementation as this suit them.
+abstract class MProxyType
        super MType
-
-       # The base type of the nullable type
+       # The base type
        var mtype: MType
 
        redef fun model do return self.mtype.model
-
-       init
-       do
-               self.to_s = "nullable {mtype}"
-       end
-
-       redef var to_s: String is noinit
-
-       redef var full_name is lazy do return "nullable {mtype.full_name}"
-
-       redef var c_name is lazy do return "nullable__{mtype.c_name}"
-
        redef fun need_anchor do return mtype.need_anchor
-       redef fun as_nullable do return self
-       redef fun as_notnullable do return mtype
+       redef fun as_nullable do return mtype.as_nullable
+       redef fun as_notnull do return mtype.as_notnull
+       redef fun undecorate do return mtype.undecorate
        redef fun resolve_for(mtype, anchor, mmodule, cleanup_virtual)
        do
                var res = self.mtype.resolve_for(mtype, anchor, mmodule, cleanup_virtual)
-               return res.as_nullable
+               return res
        end
 
        redef fun can_resolve_for(mtype, anchor, mmodule)
@@ -1542,12 +1576,10 @@ class MNullableType
                return self.mtype.can_resolve_for(mtype, anchor, mmodule)
        end
 
-       # Efficiently returns `mtype.lookup_fixed(mmodule, resolved_receiver).as_nullable`
        redef fun lookup_fixed(mmodule, resolved_receiver)
        do
                var t = mtype.lookup_fixed(mmodule, resolved_receiver)
-               if t == mtype then return self
-               return t.as_nullable
+               return t
        end
 
        redef fun depth do return self.mtype.depth
@@ -1573,6 +1605,64 @@ class MNullableType
        end
 end
 
+# A type prefixed with "nullable"
+class MNullableType
+       super MProxyType
+
+       init
+       do
+               self.to_s = "nullable {mtype}"
+       end
+
+       redef var to_s: String is noinit
+
+       redef var full_name is lazy do return "nullable {mtype.full_name}"
+
+       redef var c_name is lazy do return "nullable__{mtype.c_name}"
+
+       redef fun as_nullable do return self
+       redef fun resolve_for(mtype, anchor, mmodule, cleanup_virtual)
+       do
+               var res = super
+               return res.as_nullable
+       end
+
+       # Efficiently returns `mtype.lookup_fixed(mmodule, resolved_receiver).as_nullable`
+       redef fun lookup_fixed(mmodule, resolved_receiver)
+       do
+               var t = super
+               if t == mtype then return self
+               return t.as_nullable
+       end
+end
+
+# A non-null version of a formal type.
+#
+# When a formal type in bounded to a nullable type, this is the type of the not null version of it.
+class MNotNullType
+       super MProxyType
+
+       redef fun to_s do return "not null {mtype}"
+       redef var full_name is lazy do return "not null {mtype.full_name}"
+       redef var c_name is lazy do return "notnull__{mtype.c_name}"
+
+       redef fun as_notnull do return self
+
+       redef fun resolve_for(mtype, anchor, mmodule, cleanup_virtual)
+       do
+               var res = super
+               return res.as_notnull
+       end
+
+       # Efficiently returns `mtype.lookup_fixed(mmodule, resolved_receiver).as_notnull`
+       redef fun lookup_fixed(mmodule, resolved_receiver)
+       do
+               var t = super
+               if t == mtype then return self
+               return t.as_notnull
+       end
+end
+
 # The type of the only value null
 #
 # The is only one null type per model, see `MModel::null_type`.
@@ -1583,6 +1673,9 @@ class MNullType
        redef fun full_name do return "null"
        redef fun c_name do return "null"
        redef fun as_nullable do return self
+
+       # Aborts on `null`
+       redef fun as_notnull do abort # sorry...
        redef fun need_anchor do return false
        redef fun resolve_for(mtype, anchor, mmodule, cleanup_virtual) do return self
        redef fun can_resolve_for(mtype, anchor, mmodule) do return true
@@ -1805,7 +1898,7 @@ abstract class MProperty
        fun lookup_definitions(mmodule: MModule, mtype: MType): Array[MPROPDEF]
        do
                assert not mtype.need_anchor
-               mtype = mtype.as_notnullable
+               mtype = mtype.undecorate
 
                var cache = self.lookup_definitions_cache[mmodule, mtype]
                if cache != null then return cache
@@ -1845,7 +1938,7 @@ abstract class MProperty
        fun lookup_super_definitions(mmodule: MModule, mtype: MType): Array[MPROPDEF]
        do
                assert not mtype.need_anchor
-               mtype = mtype.as_notnullable
+               mtype = mtype.undecorate
 
                # First, select all candidates
                var candidates = new Array[MPROPDEF]
@@ -1923,7 +2016,7 @@ abstract class MProperty
        # REQUIRE: `mtype.has_mproperty(mmodule, self)`
        fun lookup_all_definitions(mmodule: MModule, mtype: MType): Array[MPROPDEF]
        do
-               mtype = mtype.as_notnullable
+               mtype = mtype.undecorate
 
                var cache = self.lookup_all_definitions_cache[mmodule, mtype]
                if cache != null then return cache
index 30f5885..23f7d49 100644 (file)
@@ -52,11 +52,16 @@ redef class ToolContext
        # 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)
+               if not mmodules.is_empty then
+                       var mainmodule = make_main_module(mmodules)
+                       for phase in phases_list do
+                               if phase.disabled then continue
+                               phase.process_mainmodule(mainmodule, mmodules)
+                       end
                end
+
+               check_errors
+               errors_info
        end
 end
 
index 9995338..93423df 100644 (file)
@@ -81,6 +81,16 @@ class ModelBuilder
                return res
        end
 
+       # Like `try_get_mclass_by_name` but display an error message when the class is not found
+       fun get_mclass_by_name(node: ANode, mmodule: MModule, name: String): nullable MClass
+       do
+               var mclass = try_get_mclass_by_name(node, mmodule, name)
+               if mclass == null then
+                       error(node, "Type Error: missing primitive class `{name}'.")
+               end
+               return mclass
+       end
+
        # Return a property named `name` on the type `mtype` visible in the module `mmodule`.
        # Visibility in modules is correctly handled.
        # Protected properties are returned (it is up to the caller to check and reject protected properties).
@@ -305,7 +315,9 @@ class ModelBuilder
                if mtype isa MGenericType then
                        var mclass = mtype.mclass
                        for i in [0..mclass.arity[ do
-                               var bound = mclass.intro.bound_mtype.arguments[i]
+                               var intro = mclass.try_intro
+                               if intro == null then return null # skip error
+                               var bound = intro.bound_mtype.arguments[i]
                                var nt = ntype.n_types[i]
                                var mt = resolve_mtype(mmodule, mclassdef, nt)
                                if mt == null then return null # forward error
index c779df9..5618c11 100644 (file)
@@ -103,7 +103,9 @@ redef class ModelBuilder
                                var mclasses = model.get_mclasses_by_name(name)
                                if mclasses != null then for other in mclasses do
                                        if other.intro_mmodule.mgroup != null and other.intro_mmodule.mgroup.mproject == mmodule.mgroup.mproject then
-                                               error(nclassdef, "Error: A class named `{other.full_name}` is already defined in module `{other.intro_mmodule}` at {other.intro.location}.")
+                                               # Skip classes that are buggy
+                                               if other.try_intro == null then continue
+                                               warning(nclassdef, "full-name-conflict", "Error: A class named `{other.full_name}` is already defined in module `{other.intro_mmodule}` at {other.intro.location}.")
                                                break
                                        end
                                end
@@ -224,11 +226,14 @@ redef class ModelBuilder
        # Visit the AST and set the super-types of the `MClassDef` objects
        private fun collect_a_mclassdef_inheritance(nmodule: AModule, nclassdef: AClassdef)
        do
-               var mmodule = nmodule.mmodule.as(not null)
+               var mmodule = nmodule.mmodule
+               if mmodule == null then return
                var objectclass = try_get_mclass_by_name(nmodule, mmodule, "Object")
                var pointerclass = try_get_mclass_by_name(nmodule, mmodule, "Pointer")
-               var mclass = nclassdef.mclass.as(not null)
-               var mclassdef = nclassdef.mclassdef.as(not null)
+               var mclass = nclassdef.mclass
+               if mclass == null then return
+               var mclassdef = nclassdef.mclassdef
+               if mclassdef == null then return
 
                # Do we need to specify Object as a super class?
                var specobject = true
@@ -274,9 +279,12 @@ redef class ModelBuilder
        # Check the validity of the specialization heirarchy
        private fun check_supertypes(nmodule: AModule, nclassdef: AClassdef)
        do
-               var mmodule = nmodule.mmodule.as(not null)
-               var mclass = nclassdef.mclass.as(not null)
-               var mclassdef = nclassdef.mclassdef.as(not null)
+               var mmodule = nmodule.mmodule
+               if mmodule == null then return
+               var mclass = nclassdef.mclass
+               if mclass == null then return
+               var mclassdef = nclassdef.mclassdef
+               if mclassdef == null then return
 
                for s in mclassdef.supertypes do
                        if s.is_subtype(mmodule, mclassdef.bound_mtype, mclassdef.bound_mtype) then
@@ -293,7 +301,8 @@ redef class ModelBuilder
                # Force building recursively
                if nmodule.build_classes_is_done then return
                nmodule.build_classes_is_done = true
-               var mmodule = nmodule.mmodule.as(not null)
+               var mmodule = nmodule.mmodule
+               if mmodule == null then return
                for imp in mmodule.in_importation.direct_greaters do
                        var nimp = mmodule2node(imp)
                        if nimp != null then build_classes(nimp)
@@ -363,7 +372,8 @@ redef class ModelBuilder
 
                # Check clash of ancestors
                for nclassdef in nmodule.n_classdefs do
-                       var mclassdef = nclassdef.mclassdef.as(not null)
+                       var mclassdef = nclassdef.mclassdef
+                       if mclassdef == null then continue
                        var superclasses = new HashMap[MClass, MClassType]
                        for scd in mclassdef.in_hierarchy.greaters do
                                for st in scd.supertypes do
@@ -387,7 +397,8 @@ redef class ModelBuilder
                # Check that the superclasses are not already known (by transitivity)
                for nclassdef in nmodule.n_classdefs do
                        if not nclassdef isa AStdClassdef then continue
-                       var mclassdef = nclassdef.mclassdef.as(not null)
+                       var mclassdef = nclassdef.mclassdef
+                       if mclassdef == null then continue
 
                        # Get the direct superclasses
                        # Since we are a mclassdef, just look at the mclassdef hierarchy
index a4d1141..c224b29 100644 (file)
@@ -86,7 +86,8 @@ redef class ModelBuilder
                # Force building recursively
                if nclassdef.build_properties_is_done then return
                nclassdef.build_properties_is_done = true
-               var mclassdef = nclassdef.mclassdef.as(not null)
+               var mclassdef = nclassdef.mclassdef
+               if mclassdef == null then return # skip error
                if mclassdef.in_hierarchy == null then return # Skip error
                for superclassdef in mclassdef.in_hierarchy.direct_greaters do
                        if not mclassdef2nclassdef.has_key(superclassdef) then continue
@@ -102,6 +103,24 @@ redef class ModelBuilder
                                npropdef.build_signature(self)
                        end
                        for npropdef in nclassdef2.n_propdefs do
+                               if not npropdef isa ATypePropdef then continue
+                               # Check circularity
+                               var mpropdef = npropdef.mpropdef
+                               if mpropdef == null then continue
+                               if mpropdef.bound == null then continue
+                               if not check_virtual_types_circularity(npropdef, mpropdef.mproperty, mclassdef.bound_mtype, mclassdef.mmodule) then
+                                       # Invalidate the bound
+                                       mpropdef.bound = mclassdef.mmodule.model.null_type
+                               end
+                       end
+                       for npropdef in nclassdef2.n_propdefs do
+                               # Check ATypePropdef first since they may be required for the other properties
+                               if not npropdef isa ATypePropdef then continue
+                               npropdef.check_signature(self)
+                       end
+
+                       for npropdef in nclassdef2.n_propdefs do
+                               if npropdef isa ATypePropdef then continue
                                npropdef.check_signature(self)
                        end
                end
@@ -296,6 +315,7 @@ redef class ModelBuilder
                                        for p in spd.initializers do
                                                if p != longest.initializers[i] then
                                                        self.error(nclassdef, "Error: conflict for inherited inits {spd}({spd.initializers.join(", ")}) and {longest}({longest.initializers.join(", ")})")
+                                                       # TODO: invalidate the initializer to avoid more errors
                                                        return
                                                end
                                                i += 1
@@ -350,7 +370,7 @@ redef class ModelBuilder
                # 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 original module of the type
-               mtype = mtype.as_notnullable
+               mtype = mtype.undecorate
                if mtype isa MClassType then
                        vis_type = mtype.mclass.visibility
                        mmodule_type = mtype.mclass.intro.mmodule
@@ -359,6 +379,8 @@ redef class ModelBuilder
                        mmodule_type = mtype.mproperty.intro_mclassdef.mmodule
                else if mtype isa MParameterType then
                        # nothing, always visible
+               else if mtype isa MNullType then
+                       # nothing to do.
                else
                        node.debug "Unexpected type {mtype}"
                        abort
@@ -387,6 +409,72 @@ redef class ModelBuilder
                        for t in mtype.arguments do check_visibility(node, t, mpropdef)
                end
        end
+
+       # Detect circularity errors for virtual types.
+       fun check_virtual_types_circularity(node: ANode, mproperty: MVirtualTypeProp, recv: MType, mmodule: MModule): Bool
+       do
+               # Check circularity
+               # Slow case: progress on each resolution until we visit all without getting a loop
+
+               # The graph used to detect loops
+               var mtype = mproperty.mvirtualtype
+               var poset = new POSet[MType]
+
+               # The work-list of types to resolve
+               var todo = new List[MType]
+               todo.add mtype
+
+               while not todo.is_empty do
+                       # The visited type
+                       var t = todo.pop
+
+                       if not t.need_anchor then continue
+
+                       # Get the types derived of `t` (subtypes and bounds)
+                       var nexts
+                       if t isa MNullableType then
+                               nexts = [t.mtype]
+                       else if t isa MGenericType then
+                               nexts = t.arguments
+                       else if t isa MVirtualType then
+                               var vt = t.mproperty
+                               # Because `vt` is possibly unchecked, we have to do the bound-lookup manually
+                               var defs = vt.lookup_definitions(mmodule, recv)
+                               # TODO something to manage correctly bound conflicts
+                               assert not defs.is_empty
+                               nexts = new Array[MType]
+                               for d in defs do
+                                       var next = defs.first.bound
+                                       if next == null then return false
+                                       nexts.add next
+                               end
+                       else if t isa MClassType then
+                               # Basic type, nothing to to
+                               continue
+                       else if t isa MParameterType then
+                               # Parameter types cannot depend on virtual types, so nothing to do
+                               continue
+                       else
+                               abort
+                       end
+
+                       # For each one
+                       for next in nexts do
+                               if poset.has_edge(next, t) then
+                                       if mtype == next then
+                                               error(node, "Error: circularity of virtual type definition: {next} <-> {t}")
+                                       else
+                                               error(node, "Error: circularity of virtual type definition: {mtype} -> {next} <-> {t}")
+                                       end
+                                       return false
+                               else
+                                       poset.add_edge(t, next)
+                                       todo.add next
+                               end
+                       end
+               end
+               return true
+       end
 end
 
 redef class MPropDef
@@ -597,7 +685,7 @@ redef class ASignature
                        param_names.add(np.n_id.text)
                        var ntype = np.n_type
                        if ntype != null then
-                               var mtype = modelbuilder.resolve_mtype(mmodule, mclassdef, ntype)
+                               var mtype = modelbuilder.resolve_mtype_unchecked(mmodule, mclassdef, ntype, true)
                                if mtype == null then return false # Skip error
                                for i in [0..param_names.length-param_types.length[ do
                                        param_types.add(mtype)
@@ -614,7 +702,7 @@ redef class ASignature
                end
                var ntype = self.n_type
                if ntype != null then
-                       self.ret_type = modelbuilder.resolve_mtype(mmodule, mclassdef, ntype)
+                       self.ret_type = modelbuilder.resolve_mtype_unchecked(mmodule, mclassdef, ntype, true)
                        if self.ret_type == null then return false # Skip error
                end
 
@@ -622,24 +710,24 @@ redef class ASignature
                return true
        end
 
-       # Build a visited signature
-       fun build_signature(modelbuilder: ModelBuilder): nullable MSignature
+       private fun check_signature(modelbuilder: ModelBuilder, mclassdef: MClassDef): Bool
        do
-               if param_names.length != param_types.length then
-                       # Some parameters are typed, other parameters are not typed.
-                       modelbuilder.error(self.n_params[param_types.length], "Error: Untyped parameter `{param_names[param_types.length]}'.")
-                       return null
+               var res = true
+               for np in self.n_params do
+                       var ntype = np.n_type
+                       if ntype != null then
+                               if modelbuilder.resolve_mtype(mclassdef.mmodule, mclassdef, ntype) == null then
+                                       res = false
+                               end
+                       end
                end
-
-               var mparameters = new Array[MParameter]
-               for i in [0..param_names.length[ do
-                       var mparameter = new MParameter(param_names[i], param_types[i], i == vararg_rank)
-                       self.n_params[i].mparameter = mparameter
-                       mparameters.add(mparameter)
+               var ntype = self.n_type
+               if ntype != null then
+                       if modelbuilder.resolve_mtype(mclassdef.mmodule, mclassdef, ntype) == null then
+                               res = false
+                       end
                end
-
-               var msignature = new MSignature(mparameters, ret_type)
-               return msignature
+               return res
        end
 end
 
@@ -735,6 +823,7 @@ redef class AMethPropdef
                        end
                        mprop.is_init = is_init
                        mprop.is_new = n_kwnew != null
+                       if mprop.is_new then mclassdef.mclass.has_new_factory = true
                        if parent isa ATopClassdef then mprop.is_toplevel = true
                        self.check_redef_keyword(modelbuilder, mclassdef, n_kwredef, false, mprop)
                else
@@ -879,6 +968,14 @@ redef class AMethPropdef
                var mysignature = self.mpropdef.msignature
                if mysignature == null then return # Error thus skiped
 
+               # Check
+               if nsig != null then
+                       if not nsig.check_signature(modelbuilder, mclassdef) then
+                               self.mpropdef.msignature = null # invalidate
+                               return # Forward error
+                       end
+               end
+
                # Lookup for signature in the precursor
                # FIXME all precursors should be considered
                if not mpropdef.is_intro then
@@ -889,6 +986,7 @@ redef class AMethPropdef
                        var ret_type = mysignature.return_mtype
                        if ret_type != null and precursor_ret_type == null then
                                modelbuilder.error(nsig.n_type.as(not null), "Redef Error: {mpropdef.mproperty} is a procedure, not a function.")
+                               self.mpropdef.msignature = null
                                return
                        end
 
@@ -900,6 +998,7 @@ redef class AMethPropdef
                                        var node = nsig.n_params[i]
                                        if not modelbuilder.check_sametype(node, mmodule, mclassdef.bound_mtype, myt, prt) then
                                                modelbuilder.error(node, "Redef Error: Wrong type for parameter `{mysignature.mparameters[i].name}'. found {myt}, expected {prt} as in {mpropdef.mproperty.intro}.")
+                                               self.mpropdef.msignature = null
                                        end
                                end
                        end
@@ -912,6 +1011,7 @@ redef class AMethPropdef
                                        ret_type = precursor_ret_type
                                else if not modelbuilder.check_subtype(node, mmodule, mclassdef.bound_mtype, ret_type, precursor_ret_type) then
                                        modelbuilder.error(node, "Redef Error: Wrong return type. found {ret_type}, expected {precursor_ret_type} as in {mpropdef.mproperty.intro}.")
+                                       self.mpropdef.msignature = null
                                end
                        end
                end
@@ -1027,6 +1127,7 @@ redef class AAttrPropdef
                                else if atautoinit != null then
                                        modelbuilder.error(atautoinit, "Error: a autoinit attribute needs a value")
                                end
+                               has_value = true
                                return
                        end
                        is_lazy = true
@@ -1091,7 +1192,7 @@ redef class AAttrPropdef
 
                var ntype = self.n_type
                if ntype != null then
-                       mtype = modelbuilder.resolve_mtype(mmodule, mclassdef, ntype)
+                       mtype = modelbuilder.resolve_mtype_unchecked(mmodule, mclassdef, ntype, true)
                        if mtype == null then return
                end
 
@@ -1112,7 +1213,7 @@ redef class AAttrPropdef
                if mtype == null then
                        if nexpr != null then
                                if nexpr isa ANewExpr then
-                                       mtype = modelbuilder.resolve_mtype(mmodule, mclassdef, nexpr.n_type)
+                                       mtype = modelbuilder.resolve_mtype_unchecked(mmodule, mclassdef, nexpr.n_type, true)
                                else if nexpr isa AIntExpr then
                                        var cla = modelbuilder.try_get_mclass_by_name(nexpr, mmodule, "Int")
                                        if cla != null then mtype = cla.mclass_type
@@ -1139,7 +1240,7 @@ redef class AAttrPropdef
                        end
                else if ntype != null and inherited_type == mtype then
                        if nexpr isa ANewExpr then
-                               var xmtype = modelbuilder.resolve_mtype(mmodule, mclassdef, nexpr.n_type)
+                               var xmtype = modelbuilder.resolve_mtype_unchecked(mmodule, mclassdef, nexpr.n_type, true)
                                if xmtype == mtype then
                                        modelbuilder.advice(ntype, "useless-type", "Warning: useless type definition")
                                end
@@ -1183,6 +1284,18 @@ redef class AAttrPropdef
                var mtype = self.mpropdef.static_mtype
                if mtype == null then return # Error thus skipped
 
+               var mclassdef = mpropdef.mclassdef
+               var mmodule = mclassdef.mmodule
+
+               # Check types
+               if ntype != null then
+                       if modelbuilder.resolve_mtype(mmodule, mclassdef, ntype) == null then return
+               end
+               var nexpr = n_expr
+               if nexpr isa ANewExpr then
+                       if modelbuilder.resolve_mtype(mmodule, mclassdef, nexpr.n_type) == null then return
+               end
+
                # Lookup for signature in the precursor
                # FIXME all precursors should be considered
                if not mpropdef.is_intro then
@@ -1314,7 +1427,7 @@ redef class ATypePropdef
                var mtype: nullable MType = null
 
                var ntype = self.n_type
-               mtype = modelbuilder.resolve_mtype(mmodule, mclassdef, ntype)
+               mtype = modelbuilder.resolve_mtype_unchecked(mmodule, mclassdef, ntype, true)
                if mtype == null then return
 
                mpropdef.bound = mtype
@@ -1326,7 +1439,7 @@ redef class ATypePropdef
                var mpropdef = self.mpropdef
                if mpropdef == null then return # Error thus skipped
 
-               var bound = self.mpropdef.bound
+               var bound = mpropdef.bound
                if bound == null then return # Error thus skipped
 
                modelbuilder.check_visibility(n_type, bound, mpropdef)
@@ -1335,25 +1448,13 @@ redef class ATypePropdef
                var mmodule = mclassdef.mmodule
                var anchor = mclassdef.bound_mtype
 
-               # Check circularity
-               if bound isa MVirtualType then
-                       # Slow case: progress on each resolution until: (i) we loop, or (ii) we found a non formal type
-                       var seen = [self.mpropdef.mproperty.mvirtualtype]
-                       loop
-                               if seen.has(bound) then
-                                       seen.add(bound)
-                                       modelbuilder.error(self, "Error: circularity of virtual type definition: {seen.join(" -> ")}")
-                                       return
-                               end
-                               seen.add(bound)
-                               var next = bound.lookup_bound(mmodule, anchor)
-                               if not next isa MVirtualType then break
-                               bound = next
-                       end
+               var ntype = self.n_type
+               if modelbuilder.resolve_mtype(mmodule, mclassdef, ntype) == null then
+                       mpropdef.bound = null
+                       return
                end
 
                # Check redefinitions
-               bound = mpropdef.bound.as(not null)
                for p in mpropdef.mproperty.lookup_super_definitions(mmodule, anchor) do
                        var supbound = p.bound
                        if supbound == null then break # broken super bound, skip error
index 349f53c..b12e1e9 100644 (file)
@@ -81,7 +81,7 @@ else
 end
 
 print "[HOST ADDRESS] : {debug.address}"
-print "[HOST] : {debug.host or else "unamed"}"
+print "[HOST] : {debug.host}"
 print "[PORT] : {debug.port}"
 print "Connecting ... {debug.connected}"
 
index f53466c..210a4b5 100644 (file)
@@ -111,7 +111,7 @@ redef class AMethPropdef
                # return type
                var rmt = mpropdef.msignature.return_mtype
                if rmt != null then
-                       if rmt isa MParameterType or rmt isa MVirtualType then
+                       if rmt isa MFormalType then
                                var mclass_type = mpropdef.mclassdef.bound_mtype
                                rmt = rmt.anchor_to(mmodule, mclass_type)
                        end
@@ -122,7 +122,7 @@ redef class AMethPropdef
                # params
                for p in mpropdef.msignature.mparameters do
                        var mtype = p.mtype.resolve_for(recv_type, recv_type, mmodule, true)
-                       if mtype isa MParameterType or mtype isa MVirtualType then
+                       if mtype isa MFormalType then
                                var mclass_type = mpropdef.mclassdef.bound_mtype
                                mtype = mtype.anchor_to(mmodule, mclass_type)
                        end
@@ -308,7 +308,7 @@ redef class AFullPropExternCall
 
                if mtype == null then return
 
-               if mtype isa MParameterType or mtype isa MVirtualType then
+               if mtype isa MFormalType then
                        mtype = mtype.anchor_to(mmodule, mclass_type)
                end
 
@@ -422,7 +422,7 @@ redef class AAsNotNullableExternCall
        redef fun from_mtype do return n_type.mtype.as_nullable
        redef fun to_mtype do
                var mtype = n_type.mtype.as(not null)
-               mtype = mtype.as_notnullable
+               mtype = mtype.undecorate
                return mtype
        end
 
diff --git a/src/parser/.gitignore b/src/parser/.gitignore
new file mode 100644 (file)
index 0000000..50e6ab8
--- /dev/null
@@ -0,0 +1,5 @@
+*.class
+org/nitlanguage/gen/analysis/
+org/nitlanguage/gen/lexer/
+org/nitlanguage/gen/node/
+org/nitlanguage/gen/parser/
index db69b26..04657cc 100644 (file)
@@ -38,3 +38,8 @@ maintainer-clean: clean
        @echo "This command is intended for maintainers to use;"
        @echo "it deletes files that may require special tools to rebuild."
        rm -f -- parser.nit parser_abs.nit parser_prod.nit lexer.nit || true
+
+java: .nit.sablecc3
+       rm -r org/nitlanguage/gen/analysis/ org/nitlanguage/gen/lexer/ org/nitlanguage/gen/node/ org/nitlanguage/gen/parser/
+       ${SABLECC3ALTGEN} .nit.sablecc3 -c .nit.sablecc3.dump
+       javac org/nitlanguage/gen/TestParser.java
index 29b46bc..64ceecf 100644 (file)
@@ -27,7 +27,7 @@ In order to simplify the development of the Nit tools, files produced by the par
 * parser_nodes.nit: token and nodes classes hierarchy used by the parser and the lexer
 * tables.nit, tables_nit.h: Interfaces to access the tables needed by the parser and the lexer
 * xss/*.xss: alternate SableCC3 template files for the Nit language
-
+* org/nitlanguage/gen: A Nit parser in Java, used for tests. use the `make java` rule to build it.
 
 The following are generated but present to avoid the need of sablecc3:
 
diff --git a/src/parser/org/nitlanguage/gen/TestParser.java b/src/parser/org/nitlanguage/gen/TestParser.java
new file mode 100644 (file)
index 0000000..06ec83f
--- /dev/null
@@ -0,0 +1,56 @@
+/* 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.
+ */
+
+package org.nitlanguage.gen;
+
+import java.io.*;
+import java.nio.file.*;
+
+import org.nitlanguage.gen.lexer.*;
+import org.nitlanguage.gen.parser.*;
+import org.nitlanguage.gen.analysis.*;
+import org.nitlanguage.gen.node.*;
+
+public class TestParser extends DepthFirstAdapter {
+       public static void main(String[] args) throws Exception {
+               if (args.length == 0) {
+                       BufferedReader ir = new BufferedReader(new InputStreamReader(System.in));
+                       work(ir);
+               } else {
+                       for(int i=0; i<args.length; i++) {
+                               //System.out.println(args[i]);
+
+                               //Here we use "ISO-8859-1" because we want to opaquely treat Bytes as characters.
+                               //Unfortunately "US-ASCII" does not seems to do the job for values>127.
+                               BufferedReader ir = new BufferedReader(new InputStreamReader(new FileInputStream(args[i]), "ISO-8859-1"));
+
+                               work(ir);
+                       }
+               }
+       }
+
+       public static void work(BufferedReader ir) {
+               TestParser testParser = new TestParser();
+               try {
+                       PushbackReader r = new PushbackReader(ir, 1024);
+                       Parser parser = new Parser(new Lexer(r));
+                       Node syntaxTree = parser.parse();
+                       syntaxTree.apply(testParser);
+               } catch (LexerException e) {
+                       System.out.println(e.getMessage() + ".");
+               } catch (ParserException e) {
+                       System.out.println(e.getMessage() + ".");
+               } catch (IOException e) {
+                       System.out.println(e.getMessage() + ".");
+                       System.exit(1);
+               }
+       }
+}
index bdec532..502d817 100644 (file)
@@ -147,7 +147,7 @@ redef class ToolContext
                var time1 = get_time
                self.info("*** END SEMANTIC ANALYSIS: {time1-time0} ***", 2)
 
-               errors_info
+               self.check_errors
        end
 
        # Process the given `phase` on the `npropdef`
index e2db002..404d780 100644 (file)
@@ -42,7 +42,7 @@ class AndroidPlatform
 
        redef fun supports_linker_script do return false
 
-       redef fun toolchain(toolcontext) do return new AndroidToolchain(toolcontext)
+       redef fun toolchain(toolcontext, compiler) do return new AndroidToolchain(toolcontext, compiler)
 end
 
 class AndroidToolchain
@@ -57,25 +57,23 @@ class AndroidToolchain
                return "{android_project_root}/jni/nit_compile/"
        end
 
-       redef fun default_outname(mainmodule) do return "{mainmodule.name}.apk"
+       redef fun default_outname do return "{super}.apk"
 
-       redef fun write_files(compiler, compile_dir, cfiles)
+       redef fun write_files(compile_dir, cfiles)
        do
                var android_project_root = android_project_root.as(not null)
-               var project = toolcontext.modelbuilder.android_project_for(compiler.mainmodule)
-               var short_project_name = compiler.mainmodule.name.replace("-", "_")
+               var project = new AndroidProject(toolcontext.modelbuilder, compiler.mainmodule)
                var release = toolcontext.opt_release.value
 
                var app_name = project.name
-               if app_name == null then app_name = compiler.mainmodule.name
                if not release then app_name += " Debug"
 
-               var app_package = project.java_package
-               if app_package == null then app_package = "org.nitlanguage.{short_project_name}"
+               var short_project_name = project.short_name
+
+               var app_package = project.namespace
                if not release then app_package += "_debug"
 
                var app_version = project.version
-               if app_version == null then app_version = "1.0"
 
                var app_min_api = project.min_api
                if app_min_api == null then app_min_api = 10
@@ -107,7 +105,7 @@ class AndroidToolchain
                if not dir.file_exists then dir.mkdir
 
                # compile normal C files
-               super(compiler, compile_dir, cfiles)
+               super
 
                # Gather extra C files generated elsewhere than in super
                for f in compiler.extern_bodies do
@@ -311,12 +309,12 @@ $(call import-module,android/native_app_glue)
                end
        end
 
-       redef fun write_makefile(compiler, compile_dir, cfiles)
+       redef fun write_makefile(compile_dir, cfiles)
        do
                # Do nothing, already done in `write_files`
        end
 
-       redef fun compile_c_code(compiler, compile_dir)
+       redef fun compile_c_code(compile_dir)
        do
                var android_project_root = android_project_root.as(not null)
                var short_project_name = compiler.mainmodule.name.replace("-", "_")
index 717c6ae..347c4dc 100644 (file)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# Annotations to gather metadata on Android projects. Get the metadata
-# by calling `ModelBuilder::android_project_for`.
+# Additionnal annotations to gather metadata on Android projects
 module android_annotations
 
-private import parser_util
-import modelize
-import literal
-import semantize
-private import annotation
+intrude import app_annotations
 
 # Metadata associated to an Android project
 class AndroidProject
-       # Name of the resulting application
-       var name: nullable String = null
-
-       # Java package used to identify the APK
-       var java_package: nullable String = null
-
-       # Version of the Android application and APK
-       var version: nullable String = null
-
-       # Numerical version code of the Android application and APK
-       var version_code: Int = 0
+       super AppProject
 
        # Custom lines to add to the AndroidManifest.xml in the <manifest> node
        var manifest_lines = new Array[String]
@@ -59,134 +44,48 @@ class AndroidProject
        # Activities to declare in the manifest
        var activities = new Array[String]
 
-       redef fun to_s do return """
-name: {{{name or else "null"}}}
-namespace: {{{java_package or else "null"}}}
-version: {{{version or else "null"}}}"""
-end
-
-redef class ModelBuilder
-       # Get the `AndroidProject` gathered from `mmodule` and its importations
-       fun android_project_for(mmodule: MModule): AndroidProject
+       init
        do
-               var project = new AndroidProject
-
-               var annot = lookup_annotation_on_modules("app_name", mmodule)
-               if annot != null then project.name = annot.arg_as_string(self)
-
-               annot =  lookup_annotation_on_modules("app_version", mmodule)
-               if annot != null then project.version =  annot.as_version(self)
-
-               annot = lookup_annotation_on_modules("java_package", mmodule)
-               if annot != null then project.java_package = annot.arg_as_string(self)
-
-               var annots = collect_annotations_on_modules("min_api_version", mmodule)
+               var annots = modelbuilder.collect_annotations_on_modules("min_api_version", mainmodule)
                if not annots.is_empty then
-                       var i = annots.pop.arg_as_int(self)
+                       var i = annots.pop.arg_as_int(modelbuilder)
                        if i == null then i = 0
-                       project.min_api = i
+                       min_api = i
                        for an in annots do
-                               i = an.arg_as_int(self)
+                               i = an.arg_as_int(modelbuilder)
                                if i == null then continue
-                               project.min_api = project.min_api.max(i)
+                               min_api = min_api.max(i)
                        end
                end
 
-               annots = collect_annotations_on_modules("max_api_version", mmodule)
+               annots = modelbuilder.collect_annotations_on_modules("max_api_version", mainmodule)
                if not annots.is_empty then
-                       var i = annots.pop.arg_as_int(self)
+                       var i = annots.pop.arg_as_int(modelbuilder)
                        if i == null then i = 0
-                       project.max_api = i
+                       max_api = i
                        for an in annots do
-                               i = an.arg_as_int(self)
+                               i = an.arg_as_int(modelbuilder)
                                if i == null then continue
-                               project.max_api = project.max_api.min(i)
+                               max_api = max_api.min(i)
                        end
                end
 
-               annot = lookup_annotation_on_modules("target_api_version", mmodule)
-               if annot != null then project.target_api = annot.arg_as_int(self) or else 0
+               var annot = modelbuilder.lookup_annotation_on_modules("target_api_version", mainmodule)
+               if annot != null then target_api = annot.arg_as_int(modelbuilder) or else 0
 
-               annots = collect_annotations_on_modules("android_manifest", mmodule)
-               for an in annots do project.manifest_lines.add an.arg_as_string(self) or else ""
+               annots = modelbuilder.collect_annotations_on_modules("android_manifest", mainmodule)
+               for an in annots do manifest_lines.add an.arg_as_string(modelbuilder) or else ""
 
-               annots = collect_annotations_on_modules("android_manifest_application", mmodule)
-               for an in annots do project.manifest_application_lines.add an.arg_as_string(self) or else ""
+               annots = modelbuilder.collect_annotations_on_modules("android_manifest_application", mainmodule)
+               for an in annots do manifest_application_lines.add an.arg_as_string(modelbuilder) or else ""
 
-               annots = collect_annotations_on_modules("android_manifest_activity", mmodule)
-               for an in annots do project.manifest_activity_attributes.add an.arg_as_string(self) or else ""
+               annots = modelbuilder.collect_annotations_on_modules("android_manifest_activity", mainmodule)
+               for an in annots do manifest_activity_attributes.add an.arg_as_string(modelbuilder) or else ""
 
-               annots = collect_annotations_on_modules("android_activity", mmodule)
+               annots = modelbuilder.collect_annotations_on_modules("android_activity", mainmodule)
                for an in annots do
-                       var activity = an.arg_as_string(self)
-                       if activity != null then project.activities.add activity
+                       var activity = an.arg_as_string(modelbuilder)
+                       if activity != null then activities.add activity
                end
-
-               # Get the date and time (down to the minute) as string
-               var local_time = new Tm.localtime
-               var local_time_s = local_time.strftime("%y%m%d%H%M")
-               project.version_code = local_time_s.to_i
-
-               toolcontext.check_errors
-
-               return project
-       end
-end
-
-redef class AAnnotation
-       # Returns a version string (example: "1.5.6b42a7c") from an annotation `version(1, 5, git_revision)`.
-       #
-       # The user can enter as many fields as needed. The call to `git_revision` will be replaced by the short
-       # 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 version_fields = new Array[Object]
-
-               var args = n_args
-               if args.length < 1 then
-                       modelbuilder.error(self, "Annotation error: \"{name}\" expects at least a single argument.")
-                       return ""
-               else
-                       for arg in args do
-                               var format_error = "Annotation error: \"{name}\" expects its arguments to be of type Int or a call to `git_revision`"
-
-                               var value
-                               value = arg.as_int
-                               if value != null then
-                                       version_fields.add value
-                                       continue
-                               end
-
-                               value = arg.as_string
-                               if value != null then
-                                       version_fields.add value
-                               end
-
-                               value = arg.as_id
-                               if value == "git_revision" then
-                                       # Get Git short revision
-                                       var proc = new ProcessReader("git", "rev-parse", "--short", "HEAD")
-                                       proc.wait
-                                       assert proc.status == 0
-                                       var lines = proc.read_all
-                                       var revision = lines.split("\n").first
-
-                                       # Is it dirty?
-                                       # If not, the return of `git diff --shortstat` is an empty line
-                                       proc = new ProcessReader("git", "diff-index", "--quiet", "HEAD")
-                                       proc.wait
-                                       var dirty = proc.status != 0
-                                       if dirty then revision += ".d"
-
-                                       version_fields.add revision
-                                       continue
-                               end
-
-                               modelbuilder.error(self, format_error)
-                               return ""
-                       end
-               end
-
-               return version_fields.join(".")
        end
 end
diff --git a/src/platform/app_annotations.nit b/src/platform/app_annotations.nit
new file mode 100644 (file)
index 0000000..67af354
--- /dev/null
@@ -0,0 +1,132 @@
+# 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.
+
+# Annotations to gather metadata on `app.nit` projects
+module app_annotations
+
+private import parser_util
+import modelize
+import literal
+import semantize
+private import annotation
+
+# Metadata associated to an `app.nit` project
+class AppProject
+       # Pretty name of the resulting application
+       var name: String = mainmodule.first_real_mmodule.name is lazy
+
+       # Short project name used in `namespace` and configuration files
+       var short_name: String = mainmodule.name.replace("-", "_") is lazy
+
+       # Namespace/package used to identify the application
+       var namespace = "org.nitlanguage.{short_name}" is lazy
+
+       # Version of the application
+       var version = "0.1"
+
+       # Numerical version code of the application
+       var version_code: Int is lazy do
+
+               # Get the date and time (down to the minute) as string
+               var local_time = new Tm.localtime
+               var local_time_s = local_time.strftime("%y%m%d%H%M")
+               return local_time_s.to_i
+       end
+
+       private var modelbuilder: ModelBuilder
+       private var mainmodule: MModule
+
+       init
+       do
+               var annot = modelbuilder.lookup_annotation_on_modules("app_name", mainmodule)
+               if annot != null then
+                       var val = annot.arg_as_string(modelbuilder)
+                       if val != null then name = val
+               end
+
+               annot = modelbuilder.lookup_annotation_on_modules("app_version", mainmodule)
+               if annot != null then version = annot.as_version(modelbuilder)
+
+               annot = modelbuilder.lookup_annotation_on_modules("app_namespace", mainmodule)
+               if annot != null then
+                       var val = annot.arg_as_string(modelbuilder)
+                       if val != null then namespace = val
+               end
+
+               modelbuilder.toolcontext.check_errors
+       end
+
+       redef fun to_s do return """
+name: {{{name}}}
+namespace: {{{namespace}}}
+version: {{{version}}}"""
+end
+
+redef class AAnnotation
+       # Returns a version string (example: "1.5.6b42a7c") from an annotation `version(1, 5, git_revision)`.
+       #
+       # The user can enter as many fields as needed. The call to `git_revision` will be replaced by the short
+       # 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 version_fields = new Array[Object]
+
+               var args = n_args
+               if args.length < 1 then
+                       modelbuilder.error(self, "Annotation error: \"{name}\" expects at least a single argument.")
+                       return ""
+               else
+                       for arg in args do
+                               var format_error = "Annotation error: \"{name}\" expects its arguments to be of type Int or a call to `git_revision`"
+
+                               var value
+                               value = arg.as_int
+                               if value != null then
+                                       version_fields.add value
+                                       continue
+                               end
+
+                               value = arg.as_string
+                               if value != null then
+                                       version_fields.add value
+                               end
+
+                               value = arg.as_id
+                               if value == "git_revision" then
+                                       # Get Git short revision
+                                       var proc = new ProcessReader("git", "rev-parse", "--short", "HEAD")
+                                       proc.wait
+                                       assert proc.status == 0
+                                       var lines = proc.read_all
+                                       var revision = lines.split("\n").first
+
+                                       # Is it dirty?
+                                       # If not, the return of `git diff --shortstat` is an empty line
+                                       proc = new ProcessReader("git", "diff-index", "--quiet", "HEAD")
+                                       proc.wait
+                                       var dirty = proc.status != 0
+                                       if dirty then revision += ".d"
+
+                                       version_fields.add revision
+                                       continue
+                               end
+
+                               modelbuilder.error(self, format_error)
+                               return ""
+                       end
+               end
+
+               return version_fields.join(".")
+       end
+end
index 3e9199a..90e361e 100644 (file)
@@ -35,17 +35,17 @@ class EmscriptenPlatform
        redef fun supports_libunwind do return false
        redef fun supports_libgc do return false
        redef fun supports_linker_script do return false
-       redef fun toolchain(toolcontext) do return new EnscriptenToolchain(toolcontext)
+       redef fun toolchain(toolcontext, compiler) do return new EnscriptenToolchain(toolcontext, compiler)
 end
 
 class EnscriptenToolchain
        super MakefileToolchain
 
-       redef fun makefile_name(mainmodule) do return "{mainmodule.name}.js.mk"
+       redef fun makefile_name do return "{super}.js.mk"
 
-       redef fun default_outname(mainmodule) do return "{super}.js"
+       redef fun default_outname do return "{super}.js"
 
-       redef fun write_makefile(compiler, compile_dir, cfiles)
+       redef fun write_makefile(compile_dir, cfiles)
        do
                super
 
diff --git a/src/platform/ios.nit b/src/platform/ios.nit
new file mode 100644 (file)
index 0000000..f81b5d2
--- /dev/null
@@ -0,0 +1,115 @@
+# 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.
+
+# Compile programs for the iOS platform
+module ios
+
+import platform
+import compiler::abstract_compiler
+import xcode_templates
+import app_annotations
+
+redef class ToolContext
+       redef fun platform_from_name(name)
+       do
+               if name == "ios" then return new IOSPlatform
+               return super
+       end
+end
+
+private class IOSPlatform
+       super Platform
+
+       redef fun supports_libunwind do return false
+       redef fun supports_libgc do return false
+       redef fun toolchain(toolcontext, compiler) do return new IOSToolchain(toolcontext, compiler)
+end
+
+private class IOSToolchain
+       super MakefileToolchain
+
+       # Root of the iOS project, usually `.nit_compile/ios/`
+       var ios_project_root: String is noinit
+
+       # `app.nit` project for the current compilation target
+       var app_project = new AppProject(compiler.modelbuilder, compiler.mainmodule) is lazy
+
+       redef fun default_outname do return "{super}.app"
+
+       # Compile C files in `ios_project_root/app_project.name`
+       redef fun compile_dir
+       do
+               ios_project_root = super/"ios"
+               return ios_project_root/app_project.short_name
+       end
+
+       redef fun write_files(compile_dir, cfiles)
+       do
+               # Clear the project directory before writing anything
+               if ios_project_root.file_exists then ios_project_root.rmdir
+               compile_dir.mkdir
+
+               super
+       end
+
+       redef fun write_makefile(compile_dir, cfiles)
+       do
+               var project_name = app_project.short_name
+
+               # Create an XCode project directory
+               var dir = ios_project_root/project_name+".xcodeproj"
+               if not dir.file_exists then dir.mkdir
+
+               # Create a PBX project file
+               var pbx = new PbxprojectTemplate(project_name)
+
+               ## Register all source files
+               for file in cfiles do pbx.add_file new PbxFile(file)
+               for file in compiler.extern_bodies do
+                       pbx.add_file new PbxFile(file.filename.basename(""))
+               end
+
+               ## TODO Register asset files
+
+               pbx.write_to_file dir/"project.pbxproj"
+
+               # Create the plist in the same directory as the generated C code
+               if not compile_dir.file_exists then compile_dir.mkdir
+               var plist = new PlistTemplate(app_project.name, app_project.namespace,
+                       app_project.version, app_project.version_code.to_s)
+               plist.write_to_file compile_dir/"Info.plist"
+       end
+
+       redef fun compile_c_code(compile_dir)
+       do
+               var project_name = app_project.short_name
+               var release = toolcontext.opt_release.value
+               var outfile = outfile(compiler.mainmodule)
+
+               # Compile with `xcodebuild`
+               #
+               # TODO support more than the iPhone and the simulator.
+               var args = ["sh", "-c", "cd {ios_project_root}; " +
+                       "xcodebuild -target '{project_name}' " +
+                       "-destination 'platform=iOS Simulator,name=iPhone' " +
+                       "-configuration {if release then "Release" else "Debug"} " +
+                       "-sdk iphonesimulator build"]
+               toolcontext.exec_and_check(args, "iOS project error")
+
+               # Move compiled app to destination
+               if outfile.file_exists then outfile.rmdir
+               args = ["mv", "{ios_project_root}/build/Debug-iphonesimulator/{project_name}.app", outfile]
+               toolcontext.exec_and_check(args, "iOS project error")
+       end
+end
index d7103db..8136187 100644 (file)
@@ -37,13 +37,13 @@ class PnaclPlatform
 
        redef fun no_main do return true
 
-       redef fun toolchain(toolcontext) do return new PnaclToolchain(toolcontext)
+       redef fun toolchain(toolcontext, compiler) do return new PnaclToolchain(toolcontext, compiler)
 end
 
 class PnaclToolchain
        super MakefileToolchain
 
-       redef fun write_files(compiler, compile_dir, cfiles)
+       redef fun write_files(compile_dir, cfiles)
        do
                var app_name = compiler.mainmodule.name
 
@@ -52,7 +52,7 @@ class PnaclToolchain
                if not dir.file_exists then dir.mkdir
 
                # compile normal C files
-               super(compiler, compile_dir, cfiles)
+               super
 
                # Gather extra C files generated elsewhere than in super
                for f in compiler.extern_bodies do
@@ -238,12 +238,12 @@ function updateStatus(opt_message) {
                """.write_to_file(file)
        end
 
-       redef fun write_makefile(compiler, compile_dir, cfiles)
+       redef fun write_makefile(compile_dir, cfiles)
        do
                # Do nothing, already done in `write_files`
        end
 
-       redef fun compile_c_code(compiler, compile_dir)
+       redef fun compile_c_code(compile_dir)
        do
                # Generate the pexe
                toolcontext.exec_and_check(["make", "-C", compile_dir, "-j", "4"], "PNaCl project error")
diff --git a/src/platform/xcode_templates.nit b/src/platform/xcode_templates.nit
new file mode 100644 (file)
index 0000000..e4ebbdf
--- /dev/null
@@ -0,0 +1,690 @@
+# 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.
+
+# Templates and other services to create XCode projects
+module xcode_templates
+
+import template
+
+import platform
+import compiler::abstract_compiler
+
+redef class Sys
+       # Map to identify the PBX file type for a given file extension
+       private var pbx_file_types: Map[String, String] is lazy do
+               var map = new HashMap[String, String]
+
+               # Source code
+               map["m"] =                      "sourcecode.c.objc"
+               map["c"] =                      "sourcecode.c.c"
+               map["h"] =                      "sourcecode.c.h"
+               map["cpp"] =            "sourcecode.cpp.cpp"
+               map["hpp"] =            "sourcecode.cpp.h"
+               map["vsh"] =            "sourcecode.glsl"
+               map["fsh"] =            "sourcecode.glsl"
+
+               # Images
+               map["png"] =            "image.png"
+               map["gif"] =            "image.gif"
+               map["jpg"] =            "image.jpeg"
+               map["jpeg"] =           "image.jpeg"
+               map["pdf"] =            "image.pdf"
+               map["ico"] =            "image.ico"
+
+               # Others
+               map["app"] =            "wrapper.application"
+               map["plist"] =          "text.plist.xml"
+               map["storyboard"] =     "file.storyboard"
+               map["xib"] =            "file.xib"
+               map["xcassets"] =       "folder.assetcatalog"
+               map["xctest"] =         "wrapper.cfbundle"
+
+               return map
+       end
+
+       # Generator of PBX UUIDs quique to an execution of the compiler
+       private var pbx_uuid_generator = new PbxUUIDGenerator is lazy
+end
+
+# Generator of PBX UUIDs
+#
+# PBX UUID are composed of 24 hex characters.
+# They only need to be unique within the same project.
+#
+# This implementation simply counts upward from 0.
+class PbxUUIDGenerator
+       private var seed = 0
+
+       # Generate a new UUID
+       fun next_uuid: String
+       do
+               seed += 1
+
+               var hex_val = seed.to_hex.to_upper
+               return "0"*(24-hex_val.length) + hex_val
+       end
+end
+
+# Reference to a file for the PBX format of a project file
+#
+# TODO create subclasses for different file types, this is currently for
+# compilable source files only.
+class PbxFile
+
+       # Path to `self`
+       var path: String
+
+       # UUID for build elements
+       private var build_uuid: String = sys.pbx_uuid_generator.next_uuid is lazy
+
+       # File reference UUID
+       private var ref_uuid: String = sys.pbx_uuid_generator.next_uuid is lazy
+
+       # Documentation to add besides this file in the template
+       private fun doc: String do return path
+
+       # PBX file type for `self`
+       fun file_type: String
+       do
+               var map = sys.pbx_file_types
+               var ext = path.file_extension
+               if ext != null and map.keys.has(ext) then return map[ext]
+               return "unknown"
+       end
+
+       # PBX description of this file
+       private fun description: Writable do return """
+               {{{ref_uuid}}} /* {{{doc}}} */ = {
+                       isa = PBXFileReference;
+                       fileEncoding = 4;
+                       lastKnownFileType = {{{file_type}}};
+                       path = {{{path}}};
+                       sourceTree = "<group>";
+                       };
+"""
+
+       private fun add_to_project(project: PbxprojectTemplate)
+       do
+               project.source_files.add self
+               project.files.add self
+       end
+end
+
+# Template for a PBX project file, usually a `project.pbcproj`
+#
+# This file list all information required to build an XCode project.
+# It would usually be written and read by XCode.
+# From the command line, xcodebuild can read this file but not write it.
+#
+# Information in the file (simplified list):
+#
+# * Compilable source files
+# * Asset files
+# * Build configurations (Release and debug modes, cflags, etc.)
+# * List of files composing the project
+class PbxprojectTemplate
+       super Template
+
+       # Name of the project
+       var name: String
+
+       # All body/implementation source files to be compiled
+       private var source_files = new Array[PbxFile]
+
+       # All asset files added to the app package
+       private var asset_files = new Array[PbxFile]
+
+       # All files used by this project
+       private var files = new Array[PbxFile]
+
+       # Add `file` to this project
+       fun add_file(file: PbxFile) do file.add_to_project(self)
+
+       redef fun rendering
+       do
+               add """
+// !$*UTF8*$!
+{
+       archiveVersion = 1;
+       classes = {
+       };
+       objectVersion = 46;
+       objects = {
+
+/* Begin PBXBuildFile section */
+"""
+
+               # List build files (compilable sources and assets) with their reference UUID
+               for array in [source_files, asset_files] do for file in array do add """
+               {{{file.build_uuid}}} /* {{{file.doc}}} */ = {
+                       isa = PBXBuildFile;
+                       fileRef = {{{file.ref_uuid}}} /* {{{file.doc}}} */;
+                       };
+"""
+
+               add """
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+               AF9F83EA1A5F0D21004B62C0 /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = AF9F83C41A5F0D21004B62C0 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = AF9F83CB1A5F0D21004B62C0;
+                       remoteInfo = {{{name}}};
+               };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXFileReference section */
+       /* Static generated files */
+               AF9F83CC1A5F0D21004B62C0 /* {{{name}}}.app */ = {
+                       isa = PBXFileReference;
+                       explicitFileType = wrapper.application;
+                       includeInIndex = 0;
+                       path = {{{name}}}.app;
+                       sourceTree = BUILT_PRODUCTS_DIR;
+                       };
+               AF9F83D01A5F0D21004B62C0 /* Info.plist */ = {
+                       isa = PBXFileReference;
+                       lastKnownFileType = text.plist.xml;
+                       path = Info.plist;
+                       sourceTree = "<group>";
+                       };
+               AF9F83DE1A5F0D21004B62C0 /* Base */ = {
+                       isa = PBXFileReference;
+                       lastKnownFileType = file.storyboard;
+                       name = Base;
+                       path = Base.lproj/Main.storyboard;
+                       sourceTree = "<group>";
+                       };
+               AF9F83E01A5F0D21004B62C0 /* Images.xcassets */ = {
+                       isa = PBXFileReference;
+                       lastKnownFileType = folder.assetcatalog;
+                       path = Images.xcassets;
+                       sourceTree = "<group>";
+                       };
+               AF9F83E31A5F0D21004B62C0 /* Base */ = {
+                       isa = PBXFileReference;
+                       lastKnownFileType = file.xib;
+                       name = Base;
+                       path = Base.lproj/LaunchScreen.xib;
+                       sourceTree = "<group>";
+                       };
+               AF9F83E91A5F0D21004B62C0 /* {{{name}}}Tests.xctest */ = {
+                       isa = PBXFileReference;
+                       explicitFileType = wrapper.cfbundle;
+                       includeInIndex = 0;
+                       path = {{{name}}}Tests.xctest;
+                       sourceTree = BUILT_PRODUCTS_DIR;
+                       };
+               AF9F83EE1A5F0D21004B62C0 /* Info.plist */ = {
+                       isa = PBXFileReference;
+                       lastKnownFileType = text.plist.xml;
+                       path = Info.plist;
+                       sourceTree = "<group>";
+                       };
+               AF9F83EF1A5F0D21004B62C0 /* {{{name}}}Tests.m */ = {
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = {{{name}}}Tests.m;
+                       sourceTree = "<group>";
+                       };
+
+       /* Changing generated files */
+"""
+               # Describe all known files
+               for file in files do add file.description
+
+               add """
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+               AF9F83C91A5F0D21004B62C0 /* Frameworks */ = {
+                       isa = PBXFrameworksBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               AF9F83E61A5F0D21004B62C0 /* Frameworks */ = {
+                       isa = PBXFrameworksBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+               AF9F83C31A5F0D21004B62C0 = {
+                       isa = PBXGroup;
+                       children = (
+                               AF9F83CE1A5F0D21004B62C0 /* {{{name}}} */,
+                               AF9F83EC1A5F0D21004B62C0 /* {{{name}}}Tests */,
+                               AF9F83CD1A5F0D21004B62C0 /* Products */,
+                       );
+                       sourceTree = "<group>";
+               };
+               AF9F83CD1A5F0D21004B62C0 /* Products */ = {
+                       isa = PBXGroup;
+                       children = (
+                               AF9F83CC1A5F0D21004B62C0 /* {{{name}}}.app */,
+                               AF9F83E91A5F0D21004B62C0 /* {{{name}}}Tests.xctest */,
+                       );
+                       name = Products;
+                       sourceTree = "<group>";
+               };
+               AF9F83CE1A5F0D21004B62C0 /* {{{name}}} */ = {
+                       isa = PBXGroup;
+                       children = (
+"""
+                       # Reference all known files
+                       for file in files do add """
+                               {{{file.ref_uuid}}} /* {{{file.doc}}} */,
+"""
+
+               add """
+                       );
+                       path = {{{name}}};
+                       sourceTree = "<group>";
+               };
+               AF9F83CF1A5F0D21004B62C0 /* Supporting Files */ = {
+                       isa = PBXGroup;
+                       children = (
+                               AF9F83D01A5F0D21004B62C0 /* Info.plist */,
+                               AF9F83D11A5F0D21004B62C0 /* main.m */,
+                       );
+                       name = "Supporting Files";
+                       sourceTree = "<group>";
+               };
+               AF9F83EC1A5F0D21004B62C0 /* {{{name}}}Tests */ = {
+                       isa = PBXGroup;
+                       children = (
+                               AF9F83EF1A5F0D21004B62C0 /* {{{name}}}Tests.m */,
+                               AF9F83ED1A5F0D21004B62C0 /* Supporting Files */,
+                       );
+                       path = {{{name}}}Tests;
+                       sourceTree = "<group>";
+               };
+               AF9F83ED1A5F0D21004B62C0 /* Supporting Files */ = {
+                       isa = PBXGroup;
+                       children = (
+                               AF9F83EE1A5F0D21004B62C0 /* Info.plist */,
+                       );
+                       name = "Supporting Files";
+                       sourceTree = "<group>";
+               };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+               AF9F83CB1A5F0D21004B62C0 /* {{{name}}} */ = {
+                       isa = PBXNativeTarget;
+                       buildConfigurationList = AF9F83F31A5F0D21004B62C0 /* Build configuration list for PBXNativeTarget "{{{name}}}" */;
+                       buildPhases = (
+                               AF9F83C81A5F0D21004B62C0 /* Sources */,
+                               AF9F83C91A5F0D21004B62C0 /* Frameworks */,
+                               AF9F83CA1A5F0D21004B62C0 /* Resources */,
+                       );
+                       buildRules = (
+                       );
+                       dependencies = (
+                       );
+                       name = {{{name}}};
+                       productName = {{{name}}};
+                       productReference = AF9F83CC1A5F0D21004B62C0 /* {{{name}}}.app */;
+                       productType = "com.apple.product-type.application";
+               };
+               AF9F83E81A5F0D21004B62C0 /* {{{name}}}Tests */ = {
+                       isa = PBXNativeTarget;
+                       buildConfigurationList = AF9F83F61A5F0D21004B62C0 /* Build configuration list for PBXNativeTarget "{{{name}}}Tests" */;
+                       buildPhases = (
+                               AF9F83E51A5F0D21004B62C0 /* Sources */,
+                               AF9F83E61A5F0D21004B62C0 /* Frameworks */,
+                               AF9F83E71A5F0D21004B62C0 /* Resources */,
+                       );
+                       buildRules = (
+                       );
+                       dependencies = (
+                               AF9F83EB1A5F0D21004B62C0 /* PBXTargetDependency */,
+                       );
+                       name = {{{name}}}Tests;
+                       productName = {{{name}}}Tests;
+                       productReference = AF9F83E91A5F0D21004B62C0 /* {{{name}}}Tests.xctest */;
+                       productType = "com.apple.product-type.bundle.unit-test";
+               };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+               AF9F83C41A5F0D21004B62C0 /* Project object */ = {
+                       isa = PBXProject;
+                       attributes = {
+                               LastUpgradeCheck = 0610;
+                               TargetAttributes = {
+                                       AF9F83CB1A5F0D21004B62C0 = {
+                                               CreatedOnToolsVersion = 6.1.1;
+                                       };
+                                       AF9F83E81A5F0D21004B62C0 = {
+                                               CreatedOnToolsVersion = 6.1.1;
+                                               TestTargetID = AF9F83CB1A5F0D21004B62C0;
+                                       };
+                               };
+                       };
+                       buildConfigurationList = AF9F83C71A5F0D21004B62C0 /* Build configuration list for PBXProject "{{{name}}}" */;
+                       compatibilityVersion = "Xcode 3.2";
+                       developmentRegion = English;
+                       hasScannedForEncodings = 0;
+                       knownRegions = (
+                               en,
+                               Base,
+                       );
+                       mainGroup = AF9F83C31A5F0D21004B62C0;
+                       productRefGroup = AF9F83CD1A5F0D21004B62C0 /* Products */;
+                       projectDirPath = "";
+                       projectRoot = "";
+                       targets = (
+                               AF9F83CB1A5F0D21004B62C0 /* {{{name}}} */,
+                               AF9F83E81A5F0D21004B62C0 /* {{{name}}}Tests */,
+                       );
+               };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+               AF9F83CA1A5F0D21004B62C0 /* Resources */ = {
+                       isa = PBXResourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+"""
+               # Reference all asset files by their build UUID
+               for file in asset_files do add """
+                               {{{file.build_uuid}}} /* {{{file.doc}}} */,
+"""
+
+               add """
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               AF9F83E71A5F0D21004B62C0 /* Resources */ = {
+                       isa = PBXResourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+               AF9F83C81A5F0D21004B62C0 /* Sources */ = {
+                       isa = PBXSourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+"""
+               # Reference all compilable source files by their build UUID
+               for file in source_files do add """
+                               {{{file.build_uuid}}} /* {{{file.doc}}} */,
+"""
+               add """
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               AF9F83E51A5F0D21004B62C0 /* Sources */ = {
+                       isa = PBXSourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               AF9F83F01A5F0D21004B62C0 /* {{{name}}}Tests.m in Sources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+               AF9F83EB1A5F0D21004B62C0 /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = AF9F83CB1A5F0D21004B62C0 /* {{{name}}} */;
+                       targetProxy = AF9F83EA1A5F0D21004B62C0 /* PBXContainerItemProxy */;
+               };
+/* End PBXTargetDependency section */
+
+/* Begin PBXVariantGroup section */
+               AF9F83DD1A5F0D21004B62C0 /* Main.storyboard */ = {
+                       isa = PBXVariantGroup;
+                       children = (
+                               AF9F83DE1A5F0D21004B62C0 /* Base */,
+                       );
+                       name = Main.storyboard;
+                       sourceTree = "<group>";
+               };
+               AF9F83E21A5F0D21004B62C0 /* LaunchScreen.xib */ = {
+                       isa = PBXVariantGroup;
+                       children = (
+                               AF9F83E31A5F0D21004B62C0 /* Base */,
+                       );
+                       name = LaunchScreen.xib;
+                       sourceTree = "<group>";
+               };
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+               AF9F83F11A5F0D21004B62C0 /* Debug */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               ALWAYS_SEARCH_USER_PATHS = NO;
+                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+                               CLANG_CXX_LIBRARY = "libc++";
+                               CLANG_ENABLE_MODULES = YES;
+                               CLANG_ENABLE_OBJC_ARC = YES;
+                               CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+                               CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+                               "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+                               COPY_PHASE_STRIP = NO;
+                               ENABLE_STRICT_OBJC_MSGSEND = YES;
+                               GCC_C_LANGUAGE_STANDARD = gnu99;
+                               GCC_DYNAMIC_NO_PIC = NO;
+                               GCC_OPTIMIZATION_LEVEL = 0;
+                               GCC_PREPROCESSOR_DEFINITIONS = (
+                                       "DEBUG=1",
+                                       "$(inherited)",
+                               );
+                               GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+                               GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+                               GCC_WARN_UNDECLARED_SELECTOR = YES;
+                               GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+                               IPHONEOS_DEPLOYMENT_TARGET = 8.1;
+                               MTL_ENABLE_DEBUG_INFO = YES;
+                               ONLY_ACTIVE_ARCH = YES;
+                               SDKROOT = iphoneos;
+                               TARGETED_DEVICE_FAMILY = "1,2";
+                       };
+                       name = Debug;
+               };
+               AF9F83F21A5F0D21004B62C0 /* Release */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               ALWAYS_SEARCH_USER_PATHS = NO;
+                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+                               CLANG_CXX_LIBRARY = "libc++";
+                               CLANG_ENABLE_MODULES = YES;
+                               CLANG_ENABLE_OBJC_ARC = YES;
+                               CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+                               CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+                               "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+                               COPY_PHASE_STRIP = YES;
+                               ENABLE_NS_ASSERTIONS = NO;
+                               ENABLE_STRICT_OBJC_MSGSEND = YES;
+                               GCC_C_LANGUAGE_STANDARD = gnu99;
+                               GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+                               GCC_WARN_UNDECLARED_SELECTOR = YES;
+                               GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+                               IPHONEOS_DEPLOYMENT_TARGET = 8.1;
+                               MTL_ENABLE_DEBUG_INFO = NO;
+                               SDKROOT = iphoneos;
+                               TARGETED_DEVICE_FAMILY = "1,2";
+                               VALIDATE_PRODUCT = YES;
+                       };
+                       name = Release;
+               };
+               AF9F83F41A5F0D21004B62C0 /* Debug */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+                               INFOPLIST_FILE = {{{name}}}/Info.plist;
+                               LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+                               PRODUCT_NAME = "$(TARGET_NAME)";
+                       };
+                       name = Debug;
+               };
+               AF9F83F51A5F0D21004B62C0 /* Release */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+                               INFOPLIST_FILE = {{{name}}}/Info.plist;
+                               LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+                               PRODUCT_NAME = "$(TARGET_NAME)";
+                       };
+                       name = Release;
+               };
+               AF9F83F71A5F0D21004B62C0 /* Debug */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               BUNDLE_LOADER = "$(TEST_HOST)";
+                               FRAMEWORK_SEARCH_PATHS = (
+                                       "$(SDKROOT)/Developer/Library/Frameworks",
+                                       "$(inherited)",
+                               );
+                               GCC_PREPROCESSOR_DEFINITIONS = (
+                                       "DEBUG=1",
+                                       "$(inherited)",
+                               );
+                               INFOPLIST_FILE = {{{name}}}Tests/Info.plist;
+                               LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+                               PRODUCT_NAME = "$(TARGET_NAME)";
+                               TEST_HOST = "$(BUILT_PRODUCTS_DIR)/{{{name}}}.app/{{{name}}}";
+                       };
+                       name = Debug;
+               };
+               AF9F83F81A5F0D21004B62C0 /* Release */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               BUNDLE_LOADER = "$(TEST_HOST)";
+                               FRAMEWORK_SEARCH_PATHS = (
+                                       "$(SDKROOT)/Developer/Library/Frameworks",
+                                       "$(inherited)",
+                               );
+                               INFOPLIST_FILE = {{{name}}}Tests/Info.plist;
+                               LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+                               PRODUCT_NAME = "$(TARGET_NAME)";
+                               TEST_HOST = "$(BUILT_PRODUCTS_DIR)/{{{name}}}.app/{{{name}}}";
+                       };
+                       name = Release;
+               };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+               AF9F83C71A5F0D21004B62C0 /* Build configuration list for PBXProject "{{{name}}}" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               AF9F83F11A5F0D21004B62C0 /* Debug */,
+                               AF9F83F21A5F0D21004B62C0 /* Release */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Release;
+               };
+               AF9F83F31A5F0D21004B62C0 /* Build configuration list for PBXNativeTarget "{{{name}}}" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               AF9F83F41A5F0D21004B62C0 /* Debug */,
+                               AF9F83F51A5F0D21004B62C0 /* Release */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+               };
+               AF9F83F61A5F0D21004B62C0 /* Build configuration list for PBXNativeTarget "{{{name}}}Tests" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               AF9F83F71A5F0D21004B62C0 /* Debug */,
+                               AF9F83F81A5F0D21004B62C0 /* Release */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+               };
+/* End XCConfigurationList section */
+       };
+       rootObject = AF9F83C41A5F0D21004B62C0 /* Project object */;
+}
+"""
+       end
+end
+
+# Template for a property list used by XCode for iOS projects
+class PlistTemplate
+       super Template
+
+       # Value of CFBundleName, pretty name of the application
+       var product_name: String
+
+       # Value of CFBundleIdentifier, namespace of the app
+       var bundle_identifier: String
+
+       # Value of CFBundleShortVersionString, human readable version
+       var short_version: String
+
+       # Value of CFBundleVersion, often a revision number
+       var bundle_version: String
+
+       redef fun rendering
+       do
+               add """
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>en</string>
+       <key>CFBundleExecutable</key>
+       <string>$(EXECUTABLE_NAME)</string>
+       <key>CFBundleIdentifier</key>
+       <string>{{{bundle_identifier}}}</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundleName</key>
+       <string>{{{product_name}}}</string>
+       <key>CFBundlePackageType</key>
+       <string>APPL</string>
+       <key>CFBundleShortVersionString</key>
+       <string>{{{short_version}}}</string>
+       <key>CFBundleSignature</key>
+       <string>\\?\\?\\?\\?</string>
+       <key>CFBundleVersion</key>
+       <string>{{{bundle_version}}}</string>
+       <key>LSRequiresIPhoneOS</key>
+       <true/>
+       <key>UIRequiredDeviceCapabilities</key>
+       <array>
+               <string>armv7</string>
+       </array>
+       <key>UISupportedInterfaceOrientations</key>
+       <array>
+               <string>UIInterfaceOrientationPortrait</string>
+               <string>UIInterfaceOrientationLandscapeLeft</string>
+               <string>UIInterfaceOrientationLandscapeRight</string>
+       </array>
+       <key>UISupportedInterfaceOrientations~ipad</key>
+       <array>
+               <string>UIInterfaceOrientationPortrait</string>
+               <string>UIInterfaceOrientationPortraitUpsideDown</string>
+               <string>UIInterfaceOrientationLandscapeLeft</string>
+               <string>UIInterfaceOrientationLandscapeRight</string>
+       </array>
+</dict>
+</plist>
+"""
+       end
+end
index 69e9023..73cc176 100644 (file)
@@ -93,7 +93,7 @@ class RapidTypeAnalysis
                var mtype = callsite.recv
                var anchor = callsite.anchor
                if anchor != null then mtype = mtype.anchor_to(callsite.mmodule, anchor)
-               mtype = mtype.as_notnullable
+               mtype = mtype.undecorate
                if mtype isa MClassType then mtype = mtype.mclass.intro.bound_mtype
                var mproperty = callsite.mproperty
                var res = live_targets_cache[mtype, mproperty]
@@ -465,7 +465,7 @@ class RapidTypeVisitor
        do
                mtype = mtype.anchor_to(self.analysis.mainmodule, self.receiver)
                if mtype isa MNullType then return null
-               mtype = mtype.as_notnullable
+               mtype = mtype.undecorate
                assert mtype isa MClassType
                assert not mtype.need_anchor
                return mtype
index d60e2a3..07b4f46 100644 (file)
@@ -56,8 +56,10 @@ redef class AMethPropdef
        # Collect initializers and build the auto-init
        fun do_auto_super_init(modelbuilder: ModelBuilder)
        do
-               var mclassdef = self.parent.as(AClassdef).mclassdef.as(not null)
-               var mpropdef = self.mpropdef.as(not null)
+               var mclassdef = self.parent.as(AClassdef).mclassdef
+               if mclassdef == null then return # skip error
+               var mpropdef = self.mpropdef
+               if mpropdef == null then return # skip error
                var mmodule = mpropdef.mclassdef.mmodule
                var anchor = mclassdef.bound_mtype
                var recvtype = mclassdef.mclass.mclass_type
index 15d38a2..cf8bbda 100644 (file)
@@ -115,7 +115,12 @@ private class TypeVisitor
                        #node.debug("Unsafe typing: expected {sup}, got {sub}")
                        return sup
                end
-               self.modelbuilder.error(node, "Type error: expected {sup}, got {sub}")
+               if sub.need_anchor then
+                       var u = anchor_to(sub)
+                       self.modelbuilder.error(node, "Type error: expected {sup}, got {sub}: {u}")
+               else
+                       self.modelbuilder.error(node, "Type error: expected {sup}, got {sub}")
+               end
                return null
        end
 
@@ -194,6 +199,34 @@ private class TypeVisitor
                return sup
        end
 
+       # Can `mtype` be null (up to the current knowledge)?
+       fun can_be_null(mtype: MType): Bool
+       do
+               if mtype isa MNullableType or mtype isa MNullType then return true
+               if mtype isa MFormalType then
+                       var x = anchor_to(mtype)
+                       if x isa MNullableType or x isa MNullType then return true
+               end
+               return false
+       end
+
+       # Check that `mtype` can be null (up to the current knowledge).
+       #
+       # If not then display a `useless-null-test` warning on node and return false.
+       # Else return true.
+       fun check_can_be_null(anode: ANode, mtype: MType): Bool
+       do
+               if can_be_null(mtype) then return true
+
+               if mtype isa MFormalType then
+                       var res = anchor_to(mtype)
+                       modelbuilder.warning(anode, "useless-null-test", "Warning: expression is not null, since it is a `{mtype}: {res}`.")
+               else
+                       modelbuilder.warning(anode, "useless-null-test", "Warning: expression is not null, since it is a `{mtype}`.")
+               end
+               return false
+       end
+
        # Special verification on != and == for null
        # Return true
        fun null_test(anode: ABinopExpr)
@@ -205,24 +238,24 @@ private class TypeVisitor
 
                if not mtype2 isa MNullType then return
 
+               if mtype 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
+               if not check_can_be_null(anode.n_expr, mtype) then return
+
+               mtype = mtype.as_notnull
 
                # Check for type adaptation
                var variable = anode.n_expr.its_variable
                if variable == null then return
 
+               # One is null (mtype2 see above) the other is not null
                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)
+                       anode.after_flow_context.when_false.set_var(variable, 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)
+                       anode.after_flow_context.when_true.set_var(variable, mtype)
                else
                        abort
                end
@@ -246,10 +279,7 @@ private class TypeVisitor
 
        fun get_mclass(node: ANode, name: String): nullable MClass
        do
-               var mclass = modelbuilder.try_get_mclass_by_name(node, mmodule, name)
-               if mclass == null then
-                       self.modelbuilder.error(node, "Type Error: missing primitive class `{name}'.")
-               end
+               var mclass = modelbuilder.get_mclass_by_name(node, mmodule, name)
                return mclass
        end
 
@@ -268,7 +298,9 @@ private class TypeVisitor
                if recvtype isa MNullType then
                        # `null` only accepts some methods of object.
                        if name == "==" or name == "!=" or name == "is_same_instance" then
-                               unsafe_type = mmodule.object_type.as_nullable
+                               var objclass = get_mclass(node, "Object")
+                               if objclass == null then return null # Forward error
+                               unsafe_type = objclass.mclass_type
                        else
                                self.error(node, "Error: Method '{name}' call on 'null'.")
                                return null
@@ -328,13 +360,14 @@ private class TypeVisitor
                end
 
 
-               var msignature = mpropdef.new_msignature or else mpropdef.msignature.as(not null)
+               var msignature = mpropdef.new_msignature or else mpropdef.msignature
+               if msignature == null then return null # skip error
                msignature = resolve_for(msignature, recvtype, recv_is_self).as(MSignature)
 
                var erasure_cast = false
                var rettype = mpropdef.msignature.return_mtype
                if not recv_is_self and rettype != null then
-                       rettype = rettype.as_notnullable
+                       rettype = rettype.undecorate
                        if rettype isa MParameterType then
                                var erased_rettype = msignature.return_mtype
                                assert erased_rettype != null
@@ -450,7 +483,7 @@ private class TypeVisitor
                        var found = true
                        for t2 in col do
                                if t2 == null then continue # return null
-                               if t2 isa MNullableType or t2 isa MNullType then
+                               if can_be_null(t2) and not can_be_null(t1) then
                                        t1 = t1.as_nullable
                                end
                                if not is_subtype(t2, t1) then found = false
@@ -569,14 +602,18 @@ redef class AMethPropdef
                var nblock = self.n_block
                if nblock == null then return
 
-               var mpropdef = self.mpropdef.as(not null)
+               var mpropdef = self.mpropdef
+               if mpropdef == null then return # skip error
+
                var v = new TypeVisitor(modelbuilder, mpropdef.mclassdef.mmodule, mpropdef)
                self.selfvariable = v.selfvariable
 
                var mmethoddef = self.mpropdef.as(not null)
-               for i in [0..mmethoddef.msignature.arity[ do
-                       var mtype = mmethoddef.msignature.mparameters[i].mtype
-                       if mmethoddef.msignature.vararg_rank == i then
+               var msignature = mmethoddef.msignature
+               if msignature == null then return # skip error
+               for i in [0..msignature.arity[ do
+                       var mtype = msignature.mparameters[i].mtype
+                       if msignature.vararg_rank == i then
                                var arrayclass = v.get_mclass(self.n_signature.n_params[i], "Array")
                                if arrayclass == null then return # Skip error
                                mtype = arrayclass.get_mtype([mtype])
@@ -587,7 +624,7 @@ redef class AMethPropdef
                end
                v.visit_stmt(nblock)
 
-               if not nblock.after_flow_context.is_unreachable and mmethoddef.msignature.return_mtype != null then
+               if not nblock.after_flow_context.is_unreachable and msignature.return_mtype != null then
                        # We reach the end of the function without having a return, it is bad
                        v.error(self, "Control error: Reached end of function (a 'return' with a value was expected).")
                end
@@ -599,7 +636,9 @@ redef class AAttrPropdef
        do
                if not has_value then return
 
-               var mpropdef = self.mpropdef.as(not null)
+               var mpropdef = self.mpropdef
+               if mpropdef == null then return # skip error
+
                var v = new TypeVisitor(modelbuilder, mpropdef.mclassdef.mmodule, mpropdef)
                self.selfvariable = v.selfvariable
 
@@ -698,7 +737,9 @@ redef class AVardeclExpr
 
                var decltype = mtype
                if mtype == null or mtype isa MNullType then
-                       decltype = v.get_mclass(self, "Object").mclass_type.as_nullable
+                       var objclass = v.get_mclass(self, "Object")
+                       if objclass == null then return # skip error
+                       decltype = objclass.mclass_type.as_nullable
                        if mtype == null then mtype = decltype
                end
 
@@ -1003,7 +1044,7 @@ redef class AForExpr
                # anchor formal and virtual types
                if mtype.need_anchor then mtype = v.anchor_to(mtype)
 
-               mtype = mtype.as_notnullable
+               mtype = mtype.undecorate
                self.coltype = mtype.as(MClassType)
 
                # get methods is_ok, next, item
@@ -1140,12 +1181,18 @@ redef class AOrElseExpr
                        return # Skip error
                end
 
-               t1 = t1.as_notnullable
+               if t1 isa MNullType then
+                       v.error(n_expr, "Type error: or else on null")
+               else if v.check_can_be_null(n_expr, t1) then
+                       t1 = t1.as_notnull
+               end
 
                var t = v.merge_types(self, [t1, t2])
                if t == null then
-                       t = v.mmodule.object_type
-                       if t2 isa MNullableType then
+                       var c = v.get_mclass(self, "Object")
+                       if c == null then return # forward error
+                       t = c.mclass_type
+                       if v.can_be_null(t2) then
                                t = t.as_nullable
                        end
                        #v.error(self, "Type Error: ambiguous type {t1} vs {t2}")
@@ -1210,8 +1257,11 @@ redef class ASuperstringExpr
                var mclass = v.get_mclass(self, "String")
                if mclass == null then return # Forward error
                self.mtype = mclass.mclass_type
+               var objclass = v.get_mclass(self, "Object")
+               if objclass == null then return # Forward error
+               var objtype = objclass.mclass_type
                for nexpr in self.n_exprs do
-                       v.visit_expr_subtype(nexpr, v.mmodule.object_type)
+                       v.visit_expr_subtype(nexpr, objtype)
                end
        end
 end
@@ -1374,22 +1424,12 @@ redef class AAsNotnullExpr
                        v.error(self, "Type error: as(not null) on null")
                        return
                end
-               if mtype isa MNullableType then
-                       self.mtype = mtype.mtype
-                       return
-               end
-               self.mtype = mtype
 
-               if mtype isa MClassType then
-                       v.modelbuilder.warning(self, "useless-type-test", "Warning: expression is already not null, since it is a `{mtype}`.")
-                       return
-               end
-               assert mtype.need_anchor
-               var u = v.anchor_to(mtype)
-               if not u isa MNullableType then
-                       v.modelbuilder.warning(self, "useless-type-test", "Warning: expression is already not null, since it is a `{mtype}: {u}`.")
-                       return
+               if v.check_can_be_null(n_expr, mtype) then
+                       mtype = mtype.as_notnull
                end
+
+               self.mtype = mtype
        end
 end
 
@@ -1836,7 +1876,8 @@ redef class AAttrFormExpr
                var mpropdefs = mproperty.lookup_definitions(v.mmodule, unsafe_type)
                assert mpropdefs.length == 1
                var mpropdef = mpropdefs.first
-               var attr_type = mpropdef.static_mtype.as(not null)
+               var attr_type = mpropdef.static_mtype
+               if attr_type == null then return # skip error
                attr_type = v.resolve_for(attr_type, recvtype, self.n_expr isa ASelfExpr)
                self.attr_type = attr_type
        end
index 8fd5908..767cf95 100644 (file)
@@ -62,6 +62,6 @@ var model = new Model
 var modelbuilder = new ModelBuilder(model, toolcontext)
 
 # Here we load an process all modules passed on the command line
-var mmodules = modelbuilder.parse(arguments)
+var mmodules = modelbuilder.parse_full(arguments)
 modelbuilder.run_phases
 toolcontext.run_global_phases(mmodules)
index 62c184a..92a4824 100644 (file)
@@ -134,13 +134,13 @@ class ToolContext
                return tags.has("all") or tags.has(tag)
        end
 
-       # Output all current stacked messages and display total error informations
+       # Output all current stacked messages
        #
        # Return true if no errors occurred.
        #
        # If some errors occurred, the behavior depends on the value of `keep_going`.
-       # If `keep_going` is false, then the program exits.
-       # Else, the error count and the warning count are reset and false is returned.
+       # If `keep_going` is false, then the total error informations is displayed and the program exits.
+       # Else, false is returned.
        fun check_errors: Bool
        do
                if messages.length > 0 then
@@ -158,21 +158,21 @@ class ToolContext
                end
 
                if error_count > 0 then
-                       errors_info
-                       if not keep_going then exit(1)
+                       if not keep_going then
+                               errors_info
+                               exit(1)
+                       end
                        return false
                end
                return true
        end
 
-       # Display (and reset) total error informations
+       # Display total error informations
        fun errors_info
        do
                if error_count == 0 and warning_count == 0 then return
                if opt_no_color.value then return
                sys.stderr.write "Errors: {error_count}. Warnings: {warning_count}.\n"
-               error_count = 0
-               warning_count = 0
        end
 
        # Display an error
index b33e7f8..9c3d516 100644 (file)
@@ -61,10 +61,10 @@ class VirtualMachine super NaiveInterpreter
                var anchor = self.frame.arguments.first.mtype.as(MClassType)
 
                # `sub` or `sup` are formal or virtual types, resolve them to concrete types
-               if sub isa MParameterType or sub isa MVirtualType then
+               if sub isa MFormalType then
                        sub = sub.resolve_for(anchor.mclass.mclass_type, anchor, mainmodule, false)
                end
-               if sup isa MParameterType or sup isa MVirtualType then
+               if sup isa MFormalType then
                        sup = sup.resolve_for(anchor.mclass.mclass_type, anchor, mainmodule, false)
                end
 
@@ -87,7 +87,7 @@ class VirtualMachine super NaiveInterpreter
                end
                # Now the case of direct null and nullable is over
 
-               if sub isa MParameterType or sub isa MVirtualType then
+               if sub isa MFormalType then
                        sub = sub.anchor_to(mainmodule, anchor)
                        # Manage the second layer of null/nullable
                        if sub isa MNullableType then
index 609105e..8a90f1d 100644 (file)
@@ -1,3 +1,5 @@
 cocoa_extern_types
 cocoa_message_box
 hello_cocoa
+hello_ios
+test_platform_ios
diff --git a/tests/base_notnull.nit b/tests/base_notnull.nit
new file mode 100644 (file)
index 0000000..133aef1
--- /dev/null
@@ -0,0 +1,43 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import standard::kernel
+
+class A[E] #alt2# class A[E: Object]
+       type V: nullable Object #alt2# type V: Object
+
+       fun foo(e: E, v: E) do #1alt1# fun foo(e: nullable E, v: nullable E) do
+               assert e != null#alt1# #alt3# assert e == null #alt4# if false then e = null
+               assert v != null#alt1# #alt3# assert v == null #alt4# if false then e = null
+               bar(e)
+               bar(v)
+               if e != null then
+                       bar(e)
+               else bar(e)
+               if v != null then
+                       bar(v)
+               else bar(v)
+               bar(e.as(not null))
+               bar(v.as(not null))
+               bar(e or else 0)
+               bar(v or else 0)
+               bar(e or else v)
+               bar(v or else e)
+       end
+
+       fun bar(o: Object) do o.output
+end
+
+var a = new A[Object]
+a.foo (1, 2)
diff --git a/tests/base_notnull_lit.nit b/tests/base_notnull_lit.nit
new file mode 100644 (file)
index 0000000..dae4e46
--- /dev/null
@@ -0,0 +1,40 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+class A[E: nullable Discrete]
+       fun array(e, f: E): Object
+       do
+               assert e != null
+               assert f != null #alt1# #alt2# assert f == null
+               return [e, f]
+       end
+
+       fun range(e, f: E): Object
+       do
+               assert e != null
+               assert f != null #alt1#
+               return [e..f]
+       end
+end
+
+var a = new A[nullable Int]
+
+var ar = a.array(1, 5)
+ar.output_class_name
+ar.as(Array[Int]).add 6
+print ar
+
+var ra = a.range(1, 5)
+ra.output_class_name
+print ra
diff --git a/tests/error_virtual_type.nit b/tests/error_virtual_type.nit
new file mode 100644 (file)
index 0000000..dd7243b
--- /dev/null
@@ -0,0 +1,35 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import standard::kernel
+
+class G[E: Object]
+end
+
+class A
+       fun foo(t: T): Comparable do return t
+       type T: Comparable #alt1-5#
+       #alt1#type T: T
+       #alt2#type T: nullable T
+       #alt3#type T: G[T]
+       #alt4#type T: U
+       #alt4#type U: FAIL
+       #alt5#type T: U
+       #alt5#type U: T
+       fun bar(t: T): Comparable do return t
+end
+
+var a = new A
+a.foo(1)
+a.bar('1')
diff --git a/tests/error_virtual_type2.nit b/tests/error_virtual_type2.nit
new file mode 100644 (file)
index 0000000..274bb77
--- /dev/null
@@ -0,0 +1,52 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import standard::kernel
+
+class G[E]
+end
+
+class A
+       fun foo(t: T): Comparable do return t
+       #fun foog: nullable G[T] do return barg
+       type T: Comparable #alt1-5#
+       type GT: G[T]
+       #alt1#type T: T
+       #alt2#type T: nullable T
+       #alt3#type T: G[T]
+       #alt4#type T: U
+       #alt4#type U: FAIL
+       #alt5#type T: U
+       #alt5#type U: T
+       fun bar(t: T): Comparable do return t
+       #fun barg: nullable G[T] do return foog
+end
+
+class B
+       super A
+       redef fun foo(t: T): T do return t
+       #redef fun foog: GT do return barg
+       redef type GT: G[Discrete]
+       #alt6#redef type GT: G[Bool]
+       redef fun bar(t: T): T do return t
+       #redef fun barg: GT do return foog
+end
+
+var a = new A
+a.foo(1)
+a.bar('1')
+
+var b = new B
+b.foo(2)
+b.bar('3')
index 2380a43..2324342 100644 (file)
@@ -1,7 +1,7 @@
-base_as_notnull.nit:41,6--19: Warning: expression is already not null, since it is a `A`.
-base_as_notnull.nit:42,6--20: Warning: expression is already not null, since it is a `A`.
-base_as_notnull.nit:43,6--19: Warning: expression is already not null, since it is a `B`.
-base_as_notnull.nit:52,6--19: Warning: expression is already not null, since it is a `B`.
+base_as_notnull.nit:41,6: Warning: expression is not null, since it is a `A`.
+base_as_notnull.nit:42,6--7: Warning: expression is not null, since it is a `A`.
+base_as_notnull.nit:43,6: Warning: expression is not null, since it is a `B`.
+base_as_notnull.nit:52,6: Warning: expression is not null, since it is a `B`.
 1
 2
 3
index b0818df..1962743 100644 (file)
@@ -1,5 +1,5 @@
-base_as_notnull2.nit:30,12--25: Warning: expression is already not null, since it is a `Object`.
-base_as_notnull2.nit:50,12--25: Warning: expression is already not null, since it is a `F: Object`.
+base_as_notnull2.nit:30,12: Warning: expression is not null, since it is a `Object`.
+base_as_notnull2.nit:50,12: Warning: expression is not null, since it is a `F: Object`.
 1
 1
 2
index 01ee624..b61957e 100644 (file)
@@ -1,3 +1,3 @@
-alt/base_as_notnull2_alt1.nit:30,12--25: Warning: expression is already not null, since it is a `Object`.
-alt/base_as_notnull2_alt1.nit:50,12--25: Warning: expression is already not null, since it is a `F: Object`.
+alt/base_as_notnull2_alt1.nit:30,12: Warning: expression is not null, since it is a `Object`.
+alt/base_as_notnull2_alt1.nit:50,12: Warning: expression is not null, since it is a `F: Object`.
 alt/base_as_notnull2_alt1.nit:58,7--10: Type error: expected Object, got null
index e6335c5..4ac9e4e 100644 (file)
@@ -1,5 +1,5 @@
-alt/base_as_notnull2_alt2.nit:30,12--25: Warning: expression is already not null, since it is a `Object`.
-alt/base_as_notnull2_alt2.nit:50,12--25: Warning: expression is already not null, since it is a `F: Object`.
+alt/base_as_notnull2_alt2.nit:30,12: Warning: expression is not null, since it is a `Object`.
+alt/base_as_notnull2_alt2.nit:50,12: Warning: expression is not null, since it is a `F: Object`.
 Runtime error: Cast failed (alt/base_as_notnull2_alt2.nit:40)
 1
 1
index 4fb6e73..4a57748 100644 (file)
@@ -1,3 +1,3 @@
-alt/base_as_notnull2_alt3.nit:30,12--25: Warning: expression is already not null, since it is a `Object`.
-alt/base_as_notnull2_alt3.nit:50,12--25: Warning: expression is already not null, since it is a `F: Object`.
+alt/base_as_notnull2_alt3.nit:30,12: Warning: expression is not null, since it is a `Object`.
+alt/base_as_notnull2_alt3.nit:50,12: Warning: expression is not null, since it is a `F: Object`.
 alt/base_as_notnull2_alt3.nit:64,7--10: Type error: expected Int, got null
index ad6b798..cbb18f8 100644 (file)
@@ -1,6 +1,6 @@
-alt/base_as_notnull_alt1.nit:41,6--19: Warning: expression is already not null, since it is a `A`.
-alt/base_as_notnull_alt1.nit:42,6--20: Warning: expression is already not null, since it is a `A`.
-alt/base_as_notnull_alt1.nit:43,6--19: Warning: expression is already not null, since it is a `B`.
-alt/base_as_notnull_alt1.nit:50,6--19: Warning: expression is already not null, since it is a `A`.
+alt/base_as_notnull_alt1.nit:41,6: Warning: expression is not null, since it is a `A`.
+alt/base_as_notnull_alt1.nit:42,6--7: Warning: expression is not null, since it is a `A`.
+alt/base_as_notnull_alt1.nit:43,6: Warning: expression is not null, since it is a `B`.
+alt/base_as_notnull_alt1.nit:50,6: Warning: expression is not null, since it is a `A`.
 alt/base_as_notnull_alt1.nit:50,6--19: Type error: expected B, got A
-alt/base_as_notnull_alt1.nit:52,6--19: Warning: expression is already not null, since it is a `B`.
+alt/base_as_notnull_alt1.nit:52,6: Warning: expression is not null, since it is a `B`.
index 0e0e68c..c9dfed9 100644 (file)
@@ -1,6 +1,6 @@
-alt/base_as_notnull_alt2.nit:41,6--19: Warning: expression is already not null, since it is a `A`.
-alt/base_as_notnull_alt2.nit:42,6--20: Warning: expression is already not null, since it is a `A`.
-alt/base_as_notnull_alt2.nit:43,6--19: Warning: expression is already not null, since it is a `B`.
-alt/base_as_notnull_alt2.nit:51,6--20: Warning: expression is already not null, since it is a `A`.
+alt/base_as_notnull_alt2.nit:41,6: Warning: expression is not null, since it is a `A`.
+alt/base_as_notnull_alt2.nit:42,6--7: Warning: expression is not null, since it is a `A`.
+alt/base_as_notnull_alt2.nit:43,6: Warning: expression is not null, since it is a `B`.
+alt/base_as_notnull_alt2.nit:51,6--7: Warning: expression is not null, since it is a `A`.
 alt/base_as_notnull_alt2.nit:51,6--20: Type error: expected B, got A
-alt/base_as_notnull_alt2.nit:52,6--19: Warning: expression is already not null, since it is a `B`.
+alt/base_as_notnull_alt2.nit:52,6: Warning: expression is not null, since it is a `B`.
index bd83530..d66632f 100644 (file)
@@ -1,5 +1,5 @@
-alt/base_as_notnull_alt3.nit:41,6--19: Warning: expression is already not null, since it is a `A`.
-alt/base_as_notnull_alt3.nit:42,6--20: Warning: expression is already not null, since it is a `A`.
-alt/base_as_notnull_alt3.nit:43,6--19: Warning: expression is already not null, since it is a `B`.
-alt/base_as_notnull_alt3.nit:52,6--19: Warning: expression is already not null, since it is a `B`.
+alt/base_as_notnull_alt3.nit:41,6: Warning: expression is not null, since it is a `A`.
+alt/base_as_notnull_alt3.nit:42,6--7: Warning: expression is not null, since it is a `A`.
+alt/base_as_notnull_alt3.nit:43,6: Warning: expression is not null, since it is a `B`.
+alt/base_as_notnull_alt3.nit:52,6: Warning: expression is not null, since it is a `B`.
 alt/base_as_notnull_alt3.nit:53,6--20: Type error: expected B, got A
index 0050108..b25242f 100644 (file)
@@ -1,5 +1,5 @@
-alt/base_as_notnull_alt4.nit:41,6--19: Warning: expression is already not null, since it is a `A`.
-alt/base_as_notnull_alt4.nit:42,6--20: Warning: expression is already not null, since it is a `A`.
-alt/base_as_notnull_alt4.nit:43,6--19: Warning: expression is already not null, since it is a `B`.
-alt/base_as_notnull_alt4.nit:52,6--19: Warning: expression is already not null, since it is a `B`.
+alt/base_as_notnull_alt4.nit:41,6: Warning: expression is not null, since it is a `A`.
+alt/base_as_notnull_alt4.nit:42,6--7: Warning: expression is not null, since it is a `A`.
+alt/base_as_notnull_alt4.nit:43,6: Warning: expression is not null, since it is a `B`.
+alt/base_as_notnull_alt4.nit:52,6: Warning: expression is not null, since it is a `B`.
 alt/base_as_notnull_alt4.nit:54,6--21: Type error: expected B, got A
index d8136e9..b52a40b 100644 (file)
@@ -1,7 +1,7 @@
-alt/base_as_notnull_alt5.nit:41,6--19: Warning: expression is already not null, since it is a `A`.
-alt/base_as_notnull_alt5.nit:42,6--20: Warning: expression is already not null, since it is a `A`.
-alt/base_as_notnull_alt5.nit:43,6--19: Warning: expression is already not null, since it is a `B`.
-alt/base_as_notnull_alt5.nit:52,6--19: Warning: expression is already not null, since it is a `B`.
+alt/base_as_notnull_alt5.nit:41,6: Warning: expression is not null, since it is a `A`.
+alt/base_as_notnull_alt5.nit:42,6--7: Warning: expression is not null, since it is a `A`.
+alt/base_as_notnull_alt5.nit:43,6: Warning: expression is not null, since it is a `B`.
+alt/base_as_notnull_alt5.nit:52,6: Warning: expression is not null, since it is a `B`.
 Runtime error: Cast failed (alt/base_as_notnull_alt5.nit:59)
 1
 2
index 7083fa3..518f166 100644 (file)
@@ -1,7 +1,7 @@
-alt/base_as_notnull_alt6.nit:41,6--19: Warning: expression is already not null, since it is a `A`.
-alt/base_as_notnull_alt6.nit:42,6--20: Warning: expression is already not null, since it is a `A`.
-alt/base_as_notnull_alt6.nit:43,6--19: Warning: expression is already not null, since it is a `B`.
-alt/base_as_notnull_alt6.nit:52,6--19: Warning: expression is already not null, since it is a `B`.
+alt/base_as_notnull_alt6.nit:41,6: Warning: expression is not null, since it is a `A`.
+alt/base_as_notnull_alt6.nit:42,6--7: Warning: expression is not null, since it is a `A`.
+alt/base_as_notnull_alt6.nit:43,6: Warning: expression is not null, since it is a `B`.
+alt/base_as_notnull_alt6.nit:52,6: Warning: expression is not null, since it is a `B`.
 Runtime error: Cast failed (alt/base_as_notnull_alt6.nit:60)
 1
 2
index 38f0903..6ad88ec 100644 (file)
@@ -1,5 +1,5 @@
-alt/base_as_notnull_alt7.nit:41,6--19: Warning: expression is already not null, since it is a `A`.
-alt/base_as_notnull_alt7.nit:42,6--20: Warning: expression is already not null, since it is a `A`.
-alt/base_as_notnull_alt7.nit:43,6--19: Warning: expression is already not null, since it is a `B`.
-alt/base_as_notnull_alt7.nit:52,6--19: Warning: expression is already not null, since it is a `B`.
+alt/base_as_notnull_alt7.nit:41,6: Warning: expression is not null, since it is a `A`.
+alt/base_as_notnull_alt7.nit:42,6--7: Warning: expression is not null, since it is a `A`.
+alt/base_as_notnull_alt7.nit:43,6: Warning: expression is not null, since it is a `B`.
+alt/base_as_notnull_alt7.nit:52,6: Warning: expression is not null, since it is a `B`.
 alt/base_as_notnull_alt7.nit:61,1--17: Type error: as(not null) on null
index 4635340..8b381a4 100644 (file)
@@ -1,5 +1,5 @@
-base_as_notnull_int.nit:18,1--14: Warning: expression is already not null, since it is a `Int`.
-base_as_notnull_int.nit:20,1--15: Warning: expression is already not null, since it is a `Object`.
+base_as_notnull_int.nit:18,1: Warning: expression is not null, since it is a `Int`.
+base_as_notnull_int.nit:20,1--2: Warning: expression is not null, since it is a `Object`.
 1
 1
 1
index b4226bc..faf4840 100644 (file)
@@ -1,5 +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`.
+base_eq_null_notnull.nit:36,6: Warning: expression is not null, since it is a `A`.
+base_eq_null_notnull.nit:43,2: Warning: expression is not null, since it is a `A`.
 true
 true
 true
diff --git a/tests/sav/base_notnull.res b/tests/sav/base_notnull.res
new file mode 100644 (file)
index 0000000..1b755df
--- /dev/null
@@ -0,0 +1,18 @@
+base_notnull.nit:25,6: Warning: expression is not null, since it is a `not null E`.
+base_notnull.nit:28,6: Warning: expression is not null, since it is a `not null E`.
+base_notnull.nit:31,7: Warning: expression is not null, since it is a `not null E`.
+base_notnull.nit:32,7: Warning: expression is not null, since it is a `not null E`.
+base_notnull.nit:33,7: Warning: expression is not null, since it is a `not null E`.
+base_notnull.nit:34,7: Warning: expression is not null, since it is a `not null E`.
+base_notnull.nit:35,7: Warning: expression is not null, since it is a `not null E`.
+base_notnull.nit:36,7: Warning: expression is not null, since it is a `not null E`.
+1
+2
+1
+2
+1
+2
+1
+2
+1
+2
diff --git a/tests/sav/base_notnull_1alt1.res b/tests/sav/base_notnull_1alt1.res
new file mode 100644 (file)
index 0000000..925e389
--- /dev/null
@@ -0,0 +1,18 @@
+alt/base_notnull_1alt1.nit:25,6: Warning: expression is not null, since it is a `not null E`.
+alt/base_notnull_1alt1.nit:28,6: Warning: expression is not null, since it is a `not null E`.
+alt/base_notnull_1alt1.nit:31,7: Warning: expression is not null, since it is a `not null E`.
+alt/base_notnull_1alt1.nit:32,7: Warning: expression is not null, since it is a `not null E`.
+alt/base_notnull_1alt1.nit:33,7: Warning: expression is not null, since it is a `not null E`.
+alt/base_notnull_1alt1.nit:34,7: Warning: expression is not null, since it is a `not null E`.
+alt/base_notnull_1alt1.nit:35,7: Warning: expression is not null, since it is a `not null E`.
+alt/base_notnull_1alt1.nit:36,7: Warning: expression is not null, since it is a `not null E`.
+1
+2
+1
+2
+1
+2
+1
+2
+1
+2
diff --git a/tests/sav/base_notnull_1alt1_alt1.res b/tests/sav/base_notnull_1alt1_alt1.res
new file mode 100644 (file)
index 0000000..8a63507
--- /dev/null
@@ -0,0 +1,6 @@
+alt/base_notnull_1alt1_alt1.nit:23,7: Type error: expected Object, got nullable E: nullable Object
+alt/base_notnull_1alt1_alt1.nit:24,7: Type error: expected Object, got nullable E: nullable Object
+alt/base_notnull_1alt1_alt1.nit:27,12: Type error: expected Object, got null
+alt/base_notnull_1alt1_alt1.nit:30,12: Type error: expected Object, got null
+alt/base_notnull_1alt1_alt1.nit:35,7--17: Type error: expected Object, got nullable E: nullable Object
+alt/base_notnull_1alt1_alt1.nit:36,7--17: Type error: expected Object, got nullable E: nullable Object
diff --git a/tests/sav/base_notnull_1alt1_alt2.res b/tests/sav/base_notnull_1alt1_alt2.res
new file mode 100644 (file)
index 0000000..a316b82
--- /dev/null
@@ -0,0 +1,18 @@
+alt/base_notnull_1alt1_alt2.nit:25,6: Warning: expression is not null, since it is a `not null E`.
+alt/base_notnull_1alt1_alt2.nit:28,6: Warning: expression is not null, since it is a `not null E`.
+alt/base_notnull_1alt1_alt2.nit:31,7: Warning: expression is not null, since it is a `not null E`.
+alt/base_notnull_1alt1_alt2.nit:32,7: Warning: expression is not null, since it is a `not null E`.
+alt/base_notnull_1alt1_alt2.nit:33,7: Warning: expression is not null, since it is a `not null E`.
+alt/base_notnull_1alt1_alt2.nit:34,7: Warning: expression is not null, since it is a `not null E`.
+alt/base_notnull_1alt1_alt2.nit:35,7: Warning: expression is not null, since it is a `not null E`.
+alt/base_notnull_1alt1_alt2.nit:36,7: Warning: expression is not null, since it is a `not null E`.
+1
+2
+1
+2
+1
+2
+1
+2
+1
+2
diff --git a/tests/sav/base_notnull_1alt1_alt3.res b/tests/sav/base_notnull_1alt1_alt3.res
new file mode 100644 (file)
index 0000000..d044957
--- /dev/null
@@ -0,0 +1,16 @@
+alt/base_notnull_1alt1_alt3.nit:23,7: Type error: expected Object, got null
+alt/base_notnull_1alt1_alt3.nit:24,7: Type error: expected Object, got null
+alt/base_notnull_1alt1_alt3.nit:26,8: Type error: expected Object, got null
+alt/base_notnull_1alt1_alt3.nit:27,12: Type error: expected Object, got null
+alt/base_notnull_1alt1_alt3.nit:29,8: Type error: expected Object, got null
+alt/base_notnull_1alt1_alt3.nit:30,12: Type error: expected Object, got null
+alt/base_notnull_1alt1_alt3.nit:31,7--20: Type error: as(not null) on null
+alt/base_notnull_1alt1_alt3.nit:32,7--20: Type error: as(not null) on null
+alt/base_notnull_1alt1_alt3.nit:33,7: Type error: or else on null
+alt/base_notnull_1alt1_alt3.nit:33,7--17: Type error: expected Object, got nullable Int
+alt/base_notnull_1alt1_alt3.nit:34,7: Type error: or else on null
+alt/base_notnull_1alt1_alt3.nit:34,7--17: Type error: expected Object, got nullable Int
+alt/base_notnull_1alt1_alt3.nit:35,7: Type error: or else on null
+alt/base_notnull_1alt1_alt3.nit:35,7--17: Type error: expected Object, got null
+alt/base_notnull_1alt1_alt3.nit:36,7: Type error: or else on null
+alt/base_notnull_1alt1_alt3.nit:36,7--17: Type error: expected Object, got null
diff --git a/tests/sav/base_notnull_1alt1_alt4.res b/tests/sav/base_notnull_1alt1_alt4.res
new file mode 100644 (file)
index 0000000..b0f0ecd
--- /dev/null
@@ -0,0 +1,6 @@
+alt/base_notnull_1alt1_alt4.nit:23,7: Type error: expected Object, got nullable E: nullable Object
+alt/base_notnull_1alt1_alt4.nit:24,7: Type error: expected Object, got nullable E: nullable Object
+alt/base_notnull_1alt1_alt4.nit:27,12: Type error: expected Object, got null
+alt/base_notnull_1alt1_alt4.nit:30,12: Type error: expected Object, got null
+alt/base_notnull_1alt1_alt4.nit:35,7--17: Type error: expected Object, got nullable E: nullable Object
+alt/base_notnull_1alt1_alt4.nit:36,7--17: Type error: expected Object, got nullable E: nullable Object
diff --git a/tests/sav/base_notnull_alt1.res b/tests/sav/base_notnull_alt1.res
new file mode 100644 (file)
index 0000000..4a50aa8
--- /dev/null
@@ -0,0 +1,6 @@
+alt/base_notnull_alt1.nit:23,7: Type error: expected Object, got E: nullable Object
+alt/base_notnull_alt1.nit:24,7: Type error: expected Object, got E: nullable Object
+alt/base_notnull_alt1.nit:27,12: Type error: expected Object, got null
+alt/base_notnull_alt1.nit:30,12: Type error: expected Object, got null
+alt/base_notnull_alt1.nit:35,7--17: Type error: expected Object, got nullable E: nullable Object
+alt/base_notnull_alt1.nit:36,7--17: Type error: expected Object, got nullable E: nullable Object
diff --git a/tests/sav/base_notnull_alt2.res b/tests/sav/base_notnull_alt2.res
new file mode 100644 (file)
index 0000000..9450e83
--- /dev/null
@@ -0,0 +1,20 @@
+alt/base_notnull_alt2.nit:21,10: Warning: expression is not null, since it is a `E: Object`.
+alt/base_notnull_alt2.nit:22,10: Warning: expression is not null, since it is a `E: Object`.
+alt/base_notnull_alt2.nit:25,6: Warning: expression is not null, since it is a `E: Object`.
+alt/base_notnull_alt2.nit:28,6: Warning: expression is not null, since it is a `E: Object`.
+alt/base_notnull_alt2.nit:31,7: Warning: expression is not null, since it is a `E: Object`.
+alt/base_notnull_alt2.nit:32,7: Warning: expression is not null, since it is a `E: Object`.
+alt/base_notnull_alt2.nit:33,7: Warning: expression is not null, since it is a `E: Object`.
+alt/base_notnull_alt2.nit:34,7: Warning: expression is not null, since it is a `E: Object`.
+alt/base_notnull_alt2.nit:35,7: Warning: expression is not null, since it is a `E: Object`.
+alt/base_notnull_alt2.nit:36,7: Warning: expression is not null, since it is a `E: Object`.
+1
+2
+1
+2
+1
+2
+1
+2
+1
+2
diff --git a/tests/sav/base_notnull_alt3.res b/tests/sav/base_notnull_alt3.res
new file mode 100644 (file)
index 0000000..addd582
--- /dev/null
@@ -0,0 +1,16 @@
+alt/base_notnull_alt3.nit:23,7: Type error: expected Object, got null
+alt/base_notnull_alt3.nit:24,7: Type error: expected Object, got null
+alt/base_notnull_alt3.nit:26,8: Type error: expected Object, got null
+alt/base_notnull_alt3.nit:27,12: Type error: expected Object, got null
+alt/base_notnull_alt3.nit:29,8: Type error: expected Object, got null
+alt/base_notnull_alt3.nit:30,12: Type error: expected Object, got null
+alt/base_notnull_alt3.nit:31,7--20: Type error: as(not null) on null
+alt/base_notnull_alt3.nit:32,7--20: Type error: as(not null) on null
+alt/base_notnull_alt3.nit:33,7: Type error: or else on null
+alt/base_notnull_alt3.nit:33,7--17: Type error: expected Object, got nullable Int
+alt/base_notnull_alt3.nit:34,7: Type error: or else on null
+alt/base_notnull_alt3.nit:34,7--17: Type error: expected Object, got nullable Int
+alt/base_notnull_alt3.nit:35,7: Type error: or else on null
+alt/base_notnull_alt3.nit:35,7--17: Type error: expected Object, got null
+alt/base_notnull_alt3.nit:36,7: Type error: or else on null
+alt/base_notnull_alt3.nit:36,7--17: Type error: expected Object, got null
diff --git a/tests/sav/base_notnull_alt4.res b/tests/sav/base_notnull_alt4.res
new file mode 100644 (file)
index 0000000..d0db7c3
--- /dev/null
@@ -0,0 +1,6 @@
+alt/base_notnull_alt4.nit:23,7: Type error: expected Object, got E: nullable Object
+alt/base_notnull_alt4.nit:24,7: Type error: expected Object, got E: nullable Object
+alt/base_notnull_alt4.nit:27,12: Type error: expected Object, got null
+alt/base_notnull_alt4.nit:30,12: Type error: expected Object, got null
+alt/base_notnull_alt4.nit:35,7--17: Type error: expected Object, got nullable E: nullable Object
+alt/base_notnull_alt4.nit:36,7--17: Type error: expected Object, got nullable E: nullable Object
diff --git a/tests/sav/base_notnull_lit.res b/tests/sav/base_notnull_lit.res
new file mode 100644 (file)
index 0000000..dc19389
--- /dev/null
@@ -0,0 +1,4 @@
+Array[Int]
+156
+Range[Int]
+12345
diff --git a/tests/sav/base_notnull_lit_alt1.res b/tests/sav/base_notnull_lit_alt1.res
new file mode 100644 (file)
index 0000000..fac195d
--- /dev/null
@@ -0,0 +1 @@
+alt/base_notnull_lit_alt1.nit:27,14: Type error: expected Discrete, got E: nullable Discrete
diff --git a/tests/sav/base_notnull_lit_alt2.res b/tests/sav/base_notnull_lit_alt2.res
new file mode 100644 (file)
index 0000000..522489c
--- /dev/null
@@ -0,0 +1 @@
+Runtime error: Assert failed (alt/base_notnull_lit_alt2.nit:19)
index 80acf2a..814a7ef 100644 (file)
@@ -1,5 +1,3 @@
-base_null.nit:28,2--13: Warning: expression is not null, since it is a `null`.
-base_null.nit:42,2--13: Warning: expression is not null, since it is a `null`.
 false
 false
 true
index 99abb44..28f095a 100644 (file)
@@ -1 +1 @@
-alt/base_upcast2_1alt1_alt10.nit:36,21: Type error: expected C, got T
+alt/base_upcast2_1alt1_alt10.nit:36,21: Type error: expected C, got T: A[Int]
index 29fe46d..15ba7c3 100644 (file)
@@ -1 +1 @@
-alt/base_upcast2_1alt1_alt7.nit:33,22: Type error: expected A[Bool], got T
+alt/base_upcast2_1alt1_alt7.nit:33,22: Type error: expected A[Bool], got T: A[Int]
index 4f33a48..a7f751c 100644 (file)
@@ -1 +1 @@
-alt/base_upcast2_1alt1_alt8.nit:34,22: Type error: expected B[Int], got T
+alt/base_upcast2_1alt1_alt8.nit:34,22: Type error: expected B[Int], got T: A[Int]
index 3191dca..98420d0 100644 (file)
@@ -1 +1 @@
-alt/base_upcast2_1alt1_alt9.nit:35,22: Type error: expected B[Bool], got T
+alt/base_upcast2_1alt1_alt9.nit:35,22: Type error: expected B[Bool], got T: A[Int]
index 8d013a7..8ef15ac 100644 (file)
@@ -1 +1 @@
-alt/base_upcast2_1alt2_alt10.nit:36,21: Type error: expected C, got T
+alt/base_upcast2_1alt2_alt10.nit:36,21: Type error: expected C, got T: A[Bool]
index afb8ffe..016d020 100644 (file)
@@ -1 +1 @@
-alt/base_upcast2_1alt2_alt6.nit:32,22: Type error: expected A[Int], got T
+alt/base_upcast2_1alt2_alt6.nit:32,22: Type error: expected A[Int], got T: A[Bool]
index ab7c7d3..cdbac7a 100644 (file)
@@ -1 +1 @@
-alt/base_upcast2_1alt2_alt8.nit:34,22: Type error: expected B[Int], got T
+alt/base_upcast2_1alt2_alt8.nit:34,22: Type error: expected B[Int], got T: A[Bool]
index c687866..2b3c257 100644 (file)
@@ -1 +1 @@
-alt/base_upcast2_1alt2_alt9.nit:35,22: Type error: expected B[Bool], got T
+alt/base_upcast2_1alt2_alt9.nit:35,22: Type error: expected B[Bool], got T: A[Bool]
index b64929b..975c3fb 100644 (file)
@@ -1 +1 @@
-alt/base_upcast2_1alt3_alt10.nit:36,21: Type error: expected C, got T
+alt/base_upcast2_1alt3_alt10.nit:36,21: Type error: expected C, got T: B[Int]
index b2aeba1..e44436b 100644 (file)
@@ -1 +1 @@
-alt/base_upcast2_1alt3_alt7.nit:33,22: Type error: expected A[Bool], got T
+alt/base_upcast2_1alt3_alt7.nit:33,22: Type error: expected A[Bool], got T: B[Int]
index f6151ca..1f17f5f 100644 (file)
@@ -1 +1 @@
-alt/base_upcast2_1alt3_alt9.nit:35,22: Type error: expected B[Bool], got T
+alt/base_upcast2_1alt3_alt9.nit:35,22: Type error: expected B[Bool], got T: B[Int]
index 7943796..37d0456 100644 (file)
@@ -1 +1 @@
-alt/base_upcast2_1alt4_alt10.nit:36,21: Type error: expected C, got T
+alt/base_upcast2_1alt4_alt10.nit:36,21: Type error: expected C, got T: B[Bool]
index 1ce4304..a9f7c8b 100644 (file)
@@ -1 +1 @@
-alt/base_upcast2_1alt4_alt7.nit:33,22: Type error: expected A[Bool], got T
+alt/base_upcast2_1alt4_alt7.nit:33,22: Type error: expected A[Bool], got T: B[Bool]
index a636739..821b826 100644 (file)
@@ -1 +1 @@
-alt/base_upcast2_1alt4_alt8.nit:34,22: Type error: expected B[Int], got T
+alt/base_upcast2_1alt4_alt8.nit:34,22: Type error: expected B[Int], got T: B[Bool]
index a670740..9d35793 100644 (file)
@@ -1 +1 @@
-alt/base_upcast2_1alt5_alt7.nit:33,22: Type error: expected A[Bool], got T
+alt/base_upcast2_1alt5_alt7.nit:33,22: Type error: expected A[Bool], got T: C
index ce4fd54..5ce490d 100644 (file)
@@ -1 +1 @@
-alt/base_upcast2_1alt5_alt8.nit:34,22: Type error: expected B[Int], got T
+alt/base_upcast2_1alt5_alt8.nit:34,22: Type error: expected B[Int], got T: C
index 46069e8..0025f05 100644 (file)
@@ -1,4 +1,4 @@
-base_var_type_evolution_null3.nit:52,5--13: Warning: expression is not null, since it is a `Object`.
+base_var_type_evolution_null3.nit:52,5: Warning: expression is not null, since it is a `Object`.
 1
 1
 5
index a10a5e3..5bc9b2d 100644 (file)
@@ -1,4 +1,4 @@
-alt/base_var_type_evolution_null3_alt1.nit:52,5--13: Warning: expression is not null, since it is a `Object`.
+alt/base_var_type_evolution_null3_alt1.nit:52,5: Warning: expression is not null, since it is a `Object`.
 1
 1
 5
index 0fc0245..01f9a2f 100644 (file)
@@ -1,2 +1 @@
-base_virtual_type7.nit:20,2--10: Error: circularity of virtual type definition: E -> F -> E
-base_virtual_type7.nit:21,2--10: Error: circularity of virtual type definition: F -> E -> F
+base_virtual_type7.nit:20,2--10: Error: circularity of virtual type definition: E <-> F
index 397a44a..44a485a 100644 (file)
@@ -1,3 +1,3 @@
 alt/base_virtual_type_self_alt5.nit:44,9: Type error: expected A[U], got Float
-alt/base_virtual_type_self_alt5.nit:45,7--12: Type error: expected Float, got A[U]
-alt/base_virtual_type_self_alt5.nit:47,7--12: Type error: expected Float, got A[A[U]]
+alt/base_virtual_type_self_alt5.nit:45,7--12: Type error: expected Float, got A[U]: A[Int]
+alt/base_virtual_type_self_alt5.nit:47,7--12: Type error: expected Float, got A[A[U]]: A[A[Int]]
index 01f96ed..d22055c 100644 (file)
@@ -106,7 +106,7 @@ alt/error_expr_not_ok_alt4.nit:147,7--18: Type error: expected A, got Array[Int]
 alt/error_expr_not_ok_alt4.nit:149,7--24: Type error: expected A, got String
 alt/error_expr_not_ok_alt4.nit:150,7--18: Warning: Expression is already a Int.
 alt/error_expr_not_ok_alt4.nit:150,7--18: Type error: expected A, got Int
-alt/error_expr_not_ok_alt4.nit:151,7--23: Warning: expression is already not null, since it is a `Int`.
+alt/error_expr_not_ok_alt4.nit:151,7--10: Warning: expression is not null, since it is a `Int`.
 alt/error_expr_not_ok_alt4.nit:151,7--23: Type error: expected A, got Int
 alt/error_expr_not_ok_alt4.nit:152,7--18: Warning: Expression is already a Int.
 alt/error_expr_not_ok_alt4.nit:152,7--18: Type error: expected A, got Bool
index 98e1d46..a6caca4 100644 (file)
@@ -101,7 +101,7 @@ alt/error_expr_not_ok_alt5.nit:147,7--18: Type error: expected A, got Array[Int]
 alt/error_expr_not_ok_alt5.nit:149,7--24: Type error: expected A, got String
 alt/error_expr_not_ok_alt5.nit:150,7--18: Warning: Expression is already a Int.
 alt/error_expr_not_ok_alt5.nit:150,7--18: Type error: expected A, got Int
-alt/error_expr_not_ok_alt5.nit:151,7--23: Warning: expression is already not null, since it is a `Int`.
+alt/error_expr_not_ok_alt5.nit:151,7--10: Warning: expression is not null, since it is a `Int`.
 alt/error_expr_not_ok_alt5.nit:151,7--23: Type error: expected A, got Int
 alt/error_expr_not_ok_alt5.nit:152,7--18: Warning: Expression is already a Int.
 alt/error_expr_not_ok_alt5.nit:152,7--18: Type error: expected A, got Bool
index efeddc2..c56e7b6 100644 (file)
@@ -105,7 +105,7 @@ alt/error_expr_not_ok_alt6.nit:147,7--18: Type error: expected A, got Array[Int]
 alt/error_expr_not_ok_alt6.nit:149,7--24: Type error: expected A, got String
 alt/error_expr_not_ok_alt6.nit:150,7--18: Warning: Expression is already a Int.
 alt/error_expr_not_ok_alt6.nit:150,7--18: Type error: expected A, got Int
-alt/error_expr_not_ok_alt6.nit:151,7--23: Warning: expression is already not null, since it is a `Int`.
+alt/error_expr_not_ok_alt6.nit:151,7--10: Warning: expression is not null, since it is a `Int`.
 alt/error_expr_not_ok_alt6.nit:151,7--23: Type error: expected A, got Int
 alt/error_expr_not_ok_alt6.nit:152,7--18: Warning: Expression is already a Int.
 alt/error_expr_not_ok_alt6.nit:152,7--18: Type error: expected A, got Bool
index 6f7a1f9..f80abe8 100644 (file)
@@ -1 +1 @@
-Fatal Error: no primitive class NativeArray
+Fatal Error: no primitive class NativeArray in error_needed_method_alt4
index 6f7a1f9..2a7c903 100644 (file)
@@ -1 +1 @@
-Fatal Error: no primitive class NativeArray
+Fatal Error: no primitive class NativeArray in error_needed_method_alt7
diff --git a/tests/sav/error_virtual_type2.res b/tests/sav/error_virtual_type2.res
new file mode 100644 (file)
index 0000000..417f403
--- /dev/null
@@ -0,0 +1 @@
+error_virtual_type2.nit:40,17--26: Redef Error: Wrong bound type. Found G[Discrete], expected a subtype of G[T], as in error_virtual_type2#A#GT.
diff --git a/tests/sav/error_virtual_type2_alt1.res b/tests/sav/error_virtual_type2_alt1.res
new file mode 100644 (file)
index 0000000..38cf3dd
--- /dev/null
@@ -0,0 +1,5 @@
+alt/error_virtual_type2_alt1.nit:22,2--24,13: Error: circularity of virtual type definition: GT -> T <-> T
+alt/error_virtual_type2_alt1.nit:25,2--10: Error: circularity of virtual type definition: T <-> T
+alt/error_virtual_type2_alt1.nit:38,23: Redef Error: Wrong return type. found T, expected Comparable as in error_virtual_type2_alt1#A#foo.
+alt/error_virtual_type2_alt1.nit:40,17--26: Redef Error: Wrong bound type. Found G[Discrete], expected a subtype of null, as in error_virtual_type2_alt1#A#GT.
+alt/error_virtual_type2_alt1.nit:42,23: Redef Error: Wrong return type. found T, expected Comparable as in error_virtual_type2_alt1#A#bar.
diff --git a/tests/sav/error_virtual_type2_alt2.res b/tests/sav/error_virtual_type2_alt2.res
new file mode 100644 (file)
index 0000000..f155524
--- /dev/null
@@ -0,0 +1,5 @@
+alt/error_virtual_type2_alt2.nit:22,2--24,13: Error: circularity of virtual type definition: GT -> T <-> nullable T
+alt/error_virtual_type2_alt2.nit:25,2--26,19: Error: circularity of virtual type definition: T <-> nullable T
+alt/error_virtual_type2_alt2.nit:38,23: Redef Error: Wrong return type. found T, expected Comparable as in error_virtual_type2_alt2#A#foo.
+alt/error_virtual_type2_alt2.nit:40,17--26: Redef Error: Wrong bound type. Found G[Discrete], expected a subtype of null, as in error_virtual_type2_alt2#A#GT.
+alt/error_virtual_type2_alt2.nit:42,23: Redef Error: Wrong return type. found T, expected Comparable as in error_virtual_type2_alt2#A#bar.
diff --git a/tests/sav/error_virtual_type2_alt3.res b/tests/sav/error_virtual_type2_alt3.res
new file mode 100644 (file)
index 0000000..80c9981
--- /dev/null
@@ -0,0 +1,5 @@
+alt/error_virtual_type2_alt3.nit:22,2--24,13: Error: circularity of virtual type definition: GT -> G[T] <-> T
+alt/error_virtual_type2_alt3.nit:25,2--27,12: Error: circularity of virtual type definition: T <-> G[T]
+alt/error_virtual_type2_alt3.nit:38,23: Redef Error: Wrong return type. found T, expected Comparable as in error_virtual_type2_alt3#A#foo.
+alt/error_virtual_type2_alt3.nit:40,17--26: Redef Error: Wrong bound type. Found G[Discrete], expected a subtype of null, as in error_virtual_type2_alt3#A#GT.
+alt/error_virtual_type2_alt3.nit:42,23: Redef Error: Wrong return type. found T, expected Comparable as in error_virtual_type2_alt3#A#bar.
diff --git a/tests/sav/error_virtual_type2_alt4.res b/tests/sav/error_virtual_type2_alt4.res
new file mode 100644 (file)
index 0000000..158622e
--- /dev/null
@@ -0,0 +1,4 @@
+alt/error_virtual_type2_alt4.nit:29,10--13: Type error: class FAIL not found in module error_virtual_type2_alt4.
+alt/error_virtual_type2_alt4.nit:38,23: Redef Error: Wrong return type. found T, expected Comparable as in error_virtual_type2_alt4#A#foo.
+alt/error_virtual_type2_alt4.nit:40,17--26: Redef Error: Wrong bound type. Found G[Discrete], expected a subtype of null, as in error_virtual_type2_alt4#A#GT.
+alt/error_virtual_type2_alt4.nit:42,23: Redef Error: Wrong return type. found T, expected Comparable as in error_virtual_type2_alt4#A#bar.
diff --git a/tests/sav/error_virtual_type2_alt5.res b/tests/sav/error_virtual_type2_alt5.res
new file mode 100644 (file)
index 0000000..1efe3e7
--- /dev/null
@@ -0,0 +1,5 @@
+alt/error_virtual_type2_alt5.nit:22,2--24,13: Error: circularity of virtual type definition: GT -> T <-> U
+alt/error_virtual_type2_alt5.nit:25,2--30,10: Error: circularity of virtual type definition: T <-> U
+alt/error_virtual_type2_alt5.nit:38,23: Redef Error: Wrong return type. found T, expected Comparable as in error_virtual_type2_alt5#A#foo.
+alt/error_virtual_type2_alt5.nit:40,17--26: Redef Error: Wrong bound type. Found G[Discrete], expected a subtype of null, as in error_virtual_type2_alt5#A#GT.
+alt/error_virtual_type2_alt5.nit:42,23: Redef Error: Wrong return type. found T, expected Comparable as in error_virtual_type2_alt5#A#bar.
diff --git a/tests/sav/error_virtual_type2_alt6.res b/tests/sav/error_virtual_type2_alt6.res
new file mode 100644 (file)
index 0000000..6e05965
--- /dev/null
@@ -0,0 +1,2 @@
+alt/error_virtual_type2_alt6.nit:40,17--26: Redef Error: Wrong bound type. Found G[Discrete], expected a subtype of G[T], as in error_virtual_type2_alt6#A#GT.
+alt/error_virtual_type2_alt6.nit:41,2--22: Error: A property GT is already defined in class B at line 39.
diff --git a/tests/sav/error_virtual_type_alt1.res b/tests/sav/error_virtual_type_alt1.res
new file mode 100644 (file)
index 0000000..b87d6c0
--- /dev/null
@@ -0,0 +1 @@
+alt/error_virtual_type_alt1.nit:22,2--23,10: Error: circularity of virtual type definition: T <-> T
diff --git a/tests/sav/error_virtual_type_alt2.res b/tests/sav/error_virtual_type_alt2.res
new file mode 100644 (file)
index 0000000..98ff344
--- /dev/null
@@ -0,0 +1 @@
+alt/error_virtual_type_alt2.nit:22,2--24,19: Error: circularity of virtual type definition: T <-> nullable T
diff --git a/tests/sav/error_virtual_type_alt3.res b/tests/sav/error_virtual_type_alt3.res
new file mode 100644 (file)
index 0000000..1bad756
--- /dev/null
@@ -0,0 +1,2 @@
+alt/error_virtual_type_alt3.nit:25,12: Type error: expected Object, got T
+alt/error_virtual_type_alt3.nit:22,2--25,12: Error: circularity of virtual type definition: T <-> G[T]
diff --git a/tests/sav/error_virtual_type_alt4.res b/tests/sav/error_virtual_type_alt4.res
new file mode 100644 (file)
index 0000000..150aef7
--- /dev/null
@@ -0,0 +1 @@
+alt/error_virtual_type_alt4.nit:27,10--13: Type error: class FAIL not found in module error_virtual_type_alt4.
diff --git a/tests/sav/error_virtual_type_alt5.res b/tests/sav/error_virtual_type_alt5.res
new file mode 100644 (file)
index 0000000..84b89c9
--- /dev/null
@@ -0,0 +1 @@
+alt/error_virtual_type_alt5.nit:22,2--28,10: Error: circularity of virtual type definition: T <-> U
diff --git a/tests/sav/hello_ios.res b/tests/sav/hello_ios.res
new file mode 100644 (file)
index 0000000..90f398d
--- /dev/null
@@ -0,0 +1,4 @@
+out/hello_ios.bin
+out/hello_ios.bin/Info.plist
+out/hello_ios.bin/PkgInfo
+out/hello_ios.bin/hello_ios
diff --git a/tests/sav/nitg-e/base_notnull_lit.res b/tests/sav/nitg-e/base_notnull_lit.res
new file mode 100644 (file)
index 0000000..59ec579
--- /dev/null
@@ -0,0 +1,4 @@
+Array
+156
+Range
+12345
index 1fb7aeb..5789941 100644 (file)
@@ -1,4 +1,4 @@
-Runtime error: Cast failed. Expected `E`, got `Bool` (../lib/standard/collection/array.nit:909)
+Runtime error: Cast failed. Expected `E`, got `Bool` (../lib/standard/collection/array.nit:911)
 NativeString
 N
 Nit
index 36503ed..3e3247e 100644 (file)
@@ -475,7 +475,7 @@ Start ../src/test_parser.nit:17,1--147,1
                 AParExprs ../src/test_parser.nit:71,7--36
                   TOpar "(" ../src/test_parser.nit:71,7
                   AStringExpr ../src/test_parser.nit:71,8--35
-                    TString "\"  -n\11do not print anything\"" ../src/test_parser.nit:71,8--35
+                    TString "\"  -n\tdo not print anything\"" ../src/test_parser.nit:71,8--35
                   TCpar ")" ../src/test_parser.nit:71,36
               ACallExpr ../src/test_parser.nit:72,2--25
                 AImplicitSelfExpr ../src/test_parser.nit:72,2
@@ -483,7 +483,7 @@ Start ../src/test_parser.nit:17,1--147,1
                 AParExprs ../src/test_parser.nit:72,7--25
                   TOpar "(" ../src/test_parser.nit:72,7
                   AStringExpr ../src/test_parser.nit:72,8--24
-                    TString "\"  -l\11only lexer\"" ../src/test_parser.nit:72,8--24
+                    TString "\"  -l\tonly lexer\"" ../src/test_parser.nit:72,8--24
                   TCpar ")" ../src/test_parser.nit:72,25
               ACallExpr ../src/test_parser.nit:73,2--41
                 AImplicitSelfExpr ../src/test_parser.nit:73,2
@@ -491,7 +491,7 @@ Start ../src/test_parser.nit:17,1--147,1
                 AParExprs ../src/test_parser.nit:73,7--41
                   TOpar "(" ../src/test_parser.nit:73,7
                   AStringExpr ../src/test_parser.nit:73,8--40
-                    TString "\"  -p\11lexer and parser (default)\"" ../src/test_parser.nit:73,8--40
+                    TString "\"  -p\tlexer and parser (default)\"" ../src/test_parser.nit:73,8--40
                   TCpar ")" ../src/test_parser.nit:73,41
               ACallExpr ../src/test_parser.nit:74,2--68
                 AImplicitSelfExpr ../src/test_parser.nit:74,2
@@ -499,7 +499,7 @@ Start ../src/test_parser.nit:17,1--147,1
                 AParExprs ../src/test_parser.nit:74,7--68
                   TOpar "(" ../src/test_parser.nit:74,7
                   AStringExpr ../src/test_parser.nit:74,8--67
-                    TString "\"  -e\11instead on files, each argument is a content to parse\"" ../src/test_parser.nit:74,8--67
+                    TString "\"  -e\tinstead on files, each argument is a content to parse\"" ../src/test_parser.nit:74,8--67
                   TCpar ")" ../src/test_parser.nit:74,68
               ACallExpr ../src/test_parser.nit:75,2--51
                 AImplicitSelfExpr ../src/test_parser.nit:75,2
@@ -507,7 +507,7 @@ Start ../src/test_parser.nit:17,1--147,1
                 AParExprs ../src/test_parser.nit:75,7--51
                   TOpar "(" ../src/test_parser.nit:75,7
                   AStringExpr ../src/test_parser.nit:75,8--50
-                    TString "\"  -i\11tree to parse are read interactively\"" ../src/test_parser.nit:75,8--50
+                    TString "\"  -i\ttree to parse are read interactively\"" ../src/test_parser.nit:75,8--50
                   TCpar ")" ../src/test_parser.nit:75,51
               ACallExpr ../src/test_parser.nit:76,2--30
                 AImplicitSelfExpr ../src/test_parser.nit:76,2
@@ -515,7 +515,7 @@ Start ../src/test_parser.nit:17,1--147,1
                 AParExprs ../src/test_parser.nit:76,7--30
                   TOpar "(" ../src/test_parser.nit:76,7
                   AStringExpr ../src/test_parser.nit:76,8--29
-                    TString "\"  -h\11print this help\"" ../src/test_parser.nit:76,8--29
+                    TString "\"  -h\tprint this help\"" ../src/test_parser.nit:76,8--29
                   TCpar ")" ../src/test_parser.nit:76,30
             AIfExpr ../src/test_parser.nit:77,6--146,3
               TKwif "if" ../src/test_parser.nit:77,6--7
diff --git a/tests/sav/test_platform_ios.res b/tests/sav/test_platform_ios.res
new file mode 100644 (file)
index 0000000..3c5611a
--- /dev/null
@@ -0,0 +1,4 @@
+out/test_platform_ios.bin
+out/test_platform_ios.bin/Info.plist
+out/test_platform_ios.bin/PkgInfo
+out/test_platform_ios.bin/test_platform_ios
diff --git a/tests/sav/threaded_example.res b/tests/sav/threaded_example.res
new file mode 100644 (file)
index 0000000..050d79d
--- /dev/null
@@ -0,0 +1,2 @@
+main
+threaded
diff --git a/tests/test_platform_ios.nit b/tests/test_platform_ios.nit
new file mode 100644 (file)
index 0000000..b49f379
--- /dev/null
@@ -0,0 +1,15 @@
+# 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 ios
diff --git a/tests/testosx.sh b/tests/testosx.sh
new file mode 100755 (executable)
index 0000000..8976424
--- /dev/null
@@ -0,0 +1,21 @@
+#!/bin/bash
+# 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 to run on OS X for the host platform and iOS
+./tests.sh $@ \
+       test_ffi_objc_*.nit \
+       test_*ios.nit \
+       ../lib/ios/examples/*.nit \
+       ../lib/cocoa*/examples/*.nit
index 6c76366..ead5484 100755 (executable)
@@ -69,7 +69,9 @@ saferun()
                        *) stop=true
                esac
        done
-       if test -n "$TIME"; then
+       if test -d "$1"; then
+               find $1 | sort
+       elif test -n "$TIME"; then
                $TIME -o "$o" $a $TIMEOUT "$@"
        else
                if test -n "$a"; then echo 0 >> "$o"; else echo 0 > "$o"; fi