From: Jean Privat Date: Thu, 9 Apr 2015 05:24:37 +0000 (+0700) Subject: Merge: new `with` statement X-Git-Tag: v0.7.4~35 X-Git-Url: http://nitlanguage.org?hp=b91a577877b272d8aa29d1e402927490e6cc1baa Merge: new `with` statement 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 Reviewed-by: Etienne M. Gagnon Reviewed-by: Lucas Bajolet --- diff --git a/VERSION b/VERSION index 2c0a9c7..3d105a6 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -v0.7.2 +v0.7.3 diff --git a/benchmarks/bench_engines.sh b/benchmarks/bench_engines.sh index 62d6a9c..ae91703 100755 --- a/benchmarks/bench_engines.sh +++ b/benchmarks/bench_engines.sh @@ -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 index 0000000..ada48ff --- /dev/null +++ b/benchmarks/markdown/.gitignore @@ -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 index 0000000..802fab6 --- /dev/null +++ b/benchmarks/markdown/Makefile @@ -0,0 +1,21 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +all: + ./bench_markdown.sh all + +clean: + $(MAKE) clean -C benches + $(MAKE) clean -C engines + rm -rf out/ diff --git a/benchmarks/markdown/README.md b/benchmarks/markdown/README.md index a739cd8..29219c5 100644 --- a/benchmarks/markdown/README.md +++ b/benchmarks/markdown/README.md @@ -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 diff --git a/benchmarks/markdown/bench_markdown.sh b/benchmarks/markdown/bench_markdown.sh index 4cb0f15..aaa34f0 100755 --- a/benchmarks/markdown/bench_markdown.sh +++ b/benchmarks/markdown/bench_markdown.sh @@ -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 diff --git a/benchmarks/markdown/benches/Makefile b/benchmarks/markdown/benches/Makefile index 641c47e..4cb8c36 100644 --- a/benchmarks/markdown/benches/Makefile +++ b/benchmarks/markdown/benches/Makefile @@ -14,10 +14,12 @@ # 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 diff --git a/benchmarks/markdown/engines/Makefile b/benchmarks/markdown/engines/Makefile index 588e744..7301d01 100644 --- a/benchmarks/markdown/engines/Makefile +++ b/benchmarks/markdown/engines/Makefile @@ -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 diff --git a/benchmarks/markdown/engines/nitmd/Makefile b/benchmarks/markdown/engines/nitmd/Makefile index aa79fbc..256ddfe 100644 --- a/benchmarks/markdown/engines/nitmd/Makefile +++ b/benchmarks/markdown/engines/nitmd/Makefile @@ -14,11 +14,19 @@ # 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 index 0000000..ca4a354 --- /dev/null +++ b/benchmarks/markdown/engines/pandoc/Makefile @@ -0,0 +1,27 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Copyright 2015 Alexandre Terrasa +# +# 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 index 0000000..5c5db42 --- /dev/null +++ b/benchmarks/markdown/engines/pandoc/pandoc.hs @@ -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 index 0000000..0e224dc --- /dev/null +++ b/benchmarks/strings/.gitignore @@ -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 index 0000000..a6d89bf --- /dev/null +++ b/benchmarks/strings/Makefile @@ -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 index 0000000..b87b981 --- /dev/null +++ b/benchmarks/strings/README.md @@ -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. diff --git a/benchmarks/strings/array_to_s_vars/array_to_s_buffer.nit b/benchmarks/strings/array_to_s_vars/array_to_s_buffer.nit index d61b742..f18ece7 100644 --- a/benchmarks/strings/array_to_s_vars/array_to_s_buffer.nit +++ b/benchmarks/strings/array_to_s_vars/array_to_s_buffer.nit @@ -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 diff --git a/benchmarks/strings/array_to_s_vars/array_to_s_flatstr.nit b/benchmarks/strings/array_to_s_vars/array_to_s_flatstr.nit index 0240d5b..7028e3f 100644 --- a/benchmarks/strings/array_to_s_vars/array_to_s_flatstr.nit +++ b/benchmarks/strings/array_to_s_vars/array_to_s_flatstr.nit @@ -13,6 +13,27 @@ # 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 diff --git a/benchmarks/strings/array_to_s_vars/array_to_s_man_buf.nit b/benchmarks/strings/array_to_s_vars/array_to_s_man_buf.nit index ec81322..c5dbd00 100644 --- a/benchmarks/strings/array_to_s_vars/array_to_s_man_buf.nit +++ b/benchmarks/strings/array_to_s_vars/array_to_s_man_buf.nit @@ -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 diff --git a/benchmarks/strings/array_to_s_vars/array_to_s_rope.nit b/benchmarks/strings/array_to_s_vars/array_to_s_rope.nit index c162dff..9f86a8a 100644 --- a/benchmarks/strings/array_to_s_vars/array_to_s_rope.nit +++ b/benchmarks/strings/array_to_s_vars/array_to_s_rope.nit @@ -13,19 +13,21 @@ # 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 index 0000000..c7e3e7b --- /dev/null +++ b/benchmarks/strings/array_to_s_vars/array_to_s_rope_buf.nit @@ -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 diff --git a/benchmarks/bench_strings.sh b/benchmarks/strings/bench_strings.sh similarity index 53% rename from benchmarks/bench_strings.sh rename to benchmarks/strings/bench_strings.sh index 16992e9..a710dc0 100755 --- a/benchmarks/bench_strings.sh +++ b/benchmarks/strings/bench_strings.sh @@ -13,12 +13,12 @@ # 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 diff --git a/benchmarks/strings/chain_concat.nit b/benchmarks/strings/chain_concat.nit index a45075f..a70dd14 100644 --- a/benchmarks/strings/chain_concat.nit +++ b/benchmarks/strings/chain_concat.nit @@ -11,35 +11,78 @@ # 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 diff --git a/benchmarks/strings/iteration_bench.nit b/benchmarks/strings/iteration_bench.nit index 0e36c49..b37ad26 100644 --- a/benchmarks/strings/iteration_bench.nit +++ b/benchmarks/strings/iteration_bench.nit @@ -12,16 +12,33 @@ 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) diff --git a/benchmarks/strings/substr_bench.nit b/benchmarks/strings/substr_bench.nit index effb9ec..3727960 100644 --- a/benchmarks/strings/substr_bench.nit +++ b/benchmarks/strings/substr_bench.nit @@ -12,15 +12,16 @@ 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 index d720403..0000000 --- a/benchmarks/strings/utf_chain_concat.nit +++ /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 index 80277c0..0000000 --- a/benchmarks/strings/utf_iteration_bench.nit +++ /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 index 7d71a8b..0000000 --- a/benchmarks/strings/utf_substr_bench.nit +++ /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 index 0000000..45a278a --- /dev/null +++ b/bin/Makefile @@ -0,0 +1,27 @@ +# Copyright 2013 Alexandre Terrasa . +# +# 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 diff --git a/contrib/benitlux/src/benitlux_daily.nit b/contrib/benitlux/src/benitlux_daily.nit index 35aa64c..bb6d1fa 100644 --- a/contrib/benitlux/src/benitlux_daily.nit +++ b/contrib/benitlux/src/benitlux_daily.nit @@ -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) diff --git a/contrib/pep8analysis/src/flow_analysis/framework.nit b/contrib/pep8analysis/src/flow_analysis/framework.nit index e32246c..338836b 100644 --- a/contrib/pep8analysis/src/flow_analysis/framework.nit +++ b/contrib/pep8analysis/src/flow_analysis/framework.nit @@ -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) diff --git a/examples/calculator/src/calculator_android.nit b/examples/calculator/src/calculator_android.nit index ec7b374..1b1e686 100644 --- a/examples/calculator/src/calculator_android.nit +++ b/examples/calculator/src/calculator_android.nit @@ -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"""" diff --git a/examples/mnit_dino/src/dino_android.nit b/examples/mnit_dino/src/dino_android.nit index aac6d47..be92d49 100644 --- a/examples/mnit_dino/src/dino_android.nit +++ b/examples/mnit_dino/src/dino_android.nit @@ -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 diff --git a/examples/mnit_simple/src/complete_simple_android.nit b/examples/mnit_simple/src/complete_simple_android.nit index 8700ab2..f8cff4f 100644 --- a/examples/mnit_simple/src/complete_simple_android.nit +++ b/examples/mnit_simple/src/complete_simple_android.nit @@ -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 diff --git a/lib/ai/examples/puzzle.nit b/lib/ai/examples/puzzle.nit index 83c4b4c..0583035 100644 --- a/lib/ai/examples/puzzle.nit +++ b/lib/ai/examples/puzzle.nit @@ -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 diff --git a/lib/ai/search.nit b/lib/ai/search.nit index 69b5c0d..f406949 100644 --- a/lib/ai/search.nit +++ b/lib/ai/search.nit @@ -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 diff --git a/lib/android/README.md b/lib/android/README.md index 41f4830..fb11c65 100644 --- a/lib/android/README.md +++ b/lib/android/README.md @@ -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}`. diff --git a/lib/android/aware.nit b/lib/android/aware.nit index bb512d2..fec387d 100644 --- a/lib/android/aware.nit +++ b/lib/android/aware.nit @@ -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 diff --git a/lib/android/examples/src/ui_test.nit b/lib/android/examples/src/ui_test.nit index f6c2a1b..bdb06c5 100644 --- a/lib/android/examples/src/ui_test.nit +++ b/lib/android/examples/src/ui_test.nit @@ -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 diff --git a/lib/app/app_base.nit b/lib/app/app_base.nit index a528d57..f892033 100644 --- a/lib/app/app_base.nit +++ b/lib/app/app_base.nit @@ -16,6 +16,7 @@ module app_base is new_annotation app_name + new_annotation app_namespace new_annotation app_version end diff --git a/lib/geometry/points_and_lines.nit b/lib/geometry/points_and_lines.nit index 14a67fb..303aae1 100644 --- a/lib/geometry/points_and_lines.nit +++ b/lib/geometry/points_and_lines.nit @@ -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}" diff --git a/lib/github/github_curl.nit b/lib/github/github_curl.nit index cc12923..8e70600 100644 --- a/lib/github/github_curl.nit +++ b/lib/github/github_curl.nit @@ -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 index 0000000..66befa3 --- /dev/null +++ b/lib/html/bootstrap.nit @@ -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 `` 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 == "Nit" +# ~~~ +# +# Creates a link with a title attribute: +# ~~~ +# lnk = new Link.with_title("http://nitlanguage.org", "Nit", "Nit homepage") +# assert lnk.write_to_string == "Nit" +# ~~~ +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 "{text}" + end +end + +# A `

` to `

` 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 == "

Title

" +# ~~~ +# +# With subtext: +# ~~~ +# var h6 = new Header.with_subtext(6, "Title", "with subtext") +# assert h6.write_to_string == "
Titlewith subtext
" +# ~~~ +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 "{text.write_to_string}" + if subtext != null then add "{subtext.write_to_string}" + add "" + 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 `
  • ` 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 `
      ` 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 == """ +#
        +#
      1. foo
      2. +#
      3. bar
      4. +#
      5. baz
      6. +#
      +# """ +# ~~~ +class OrderedList + super HTMLList + + redef fun rendering do + addn "" + for item in items do add item + addn "
    " + end +end + +# A `
      ` 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 == """ +#
        +#
      • foo
      • +#
      • bar
      • +#
      • baz
      • +#
      +# """ +# ~~~ +class UnorderedList + super HTMLList + + redef fun rendering do + addn "" + for item in items do add item + addn "
    " + end +end + +# A `
  • ` tag. +class ListItem + super BSComponent + + # Content to display in this list item. + var text: Writable is writable + + redef fun rendering do addn "{text.write_to_string}
  • " +end + +# A Boostrap icon. +# +# See http://getbootstrap.com/components/#glyphicons +# +# Example: +# +# ~~~ +# var icon = new BSIcon("star") +# assert icon.write_to_string == "" +# ~~~ +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 "" + 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 == """ +#
      +#
    1. foo
    2. +#
    3. bar
    4. +#
    5. baz
    6. +#
    +# """ +# ~~~ +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 == "Danger!" +# ~~~ +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 "{text.write_to_string}" + end +end + +# A Bootstrap badge component. +# +# See http://getbootstrap.com/components/#badges +# +# Example: +# +# ~~~ +# var b = new BSBadge("42 messages") +# assert b.write_to_string == "42 messages" +# ~~~ +class BSBadge + super BSComponent + + # Text to display in the label. + var text: Writable + + init do css_classes.add "badge" + + redef fun rendering do + add "{text.write_to_string}" + 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 == """ +#
    +# Welcome +#
    +# """ +# ~~~ +class BSPageHeader + super BSComponent + + # Text to display as title. + var text: Writable + + init do css_classes.add "page-header" + + redef fun rendering do + addn "" + addn text.write_to_string + addn "" + end +end + +# A Bootstrap alert component. +# +# See http://getbootstrap.com/components/#alerts +# +# Example: +# +# ~~~ +# var alert = new BSAlert("danger", "Danger!") +# assert alert.write_to_string == """ +#
    +# Danger! +#
    +# """ +# ~~~ +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 "" + if is_dismissible then + add "" + end + addn text.write_to_string + addn "" + 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 == """ +#
    +#
    +# Panel content +#
    +#
    +# """ +# ~~~ +# +# Panel with heading: +# +# ~~~ +# p = new BSPanel("danger", "Panel content") +# p.heading = "Panel heading" +# +# assert p.write_to_string == """ +#
    +#
    +# Panel heading +#
    +#
    +# Panel content +#
    +#
    +# """ +# ~~~ +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 "" + if heading != null then + addn "
    " + addn heading.write_to_string + addn "
    " + end + addn "
    " + addn body.write_to_string + addn "
    " + if footer != null then + addn "
    " + addn footer.write_to_string + addn "
    " + end + addn "" + end +end diff --git a/lib/ios/app.nit b/lib/ios/app.nit new file mode 100644 index 0000000..0e337bc --- /dev/null +++ b/lib/ios/app.nit @@ -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 + + // Our interface to the iOS system + @interface AppDelegate: UIResponder + + // 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 index 0000000..3269906 --- /dev/null +++ b/lib/ios/examples/hello_ios.nit @@ -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 index 0000000..9d5079d --- /dev/null +++ b/lib/ios/ios.nit @@ -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 index 0000000..47d1536 --- /dev/null +++ b/lib/ios/platform.nit @@ -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/privileges.nit b/lib/privileges/privileges.nit similarity index 100% rename from lib/privileges.nit rename to lib/privileges/privileges.nit diff --git a/lib/pthreads/examples/threaded_example.nit b/lib/pthreads/examples/threaded_example.nit new file mode 100644 index 0000000..175c753 --- /dev/null +++ b/lib/pthreads/examples/threaded_example.nit @@ -0,0 +1,30 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Copyright 2015 Romain Chanoir +# +# 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) diff --git a/lib/pthreads/pthreads.nit b/lib/pthreads/pthreads.nit index 5d6b80d..8b8de1f 100644 --- a/lib/pthreads/pthreads.nit +++ b/lib/pthreads/pthreads.nit @@ -19,6 +19,7 @@ module pthreads is cflags "-pthread" ldflags "-pthread" pkgconfig "bdw-gc" + new_annotation threaded end # diff --git a/lib/standard/collection/abstract_collection.nit b/lib/standard/collection/abstract_collection.nit index d51e710..1b1e71e 100644 --- a/lib/standard/collection/abstract_collection.nit +++ b/lib/standard/collection/abstract_collection.nit @@ -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 diff --git a/lib/standard/collection/array.nit b/lib/standard/collection/array.nit index 233621e..3cc0b57 100644 --- a/lib/standard/collection/array.nit +++ b/lib/standard/collection/array.nit @@ -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 diff --git a/lib/standard/collection/sorter.nit b/lib/standard/collection/sorter.nit index cfcc376..00c45a3 100644 --- a/lib/standard/collection/sorter.nit +++ b/lib/standard/collection/sorter.nit @@ -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 diff --git a/lib/standard/collection/union_find.nit b/lib/standard/collection/union_find.nit index 4df80b5..12c9c86 100644 --- a/lib/standard/collection/union_find.nit +++ b/lib/standard/collection/union_find.nit @@ -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] diff --git a/lib/standard/exec_nit.c b/lib/standard/exec_nit.c index 5b5ffbb..93f5f9b 100644 --- a/lib/standard/exec_nit.c +++ b/lib/standard/exec_nit.c @@ -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; } diff --git a/lib/standard/file.nit b/lib/standard/file.nit index a2856ae..81341ad 100644 --- a/lib/standard/file.nit +++ b/lib/standard/file.nit @@ -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 diff --git a/lib/standard/string.nit b/lib/standard/string.nit index 4892f95..409b4ed 100644 --- a/lib/standard/string.nit +++ b/lib/standard/string.nit @@ -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 diff --git a/lib/template/examples/tmpl_composer.nit b/lib/template/examples/tmpl_composer.nit index 6160b1a..3150c5f 100644 --- a/lib/template/examples/tmpl_composer.nit +++ b/lib/template/examples/tmpl_composer.nit @@ -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}}} diff --git a/src/compiler/abstract_compiler.nit b/src/compiler/abstract_compiler.nit index 658f0e7..3956744 100644 --- a/src/compiler/abstract_compiler.nit +++ b/src/compiler/abstract_compiler.nit @@ -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 ") self.header.add_decl("#include ") self.header.add_decl("#include ") + self.header.add_decl("#include \n") + self.header.add_decl("#include \n") self.header.add_decl("#include \"gc_chooser.h\"") self.header.add_decl("#ifdef ANDROID") self.header.add_decl(" #include ") @@ -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 diff --git a/src/compiler/coloring.nit b/src/compiler/coloring.nit index b2f4837..e2afc48 100644 --- a/src/compiler/coloring.nit +++ b/src/compiler/coloring.nit @@ -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 diff --git a/src/compiler/compiler.nit b/src/compiler/compiler.nit index ea60c0a..c013295 100644 --- a/src/compiler/compiler.nit +++ b/src/compiler/compiler.nit @@ -22,3 +22,4 @@ import compiler_ffi import platform::android import platform::pnacl import platform::emscripten +import platform::ios diff --git a/src/compiler/separate_compiler.nit b/src/compiler/separate_compiler.nit index ecfcc8e..34e7be4 100644 --- a/src/compiler/separate_compiler.nit +++ b/src/compiler/separate_compiler.nit @@ -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 diff --git a/src/compiler/separate_erasure_compiler.nit b/src/compiler/separate_erasure_compiler.nit index 2a7f0fa..b8b2c0a 100644 --- a/src/compiler/separate_erasure_compiler.nit +++ b/src/compiler/separate_erasure_compiler.nit @@ -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("\}") diff --git a/src/doc/doc_base.nit b/src/doc/doc_base.nit index e947ee2..64b2022 100644 --- a/src/doc/doc_base.nit +++ b/src/doc/doc_base.nit @@ -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 diff --git a/src/doc/doc_phases/doc_graphs.nit b/src/doc/doc_phases/doc_graphs.nit index aff25d4..66ef564 100644 --- a/src/doc/doc_phases/doc_graphs.nit +++ b/src/doc/doc_phases/doc_graphs.nit @@ -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 diff --git a/src/doc/doc_phases/doc_hierarchies.nit b/src/doc/doc_phases/doc_hierarchies.nit index 39ad273..23da906 100644 --- a/src/doc/doc_phases/doc_hierarchies.nit +++ b/src/doc/doc_phases/doc_hierarchies.nit @@ -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 diff --git a/src/doc/doc_phases/doc_html.nit b/src/doc/doc_phases/doc_html.nit index a11e187..7d38bc0 100644 --- a/src/doc/doc_phases/doc_html.nit +++ b/src/doc/doc_phases/doc_html.nit @@ -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 "" 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 diff --git a/src/doc/doc_phases/doc_structure.nit b/src/doc/doc_phases/doc_structure.nit index 1e0d773..9c32c8c 100644 --- a/src/doc/doc_phases/doc_structure.nit +++ b/src/doc/doc_phases/doc_structure.nit @@ -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. diff --git a/src/doc/html_templates/html_components.nit b/src/doc/html_templates/html_components.nit index c3126f7..e65059b 100644 --- a/src/doc/html_templates/html_components.nit +++ b/src/doc/html_templates/html_components.nit @@ -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 `
  • ` tags - fun add_item(content: Writable, is_active: Bool) do - var tpl = new Template - tpl.add "" - tpl.add content - tpl.addn "
  • " - 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 "" - end -end - # A sidebar template class TplSidebar super Template diff --git a/src/doc/html_templates/html_model.nit b/src/doc/html_templates/html_model.nit index 15b2963..2908fad 100644 --- a/src/doc/html_templates/html_model.nit +++ b/src/doc/html_templates/html_model.nit @@ -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 diff --git a/src/doc/html_templates/html_templates.nit b/src/doc/html_templates/html_templates.nit index 83c1842..53fc0cf 100644 --- a/src/doc/html_templates/html_templates.nit +++ b/src/doc/html_templates/html_templates.nit @@ -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 "
    " - add topmenu - addn "
    " - 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 "
    " - render_topmenu + addn "
    " + add topmenu + addn "
    " addn "
    " if sidebar != null then addn "
    " @@ -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 "" + end +end diff --git a/src/ffi/extern_classes.nit b/src/ffi/extern_classes.nit index bc4f0c4..4e8f45d 100644 --- a/src/ffi/extern_classes.nit +++ b/src/ffi/extern_classes.nit @@ -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 diff --git a/src/frontend/check_annotation.nit b/src/frontend/check_annotation.nit index 36244f6..ffba4ad 100644 --- a/src/frontend/check_annotation.nit +++ b/src/frontend/check_annotation.nit @@ -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) diff --git a/src/frontend/div_by_zero.nit b/src/frontend/div_by_zero.nit index 4a8cfb4..6001f01 100644 --- a/src/frontend/div_by_zero.nit +++ b/src/frontend/div_by_zero.nit @@ -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) diff --git a/src/frontend/frontend.nit b/src/frontend/frontend.nit index 9d39890..28e36bd 100644 --- a/src/frontend/frontend.nit +++ b/src/frontend/frontend.nit @@ -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 diff --git a/src/frontend/no_warning.nit b/src/frontend/no_warning.nit index 931440e..bc59d8c 100644 --- a/src/frontend/no_warning.nit +++ b/src/frontend/no_warning.nit @@ -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 index 0000000..7da80ff --- /dev/null +++ b/src/frontend/parallelization_phase.nit @@ -0,0 +1,110 @@ +# This file is part of NIT ( http://www.nitlanguage.org ). +# +# Copyright 2015 Romain Chanoir +# +# 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 diff --git a/src/frontend/serialization_phase.nit b/src/frontend/serialization_phase.nit index 2b68eea..0d7e4ec 100644 --- a/src/frontend/serialization_phase.nit +++ b/src/frontend/serialization_phase.nit @@ -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 diff --git a/src/highlight.nit b/src/highlight.nit index ecc4c7d..39a042a 100644 --- a/src/highlight.nit +++ b/src/highlight.nit @@ -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) diff --git a/src/interpreter/naive_interpreter.nit b/src/interpreter/naive_interpreter.nit index 21118ab..272219f 100644 --- a/src/interpreter/naive_interpreter.nit +++ b/src/interpreter/naive_interpreter.nit @@ -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]) diff --git a/src/loader.nit b/src/loader.nit index 492584b..9876bc4 100644 --- a/src/loader.nit +++ b/src/loader.nit @@ -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 diff --git a/src/metrics/detect_covariance.nit b/src/metrics/detect_covariance.nit index dd7c36d..9090658 100644 --- a/src/metrics/detect_covariance.nit +++ b/src/metrics/detect_covariance.nit @@ -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 diff --git a/src/metrics/detect_variance_constraints.nit b/src/metrics/detect_variance_constraints.nit index 3665376..1f0205e 100644 --- a/src/metrics/detect_variance_constraints.nit +++ b/src/metrics/detect_variance_constraints.nit @@ -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] diff --git a/src/metrics/rta_metrics.nit b/src/metrics/rta_metrics.nit index 1527731..00f9d02 100644 --- a/src/metrics/rta_metrics.nit +++ b/src/metrics/rta_metrics.nit @@ -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 diff --git a/src/model/mmodule.nit b/src/model/mmodule.nit index d88a0ba..ef548a8 100644 --- a/src/model/mmodule.nit +++ b/src/model/mmodule.nit @@ -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 diff --git a/src/model/model.nit b/src/model/model.nit index 3a64638..62c3db4 100644 --- a/src/model/model.nit +++ b/src/model/model.nit @@ -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} {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 diff --git a/src/nitdbg_client.nit b/src/nitdbg_client.nit index 349f53c..b12e1e9 100644 --- a/src/nitdbg_client.nit +++ b/src/nitdbg_client.nit @@ -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}" diff --git a/src/nitni/nitni_callbacks.nit b/src/nitni/nitni_callbacks.nit index f53466c..210a4b5 100644 --- a/src/nitni/nitni_callbacks.nit +++ b/src/nitni/nitni_callbacks.nit @@ -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 index 0000000..50e6ab8 --- /dev/null +++ b/src/parser/.gitignore @@ -0,0 +1,5 @@ +*.class +org/nitlanguage/gen/analysis/ +org/nitlanguage/gen/lexer/ +org/nitlanguage/gen/node/ +org/nitlanguage/gen/parser/ diff --git a/src/parser/Makefile b/src/parser/Makefile index db69b26..04657cc 100644 --- a/src/parser/Makefile +++ b/src/parser/Makefile @@ -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 diff --git a/src/parser/README.md b/src/parser/README.md index 29b46bc..64ceecf 100644 --- a/src/parser/README.md +++ b/src/parser/README.md @@ -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 index 0000000..06ec83f --- /dev/null +++ b/src/parser/org/nitlanguage/gen/TestParser.java @@ -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; i127. + 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); + } + } +} diff --git a/src/phase.nit b/src/phase.nit index bdec532..502d817 100644 --- a/src/phase.nit +++ b/src/phase.nit @@ -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` diff --git a/src/platform/android.nit b/src/platform/android.nit index e2db002..404d780 100644 --- a/src/platform/android.nit +++ b/src/platform/android.nit @@ -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("-", "_") diff --git a/src/platform/android_annotations.nit b/src/platform/android_annotations.nit index 717c6ae..347c4dc 100644 --- a/src/platform/android_annotations.nit +++ b/src/platform/android_annotations.nit @@ -14,29 +14,14 @@ # 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 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 index 0000000..67af354 --- /dev/null +++ b/src/platform/app_annotations.nit @@ -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 diff --git a/src/platform/emscripten.nit b/src/platform/emscripten.nit index 3e9199a..90e361e 100644 --- a/src/platform/emscripten.nit +++ b/src/platform/emscripten.nit @@ -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 index 0000000..f81b5d2 --- /dev/null +++ b/src/platform/ios.nit @@ -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 diff --git a/src/platform/pnacl.nit b/src/platform/pnacl.nit index d7103db..8136187 100644 --- a/src/platform/pnacl.nit +++ b/src/platform/pnacl.nit @@ -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 index 0000000..e4ebbdf --- /dev/null +++ b/src/platform/xcode_templates.nit @@ -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 = ""; + }; +""" + + 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 = ""; + }; + AF9F83DE1A5F0D21004B62C0 /* Base */ = { + isa = PBXFileReference; + lastKnownFileType = file.storyboard; + name = Base; + path = Base.lproj/Main.storyboard; + sourceTree = ""; + }; + AF9F83E01A5F0D21004B62C0 /* Images.xcassets */ = { + isa = PBXFileReference; + lastKnownFileType = folder.assetcatalog; + path = Images.xcassets; + sourceTree = ""; + }; + AF9F83E31A5F0D21004B62C0 /* Base */ = { + isa = PBXFileReference; + lastKnownFileType = file.xib; + name = Base; + path = Base.lproj/LaunchScreen.xib; + sourceTree = ""; + }; + 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 = ""; + }; + AF9F83EF1A5F0D21004B62C0 /* {{{name}}}Tests.m */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = {{{name}}}Tests.m; + sourceTree = ""; + }; + + /* 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 = ""; + }; + AF9F83CD1A5F0D21004B62C0 /* Products */ = { + isa = PBXGroup; + children = ( + AF9F83CC1A5F0D21004B62C0 /* {{{name}}}.app */, + AF9F83E91A5F0D21004B62C0 /* {{{name}}}Tests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + AF9F83CE1A5F0D21004B62C0 /* {{{name}}} */ = { + isa = PBXGroup; + children = ( +""" + # Reference all known files + for file in files do add """ + {{{file.ref_uuid}}} /* {{{file.doc}}} */, +""" + + add """ + ); + path = {{{name}}}; + sourceTree = ""; + }; + AF9F83CF1A5F0D21004B62C0 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + AF9F83D01A5F0D21004B62C0 /* Info.plist */, + AF9F83D11A5F0D21004B62C0 /* main.m */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + AF9F83EC1A5F0D21004B62C0 /* {{{name}}}Tests */ = { + isa = PBXGroup; + children = ( + AF9F83EF1A5F0D21004B62C0 /* {{{name}}}Tests.m */, + AF9F83ED1A5F0D21004B62C0 /* Supporting Files */, + ); + path = {{{name}}}Tests; + sourceTree = ""; + }; + AF9F83ED1A5F0D21004B62C0 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + AF9F83EE1A5F0D21004B62C0 /* Info.plist */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* 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 = ""; + }; + AF9F83E21A5F0D21004B62C0 /* LaunchScreen.xib */ = { + isa = PBXVariantGroup; + children = ( + AF9F83E31A5F0D21004B62C0 /* Base */, + ); + name = LaunchScreen.xib; + sourceTree = ""; + }; +/* 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 """ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + {{{bundle_identifier}}} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + {{{product_name}}} + CFBundlePackageType + APPL + CFBundleShortVersionString + {{{short_version}}} + CFBundleSignature + \\?\\?\\?\\? + CFBundleVersion + {{{bundle_version}}} + LSRequiresIPhoneOS + + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + +""" + end +end diff --git a/src/rapid_type_analysis.nit b/src/rapid_type_analysis.nit index 69e9023..73cc176 100644 --- a/src/rapid_type_analysis.nit +++ b/src/rapid_type_analysis.nit @@ -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 diff --git a/src/semantize/auto_super_init.nit b/src/semantize/auto_super_init.nit index d60e2a3..07b4f46 100644 --- a/src/semantize/auto_super_init.nit +++ b/src/semantize/auto_super_init.nit @@ -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 diff --git a/src/semantize/typing.nit b/src/semantize/typing.nit index 15d38a2..cf8bbda 100644 --- a/src/semantize/typing.nit +++ b/src/semantize/typing.nit @@ -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 diff --git a/src/test_phase.nit b/src/test_phase.nit index 8fd5908..767cf95 100644 --- a/src/test_phase.nit +++ b/src/test_phase.nit @@ -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) diff --git a/src/toolcontext.nit b/src/toolcontext.nit index 62c184a..92a4824 100644 --- a/src/toolcontext.nit +++ b/src/toolcontext.nit @@ -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 diff --git a/src/vm/virtual_machine.nit b/src/vm/virtual_machine.nit index b33e7f8..9c3d516 100644 --- a/src/vm/virtual_machine.nit +++ b/src/vm/virtual_machine.nit @@ -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 diff --git a/tests/Linux.skip b/tests/Linux.skip index 609105e..8a90f1d 100644 --- a/tests/Linux.skip +++ b/tests/Linux.skip @@ -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 index 0000000..133aef1 --- /dev/null +++ b/tests/base_notnull.nit @@ -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 index 0000000..dae4e46 --- /dev/null +++ b/tests/base_notnull_lit.nit @@ -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 index 0000000..dd7243b --- /dev/null +++ b/tests/error_virtual_type.nit @@ -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 index 0000000..274bb77 --- /dev/null +++ b/tests/error_virtual_type2.nit @@ -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') diff --git a/tests/sav/base_as_notnull.res b/tests/sav/base_as_notnull.res index 2380a43..2324342 100644 --- a/tests/sav/base_as_notnull.res +++ b/tests/sav/base_as_notnull.res @@ -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 diff --git a/tests/sav/base_as_notnull2.res b/tests/sav/base_as_notnull2.res index b0818df..1962743 100644 --- a/tests/sav/base_as_notnull2.res +++ b/tests/sav/base_as_notnull2.res @@ -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 diff --git a/tests/sav/base_as_notnull2_alt1.res b/tests/sav/base_as_notnull2_alt1.res index 01ee624..b61957e 100644 --- a/tests/sav/base_as_notnull2_alt1.res +++ b/tests/sav/base_as_notnull2_alt1.res @@ -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 diff --git a/tests/sav/base_as_notnull2_alt2.res b/tests/sav/base_as_notnull2_alt2.res index e6335c5..4ac9e4e 100644 --- a/tests/sav/base_as_notnull2_alt2.res +++ b/tests/sav/base_as_notnull2_alt2.res @@ -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 diff --git a/tests/sav/base_as_notnull2_alt3.res b/tests/sav/base_as_notnull2_alt3.res index 4fb6e73..4a57748 100644 --- a/tests/sav/base_as_notnull2_alt3.res +++ b/tests/sav/base_as_notnull2_alt3.res @@ -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 diff --git a/tests/sav/base_as_notnull_alt1.res b/tests/sav/base_as_notnull_alt1.res index ad6b798..cbb18f8 100644 --- a/tests/sav/base_as_notnull_alt1.res +++ b/tests/sav/base_as_notnull_alt1.res @@ -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`. diff --git a/tests/sav/base_as_notnull_alt2.res b/tests/sav/base_as_notnull_alt2.res index 0e0e68c..c9dfed9 100644 --- a/tests/sav/base_as_notnull_alt2.res +++ b/tests/sav/base_as_notnull_alt2.res @@ -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`. diff --git a/tests/sav/base_as_notnull_alt3.res b/tests/sav/base_as_notnull_alt3.res index bd83530..d66632f 100644 --- a/tests/sav/base_as_notnull_alt3.res +++ b/tests/sav/base_as_notnull_alt3.res @@ -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 diff --git a/tests/sav/base_as_notnull_alt4.res b/tests/sav/base_as_notnull_alt4.res index 0050108..b25242f 100644 --- a/tests/sav/base_as_notnull_alt4.res +++ b/tests/sav/base_as_notnull_alt4.res @@ -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 diff --git a/tests/sav/base_as_notnull_alt5.res b/tests/sav/base_as_notnull_alt5.res index d8136e9..b52a40b 100644 --- a/tests/sav/base_as_notnull_alt5.res +++ b/tests/sav/base_as_notnull_alt5.res @@ -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 diff --git a/tests/sav/base_as_notnull_alt6.res b/tests/sav/base_as_notnull_alt6.res index 7083fa3..518f166 100644 --- a/tests/sav/base_as_notnull_alt6.res +++ b/tests/sav/base_as_notnull_alt6.res @@ -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 diff --git a/tests/sav/base_as_notnull_alt7.res b/tests/sav/base_as_notnull_alt7.res index 38f0903..6ad88ec 100644 --- a/tests/sav/base_as_notnull_alt7.res +++ b/tests/sav/base_as_notnull_alt7.res @@ -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 diff --git a/tests/sav/base_as_notnull_int.res b/tests/sav/base_as_notnull_int.res index 4635340..8b381a4 100644 --- a/tests/sav/base_as_notnull_int.res +++ b/tests/sav/base_as_notnull_int.res @@ -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 diff --git a/tests/sav/base_eq_null_notnull.res b/tests/sav/base_eq_null_notnull.res index b4226bc..faf4840 100644 --- a/tests/sav/base_eq_null_notnull.res +++ b/tests/sav/base_eq_null_notnull.res @@ -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 index 0000000..1b755df --- /dev/null +++ b/tests/sav/base_notnull.res @@ -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 index 0000000..925e389 --- /dev/null +++ b/tests/sav/base_notnull_1alt1.res @@ -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 index 0000000..8a63507 --- /dev/null +++ b/tests/sav/base_notnull_1alt1_alt1.res @@ -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 index 0000000..a316b82 --- /dev/null +++ b/tests/sav/base_notnull_1alt1_alt2.res @@ -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 index 0000000..d044957 --- /dev/null +++ b/tests/sav/base_notnull_1alt1_alt3.res @@ -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 index 0000000..b0f0ecd --- /dev/null +++ b/tests/sav/base_notnull_1alt1_alt4.res @@ -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 index 0000000..4a50aa8 --- /dev/null +++ b/tests/sav/base_notnull_alt1.res @@ -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 index 0000000..9450e83 --- /dev/null +++ b/tests/sav/base_notnull_alt2.res @@ -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 index 0000000..addd582 --- /dev/null +++ b/tests/sav/base_notnull_alt3.res @@ -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 index 0000000..d0db7c3 --- /dev/null +++ b/tests/sav/base_notnull_alt4.res @@ -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 index 0000000..dc19389 --- /dev/null +++ b/tests/sav/base_notnull_lit.res @@ -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 index 0000000..fac195d --- /dev/null +++ b/tests/sav/base_notnull_lit_alt1.res @@ -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 index 0000000..522489c --- /dev/null +++ b/tests/sav/base_notnull_lit_alt2.res @@ -0,0 +1 @@ +Runtime error: Assert failed (alt/base_notnull_lit_alt2.nit:19) diff --git a/tests/sav/base_null.res b/tests/sav/base_null.res index 80acf2a..814a7ef 100644 --- a/tests/sav/base_null.res +++ b/tests/sav/base_null.res @@ -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 diff --git a/tests/sav/base_upcast2_1alt1_alt10.res b/tests/sav/base_upcast2_1alt1_alt10.res index 99abb44..28f095a 100644 --- a/tests/sav/base_upcast2_1alt1_alt10.res +++ b/tests/sav/base_upcast2_1alt1_alt10.res @@ -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] diff --git a/tests/sav/base_upcast2_1alt1_alt7.res b/tests/sav/base_upcast2_1alt1_alt7.res index 29fe46d..15ba7c3 100644 --- a/tests/sav/base_upcast2_1alt1_alt7.res +++ b/tests/sav/base_upcast2_1alt1_alt7.res @@ -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] diff --git a/tests/sav/base_upcast2_1alt1_alt8.res b/tests/sav/base_upcast2_1alt1_alt8.res index 4f33a48..a7f751c 100644 --- a/tests/sav/base_upcast2_1alt1_alt8.res +++ b/tests/sav/base_upcast2_1alt1_alt8.res @@ -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] diff --git a/tests/sav/base_upcast2_1alt1_alt9.res b/tests/sav/base_upcast2_1alt1_alt9.res index 3191dca..98420d0 100644 --- a/tests/sav/base_upcast2_1alt1_alt9.res +++ b/tests/sav/base_upcast2_1alt1_alt9.res @@ -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] diff --git a/tests/sav/base_upcast2_1alt2_alt10.res b/tests/sav/base_upcast2_1alt2_alt10.res index 8d013a7..8ef15ac 100644 --- a/tests/sav/base_upcast2_1alt2_alt10.res +++ b/tests/sav/base_upcast2_1alt2_alt10.res @@ -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] diff --git a/tests/sav/base_upcast2_1alt2_alt6.res b/tests/sav/base_upcast2_1alt2_alt6.res index afb8ffe..016d020 100644 --- a/tests/sav/base_upcast2_1alt2_alt6.res +++ b/tests/sav/base_upcast2_1alt2_alt6.res @@ -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] diff --git a/tests/sav/base_upcast2_1alt2_alt8.res b/tests/sav/base_upcast2_1alt2_alt8.res index ab7c7d3..cdbac7a 100644 --- a/tests/sav/base_upcast2_1alt2_alt8.res +++ b/tests/sav/base_upcast2_1alt2_alt8.res @@ -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] diff --git a/tests/sav/base_upcast2_1alt2_alt9.res b/tests/sav/base_upcast2_1alt2_alt9.res index c687866..2b3c257 100644 --- a/tests/sav/base_upcast2_1alt2_alt9.res +++ b/tests/sav/base_upcast2_1alt2_alt9.res @@ -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] diff --git a/tests/sav/base_upcast2_1alt3_alt10.res b/tests/sav/base_upcast2_1alt3_alt10.res index b64929b..975c3fb 100644 --- a/tests/sav/base_upcast2_1alt3_alt10.res +++ b/tests/sav/base_upcast2_1alt3_alt10.res @@ -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] diff --git a/tests/sav/base_upcast2_1alt3_alt7.res b/tests/sav/base_upcast2_1alt3_alt7.res index b2aeba1..e44436b 100644 --- a/tests/sav/base_upcast2_1alt3_alt7.res +++ b/tests/sav/base_upcast2_1alt3_alt7.res @@ -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] diff --git a/tests/sav/base_upcast2_1alt3_alt9.res b/tests/sav/base_upcast2_1alt3_alt9.res index f6151ca..1f17f5f 100644 --- a/tests/sav/base_upcast2_1alt3_alt9.res +++ b/tests/sav/base_upcast2_1alt3_alt9.res @@ -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] diff --git a/tests/sav/base_upcast2_1alt4_alt10.res b/tests/sav/base_upcast2_1alt4_alt10.res index 7943796..37d0456 100644 --- a/tests/sav/base_upcast2_1alt4_alt10.res +++ b/tests/sav/base_upcast2_1alt4_alt10.res @@ -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] diff --git a/tests/sav/base_upcast2_1alt4_alt7.res b/tests/sav/base_upcast2_1alt4_alt7.res index 1ce4304..a9f7c8b 100644 --- a/tests/sav/base_upcast2_1alt4_alt7.res +++ b/tests/sav/base_upcast2_1alt4_alt7.res @@ -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] diff --git a/tests/sav/base_upcast2_1alt4_alt8.res b/tests/sav/base_upcast2_1alt4_alt8.res index a636739..821b826 100644 --- a/tests/sav/base_upcast2_1alt4_alt8.res +++ b/tests/sav/base_upcast2_1alt4_alt8.res @@ -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] diff --git a/tests/sav/base_upcast2_1alt5_alt7.res b/tests/sav/base_upcast2_1alt5_alt7.res index a670740..9d35793 100644 --- a/tests/sav/base_upcast2_1alt5_alt7.res +++ b/tests/sav/base_upcast2_1alt5_alt7.res @@ -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 diff --git a/tests/sav/base_upcast2_1alt5_alt8.res b/tests/sav/base_upcast2_1alt5_alt8.res index ce4fd54..5ce490d 100644 --- a/tests/sav/base_upcast2_1alt5_alt8.res +++ b/tests/sav/base_upcast2_1alt5_alt8.res @@ -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 diff --git a/tests/sav/base_var_type_evolution_null3.res b/tests/sav/base_var_type_evolution_null3.res index 46069e8..0025f05 100644 --- a/tests/sav/base_var_type_evolution_null3.res +++ b/tests/sav/base_var_type_evolution_null3.res @@ -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 diff --git a/tests/sav/base_var_type_evolution_null3_alt1.res b/tests/sav/base_var_type_evolution_null3_alt1.res index a10a5e3..5bc9b2d 100644 --- a/tests/sav/base_var_type_evolution_null3_alt1.res +++ b/tests/sav/base_var_type_evolution_null3_alt1.res @@ -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 diff --git a/tests/sav/base_virtual_type7.res b/tests/sav/base_virtual_type7.res index 0fc0245..01f9a2f 100644 --- a/tests/sav/base_virtual_type7.res +++ b/tests/sav/base_virtual_type7.res @@ -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 diff --git a/tests/sav/base_virtual_type_self_alt5.res b/tests/sav/base_virtual_type_self_alt5.res index 397a44a..44a485a 100644 --- a/tests/sav/base_virtual_type_self_alt5.res +++ b/tests/sav/base_virtual_type_self_alt5.res @@ -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]] diff --git a/tests/sav/error_expr_not_ok_alt4.res b/tests/sav/error_expr_not_ok_alt4.res index 01f96ed..d22055c 100644 --- a/tests/sav/error_expr_not_ok_alt4.res +++ b/tests/sav/error_expr_not_ok_alt4.res @@ -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 diff --git a/tests/sav/error_expr_not_ok_alt5.res b/tests/sav/error_expr_not_ok_alt5.res index 98e1d46..a6caca4 100644 --- a/tests/sav/error_expr_not_ok_alt5.res +++ b/tests/sav/error_expr_not_ok_alt5.res @@ -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 diff --git a/tests/sav/error_expr_not_ok_alt6.res b/tests/sav/error_expr_not_ok_alt6.res index efeddc2..c56e7b6 100644 --- a/tests/sav/error_expr_not_ok_alt6.res +++ b/tests/sav/error_expr_not_ok_alt6.res @@ -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 diff --git a/tests/sav/error_needed_method_alt4.res b/tests/sav/error_needed_method_alt4.res index 6f7a1f9..f80abe8 100644 --- a/tests/sav/error_needed_method_alt4.res +++ b/tests/sav/error_needed_method_alt4.res @@ -1 +1 @@ -Fatal Error: no primitive class NativeArray +Fatal Error: no primitive class NativeArray in error_needed_method_alt4 diff --git a/tests/sav/error_needed_method_alt7.res b/tests/sav/error_needed_method_alt7.res index 6f7a1f9..2a7c903 100644 --- a/tests/sav/error_needed_method_alt7.res +++ b/tests/sav/error_needed_method_alt7.res @@ -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 index 0000000..417f403 --- /dev/null +++ b/tests/sav/error_virtual_type2.res @@ -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 index 0000000..38cf3dd --- /dev/null +++ b/tests/sav/error_virtual_type2_alt1.res @@ -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 index 0000000..f155524 --- /dev/null +++ b/tests/sav/error_virtual_type2_alt2.res @@ -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 index 0000000..80c9981 --- /dev/null +++ b/tests/sav/error_virtual_type2_alt3.res @@ -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 index 0000000..158622e --- /dev/null +++ b/tests/sav/error_virtual_type2_alt4.res @@ -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 index 0000000..1efe3e7 --- /dev/null +++ b/tests/sav/error_virtual_type2_alt5.res @@ -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 index 0000000..6e05965 --- /dev/null +++ b/tests/sav/error_virtual_type2_alt6.res @@ -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 index 0000000..b87d6c0 --- /dev/null +++ b/tests/sav/error_virtual_type_alt1.res @@ -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 index 0000000..98ff344 --- /dev/null +++ b/tests/sav/error_virtual_type_alt2.res @@ -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 index 0000000..1bad756 --- /dev/null +++ b/tests/sav/error_virtual_type_alt3.res @@ -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 index 0000000..150aef7 --- /dev/null +++ b/tests/sav/error_virtual_type_alt4.res @@ -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 index 0000000..84b89c9 --- /dev/null +++ b/tests/sav/error_virtual_type_alt5.res @@ -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 index 0000000..90f398d --- /dev/null +++ b/tests/sav/hello_ios.res @@ -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 index 0000000..59ec579 --- /dev/null +++ b/tests/sav/nitg-e/base_notnull_lit.res @@ -0,0 +1,4 @@ +Array +156 +Range +12345 diff --git a/tests/sav/test_new_native_alt1.res b/tests/sav/test_new_native_alt1.res index 1fb7aeb..5789941 100644 --- a/tests/sav/test_new_native_alt1.res +++ b/tests/sav/test_new_native_alt1.res @@ -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 diff --git a/tests/sav/test_parser_args1.res b/tests/sav/test_parser_args1.res index 36503ed..3e3247e 100644 --- a/tests/sav/test_parser_args1.res +++ b/tests/sav/test_parser_args1.res @@ -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 index 0000000..3c5611a --- /dev/null +++ b/tests/sav/test_platform_ios.res @@ -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 index 0000000..050d79d --- /dev/null +++ b/tests/sav/threaded_example.res @@ -0,0 +1,2 @@ +main +threaded diff --git a/tests/test_platform_ios.nit b/tests/test_platform_ios.nit new file mode 100644 index 0000000..b49f379 --- /dev/null +++ b/tests/test_platform_ios.nit @@ -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 index 0000000..8976424 --- /dev/null +++ b/tests/testosx.sh @@ -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 diff --git a/tests/tests.sh b/tests/tests.sh index 6c76366..ead5484 100755 --- a/tests/tests.sh +++ b/tests/tests.sh @@ -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