Merge: CallSite on AFor and ARange
authorJean Privat <jean@pryen.org>
Fri, 28 Mar 2014 22:13:12 +0000 (18:13 -0400)
committerJean Privat <jean@pryen.org>
Fri, 28 Mar 2014 22:13:21 +0000 (18:13 -0400)
Use CallSite to resolve and type some implicit services.
Subsequent phases will like them!

Currenlty: all the AFor and ARange services are converted and tools updated.
TODO: Array and SuperString

Pull-Request: #370
Reviewed-by: Alexandre Terrasa <alexandre@moz-code.org>

79 files changed:
benchmarks/languages/bench_typetest_fts_nesting.nit
contrib/nitcc/src/grammar.nit
contrib/nitcc/src/nitcc_lexer0.nit
lib/base64.nit
lib/curl/curl_c.nit
lib/json/jsonable.nit
lib/opts.nit
lib/pipeline.nit
lib/sha1.nit [new file with mode: 0644]
lib/standard/exec.nit
lib/standard/file.nit
lib/standard/ropes.nit
lib/standard/stream.nit
lib/standard/string.nit
lib/standard/string_search.nit
src/astbuilder.nit
src/auto_super_init.nit
src/compiler_ffi.nit
src/debugger.nit
src/global_compiler.nit
src/location.nit
src/metrics/generate_hierarchies.nit
src/metrics/model_hyperdoc.nit
src/metrics/rta_metrics.nit
src/model/model.nit
src/model/model_base.nit
src/modelbuilder.nit
src/naive_interpreter.nit
src/network_debugger.nit
src/nitdbg_client.nit
src/nitdoc.nit
src/nitunit.nit
src/nitx.nit
src/phase.nit
src/rapid_type_analysis.nit
src/separate_compiler.nit
src/typing.nit
tests/base_prot.nit
tests/base_prot0.nit [new file with mode: 0644]
tests/base_prot2.nit
tests/base_prot3.nit
tests/base_test_obj_id.nit
tests/bench_string_append.nit
tests/example_objet.nit
tests/example_procedural_string.nit
tests/example_string.nit
tests/sav/base_attr3_alt2.res
tests/sav/base_attr3_alt3.res
tests/sav/base_attr3_alt4.res
tests/sav/base_class_name.res
tests/sav/base_prot.res
tests/sav/base_prot0.res [new file with mode: 0644]
tests/sav/base_prot2.res
tests/sav/base_prot2_alt1.res
tests/sav/base_prot2_alt2.res
tests/sav/base_prot2_alt3.res
tests/sav/base_prot2_alt4.res
tests/sav/base_prot3.res
tests/sav/base_prot3_alt1.res [new file with mode: 0644]
tests/sav/base_prot3_alt2.res [new file with mode: 0644]
tests/sav/base_prot3_alt3.res [new file with mode: 0644]
tests/sav/base_prot3_alt4.res [new file with mode: 0644]
tests/sav/base_prot3_alt5.res [new file with mode: 0644]
tests/sav/base_prot3_alt6.res [new file with mode: 0644]
tests/sav/base_prot3_alt7.res [new file with mode: 0644]
tests/sav/base_prot3_alt8.res [new file with mode: 0644]
tests/sav/base_prot3_alt9.res [new file with mode: 0644]
tests/sav/nitg-e/base_class_name.res
tests/sav/nitmetrics_args1.res
tests/sav/test_pipeline.res
tests/sav/test_string_search.res
tests/shootout_nsieve.nit
tests/string_ffi_ref_test.nit
tests/string_trim.nit
tests/test_isa.nit
tests/test_pipeline.nit
tests/test_string_is_numeric.nit
tests/test_string_long.nit
tests/test_string_search.nit

index 8cb2df0..732dab3 100644 (file)
@@ -7,7 +7,7 @@ class TypeTestFtsNestingGenerator
 
        fun clanit(i: Int): String
        do
-               var s = new Buffer
+               var s = new FlatBuffer
                s.append("{classes.first}[" * i)
                s.append("Root")
                s.append("]" * i)
@@ -29,7 +29,7 @@ class TypeTestFtsNestingGenerator
 
        fun clajava(i: Int): String
        do
-               var s = new Buffer
+               var s = new FlatBuffer
                s.append("{classes.first}<" * i)
                s.append("Root")
                s.append(">" * i)
@@ -81,7 +81,7 @@ class TypeTestFtsNestingGenerator
 
        fun clacpp(i: Int): String
        do
-               var s = new Buffer
+               var s = new FlatBuffer
                s.append("{classes.first}<" * i)
                s.append("Root")
                s.append("*>" * i)
@@ -103,7 +103,7 @@ class TypeTestFtsNestingGenerator
 
        fun clae(i: Int): String
        do
-               var s = new Buffer
+               var s = new FlatBuffer
                s.append("{classes.first}[" * i)
                s.append("ROOT")
                s.append("]" * i)
index 52e995c..e6851f0 100644 (file)
@@ -27,7 +27,7 @@ class Gram
        # Dump of the concrete grammar and the transformations
        fun pretty: String
        do
-               var res = new Buffer
+               var res = new FlatBuffer
                for p in prods do
                        if p.spe != null then
                                res.append("{p.name} \{-> {p.spe.name}\}=\n")
@@ -1072,7 +1072,7 @@ class Item
 
        redef fun to_s
        do
-               var b = new Buffer
+               var b = new FlatBuffer
                b.append("{alt.prod.name}::{alt.name}=")
                for i in [0..alt.elems.length[
                do
index a3cade7..6f12765 100644 (file)
@@ -96,7 +96,7 @@ class Lexer_nitcc
 
        fun str
        do
-               var b = new Buffer
+               var b = new FlatBuffer
                b.add('\'')
                while iter.is_ok do
                        var c = iter.item
@@ -123,7 +123,7 @@ class Lexer_nitcc
 
        fun id(c: Char)
        do
-               var b = new Buffer
+               var b = new FlatBuffer
                b.add c
                while iter.is_ok do
                        c = iter.item
@@ -140,7 +140,7 @@ class Lexer_nitcc
 
        fun kw(c: Char)
        do
-               var b = new Buffer
+               var b = new FlatBuffer
                b.add c
                while iter.is_ok do
                        c = iter.item
index 9c57166..2d941e9 100644 (file)
@@ -87,12 +87,12 @@ redef class String
                var steps = length / 4
                var result_length = steps*3
 
-               var padding_begin = padding.search_index_in( self, 0 )
+               var padding_begin = self.search(padding)
                var padding_count : Int
-               if padding_begin == -1 then
+               if padding_begin == null then
                        padding_count = 0
                else
-                       padding_count = length - padding_begin
+                       padding_count = length - padding_begin.from
                        steps -= 1
                        result_length -= padding_count
                end
index 5ac43c4..a8d4696 100644 (file)
@@ -17,8 +17,6 @@
 # Binding of C libCurl which allow us to interact with network.
 module curl_c is pkgconfig("libcurl")
 
-import pipeline
-
 in "C header" `{
        #include <stdio.h>
        #include <stdlib.h>
@@ -336,7 +334,11 @@ redef class Collection[E]
                        print "Collection item must be strings."
                end
                var primList = new CURLSList.with_str(self.first)
-               for s in self.skip_head(1) do primList.append(s)
+               var is_first = true
+               for s in self do
+                       if not is_first then primList.append(s)
+                       is_first = false
+               end
                return primList
        end
 end
index a4e909a..08f8908 100644 (file)
@@ -39,6 +39,10 @@ redef class SequenceRead[ V ]
        super Jsonable
 end
 
+redef class String
+       super Jsonable
+end
+
 # Can b converted to a Json object
 redef class Map[ K, V ]
        super Jsonable
index ec3c006..14e28fa 100644 (file)
@@ -68,7 +68,7 @@ abstract class Option
        # A pretty print for this help
        fun pretty(off: Int): String
        do
-               var text = new Buffer.from("  ")
+               var text = new FlatBuffer.from("  ")
                text.append(_names.join(", "))
                text.append("  ")
                var rest = off - text.length
index 92c29d4..055823f 100644 (file)
 
 # Pipelined filters and operations on iterators.
 #
-# This module enhance `Collection`s with some methods that enable a
+# This module enhance `Iterator`s with some methods that enable a
 # pipeline-like programing that offers the manupulation of
 # collections trough connected filters with reasonable memory constraints.
-#
-# The filters methods return a view bounded on the original collection.
-# Filters can be chained to build complex virtual collections.
-#
-# FIXME: Fix vocabulary (lazy/view/filter)
-# FIXME: Maybe the name of the method should indicate that the method is 'lazy' (or is a filter).
 module pipeline
 
-redef interface Collection[E]
+redef interface Iterator[E]
        # Filter: sort with `default_comparator`.
        # SEE: `sort_with` for details
        # REQUIRE: self isa Iterator[Comparable]
        #
-       #     assert [1,3,2].sort_filter.to_a        ==  [1,2,3]
-       fun sort_filter: Collection[E]
+       #     assert [1,3,2].iterator.sort.to_a      ==  [1,2,3]
+       fun sort: Iterator[E]
        do
-               assert self isa Collection[Comparable]
+               assert self isa Iterator[Comparable]
                var a = self.to_a
                default_comparator.sort(a)
-               return a
+               return a.iterator
        end
 
        # Filter: sort with a given `comparator`.
        # Important: require O(n) memory.
-       fun sort_with(comparator: Comparator[E]): Collection[E]
+       fun sort_with(comparator: Comparator[E]): Iterator[E]
        do
                var a = self.to_a
                comparator.sort(a)
-               return a
+               return a.iterator
        end
 
        # Filter: reject duplicates.
@@ -54,12 +48,12 @@ redef interface Collection[E]
        # Important: rely on `==` and `hash`
        # Important: require O(m) in memory, where m is the total number of uniq items.
        #
-       #     assert [1,2,1,1,1,3,2].uniq.to_a       ==  [1,2,3]
+       #     assert [1,2,1,1,1,3,2].iterator.uniq.to_a      ==  [1,2,3]
        #
        # REQUIRE: self isa Iterator[Object]
-       fun uniq: Collection[E]
+       fun uniq: Iterator[E]
        do
-               assert self isa Collection[Object]
+               assert self isa Iterator[Object]
                return new PipeUniq[E](self)
        end
 
@@ -67,84 +61,146 @@ redef interface Collection[E]
        #
        # Important: rely on `==`.
        #
-       #     assert [1,2,1,1,1,3,2].seq_uniq.to_a           ==  [1,2,1,3,2]
-       fun seq_uniq: Collection[E]
+       #     assert [1,2,1,1,1,3,2].iterator.seq_uniq.to_a          ==  [1,2,1,3,2]
+       fun seq_uniq: Iterator[E]
        do
                return new PipeSeqUniq[E](self)
        end
 
-       # The view of two combined collections.
+       # Combine two iterators.
+       #
+       # When the first iterator is terminated, the second is started.
        #
-       #     assert ([1..20[ + [20..40[).to_a       ==  ([1..40[).to_a
-       fun +(other: Collection[E]): Collection[E]
+       #     assert ([1..20[.iterator + [20..40[.iterator).to_a             ==  ([1..40[).to_a
+       fun +(other: Iterator[E]): Iterator[E]
        do
                return new PipeJoin[E](self, other)
        end
 
        # Alternate each item with `e`.
        #
-       #    assert [1,2,3].alternate(0).to_a                ==  [1,0,2,0,3]
-       fun alternate(e: E): Collection[E]
+       #    assert [1,2,3].iterator.alternate(0).to_a               ==  [1,0,2,0,3]
+       fun alternate(e: E): Iterator[E]
        do
                return new PipeAlternate[E](self, e)
        end
 
        # Filter: reject a given `item`.
        #
-       #    assert [1,1,2,1,3].skip(1).to_a                 ==  [2,3]
-       fun skip(item: E): Collection[E]
+       #    assert [1,1,2,1,3].iterator.skip(1).to_a                ==  [2,3]
+       fun skip(item: E): Iterator[E]
        do
                return new PipeSkip[E](self, item)
        end
 
        # Filter: keep only the first `length` items.
        #
-       #     assert [1,2,3,4,5].head(2).to_a        ==  [1,2]
-       fun head(length: Int): Collection[E]
+       # This filter does not always consume `self'.
+       #
+       #     var i = [1,2,3,4,5].iterator
+       #     assert i.head(2).to_a   == [1,2]
+       #     i.to_a                  == [3,4,5]
+       fun head(length: Int): Iterator[E]
        do
                return new PipeHead[E](self, length)
        end
 
        # Filter: reject the first `length` items.
        #
-       #     assert [1,2,3,4,5].skip_head(2).to_a           ==  [3,4,5]
+       #     assert [1,2,3,4,5].iterator.skip_head(2).to_a          ==  [3,4,5]
        #
        # ENSURE: self == return
-       fun skip_head(length: Int): Collection[E]
+       fun skip_head(length: Int): Iterator[E]
        do
-               return new PipeSkipHead[E](self, length)
+               while length > 0 and self.is_ok do
+                       length -= 1
+                       self.next
+               end
+               return self
        end
 
        # Filter: keep only the last `length` items.
        #
-       #     assert [1,2,3,4,5].tail(2).to_a        ==  [4,5]
+       #     assert [1,2,3,4,5].iterator.tail(2).to_a       ==  [4,5]
        #
        # Important: require O(length) in memory
-       fun tail(length: Int): Collection[E]
+       fun tail(length: Int): Iterator[E]
        do
-               return new PipeTail[E](self, length)
+               var lasts = new List[E]
+               while self.is_ok do
+                       while lasts.length >= length do lasts.shift
+                       lasts.push(self.item)
+                       self.next
+               end
+               return lasts.iterator
        end
 
        # Filter: reject the last `length` items.
        #
-       #     assert [1,2,3,4,5].skip_tail(2).to_a           ==  [1,2,3]
+       #     assert [1,2,3,4,5].iterator.skip_tail(2).to_a          ==  [1,2,3]
        #
        # Important: require O(length) in memory
-       fun skip_tail(length: Int): Collection[E]
+       fun skip_tail(length: Int): Iterator[E]
        do
                return new PipeSkipTail[E](self, length)
        end
+
+       # Filter: reject items that does not meet some criteria.
+       #
+       #     class IsEvenFunction
+       #       super Function[Int, Bool]
+       #       redef fun apply(i) do return i % 2 == 0
+       #     end
+       #     assert [1,2,3,4,8].iterator.select(new IsEvenFunction).to_a  == [2,4,8]
+       fun select(predicate: Function[E, Bool]): Iterator[E]
+       do
+               return new PipeSelect[E](self, predicate)
+       end
 end
 
-### Specific private collection and iterator classes
+# Interface that reify a function.
+# Concrete subclasses must implements the `apply` method.
+#
+# This interface helps to manipulate function-like objects.
+#
+# The main usage it as a transformation; that takes an argument and produce a result.
+# See `map` for example.
+#
+# Another usage is as a predicate, with `Function[E, Bool]`.
+# See `Iterator::select` for example.
+#
+# Function with more than one argument can be reified with some uncurification.
+# Eg. `Function[ARG1, Function[ARG2, RES]]`.
+#
+# NOTE: Nit is not a functionnal language, this class is a very basic way to
+# simulate the reification of a simple function.
+interface Function[FROM, TO]
+       # How an element is mapped to another one.
+       fun apply(e: FROM): TO is abstract
 
-private class PipeUniq[E]
-       super Collection[E]
-       var source: Collection[E]
-       redef fun iterator do return new PipeUniqIterator[E](source.iterator)
+       # Filter: produce an iterator which each element is transformed.
+       #
+       #     var i = [1,2,3].iterator
+       #     assert fun_to_s.map(i).to_a  == ["1", "2", "3"]
+       #
+       # Note: because there is no generic method in Nit (yet?),
+       # there is no way to have a better API.
+       # eg. with the Iterator as receiver and the function as argument.
+       # (see `Iterator::select`)
+       fun map(i: Iterator[FROM]): Iterator[TO]
+       do
+               return new PipeMap[FROM, TO](i, self)
+       end
 end
 
-private class PipeUniqIterator[E]
+private class FunctionToS
+       super Function[Object, String]
+       redef fun apply(e) do return e.to_s
+end
+
+### Specific private iterator classes
+
+private class PipeUniq[E]
        super Iterator[E]
 
        var source: Iterator[E]
@@ -166,12 +222,6 @@ private class PipeUniqIterator[E]
 end
 
 private class PipeSeqUniq[E]
-       super Collection[E]
-       var source: Collection[E]
-       redef fun iterator do return new PipeSeqUniqIterator[E](source.iterator)
-end
-
-private class PipeSeqUniqIterator[E]
        super Iterator[E]
 
        var source: Iterator[E]
@@ -191,13 +241,6 @@ private class PipeSeqUniqIterator[E]
 end
 
 private class PipeJoin[E]
-       super Collection[E]
-       var source1: Collection[E]
-       var source2: Collection[E]
-       redef fun iterator do return new PipeJoinIterator[E](source1.iterator, source2.iterator)
-end
-
-private class PipeJoinIterator[E]
        super Iterator[E]
        var source1: Iterator[E]
        var source2: Iterator[E]
@@ -219,13 +262,6 @@ private class PipeJoinIterator[E]
 end
 
 private class PipeAlternate[E]
-       super Collection[E]
-       var source: Collection[E]
-       var odd_item: E
-       redef fun iterator do return new PipeAlternateIterator[E](source.iterator, odd_item)
-end
-
-private class PipeAlternateIterator[E]
        super Iterator[E]
 
        var source: Iterator[E]
@@ -253,14 +289,6 @@ private class PipeAlternateIterator[E]
 end
 
 private class PipeSkip[E]
-       super Collection[E]
-       var source: Collection[E]
-       var skip_item: E
-       redef fun iterator do return new PipeSkipIterator[E](source.iterator, skip_item)
-end
-
-private class PipeSkipIterator[E]
-       super Collection[E]
        super Iterator[E]
 
        var source: Iterator[E]
@@ -291,13 +319,6 @@ private class PipeSkipIterator[E]
 end
 
 private class PipeHead[E]
-       super Collection[E]
-       var source: Collection[E]
-       var pipe_length: Int
-       redef fun iterator do return new PipeHeadIterator[E](source.iterator, pipe_length)
-end
-
-private class PipeHeadIterator[E]
        super Iterator[E]
 
        var source: Iterator[E]
@@ -315,48 +336,7 @@ private class PipeHeadIterator[E]
        end
 end
 
-private class PipeSkipHead[E]
-       super Collection[E]
-       var source: Collection[E]
-       var pipe_length: Int
-       redef fun iterator
-       do
-               var res = source.iterator
-               var length = pipe_length
-               while length > 0 and res.is_ok do
-                       length -= 1
-                       res.next
-               end
-               return res
-       end
-end
-
-private class PipeTail[E]
-       super Collection[E]
-       var source: Collection[E]
-       var pipe_length: Int
-       redef fun iterator
-       do
-               var lasts = new List[E]
-               var res = source.iterator
-               var length = pipe_length
-               while res.is_ok do
-                       while lasts.length >= length do lasts.shift
-                       lasts.push(res.item)
-                       res.next
-               end
-               return lasts.iterator
-       end
-end
-
 private class PipeSkipTail[E]
-       super Collection[E]
-       var source: Collection[E]
-       var pipe_length: Int
-       redef fun iterator do return new PipeSkipTailIterator[E](source.iterator, pipe_length)
-end
-
-private class PipeSkipTailIterator[E]
        super Iterator[E]
 
        var source: Iterator[E]
@@ -387,3 +367,63 @@ private class PipeSkipTailIterator[E]
                source.next
        end
 end
+
+private class PipeSelect[E]
+       super Iterator[E]
+
+       var source: Iterator[E]
+
+       var predicate: Function[E, Bool]
+
+       init(source: Iterator[E], predicate: Function[E, Bool])
+       do
+               self.source = source
+               self.predicate = predicate
+
+               do_skip
+       end
+
+       fun do_skip
+       do
+               while source.is_ok and not predicate.apply(source.item) do source.next
+       end
+
+       redef fun is_ok do return source.is_ok
+
+       redef fun item do return source.item
+
+       redef fun next
+       do
+               source.next
+               do_skip
+       end
+end
+
+private class PipeMap[E, F]
+       super Iterator[F]
+
+       var source: Iterator[E]
+       var function: Function[E, F]
+
+       var item_cache: nullable F = null
+       var item_cached = false
+
+       redef fun is_ok do return source.is_ok
+
+       redef fun item do
+               if item_cached then return item_cache
+               item_cache = function.apply(source.item)
+               item_cached = true
+               return item_cache
+       end
+
+       redef fun next do
+               source.next
+               item_cached = false
+       end
+end
+
+# Stateless singleton that reify to the `to_s` method.
+#
+#     assert fun_to_s.apply(5)  == "5"
+fun fun_to_s: Function[Object, String] do return once new FunctionToS
diff --git a/lib/sha1.nit b/lib/sha1.nit
new file mode 100644 (file)
index 0000000..033bd83
--- /dev/null
@@ -0,0 +1,279 @@
+# This file is part of NIT (http://www.nitlanguage.org).
+#
+# Copyright 2014 Lucas Bajolet <r4pass@hotmail.com>
+#
+# 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.
+
+# Provides methods to compute the SHA1 hash of a String
+module sha1
+
+in "C Header" `{
+
+       /* This code is public-domain - it is based on libcrypt
+        * placed in the public domain by Wei Dai and other contributors.
+        */
+
+       #include <stdint.h>
+       #include <string.h>
+
+       #define HASH_LENGTH 20
+       #define BLOCK_LENGTH 64
+
+       union _buffer {
+               uint8_t b[BLOCK_LENGTH];
+               uint32_t w[BLOCK_LENGTH/4];
+       };
+
+       union _state {
+               uint8_t b[HASH_LENGTH];
+               uint32_t w[HASH_LENGTH/4];
+       };
+
+       typedef struct sha1nfo {
+               union _buffer buffer;
+               uint8_t bufferOffset;
+               union _state state;
+               uint32_t byteCount;
+               uint8_t keyBuffer[BLOCK_LENGTH];
+               uint8_t innerHash[HASH_LENGTH];
+       } sha1nfo;
+
+       /**
+        */
+       void sha1_init(sha1nfo *s);
+       /**
+        */
+       void sha1_writebyte(sha1nfo *s, uint8_t data);
+       /**
+        */
+       void sha1_write(sha1nfo *s, const char *data, size_t len);
+       /**
+        */
+       uint8_t* sha1_result(sha1nfo *s);
+       /**
+        */
+       void sha1_initHmac(sha1nfo *s, const uint8_t* key, int keyLength);
+       /**
+        */
+       uint8_t* sha1_resultHmac(sha1nfo *s);
+`}
+
+`{
+       #define SHA1_K0 0x5a827999
+       #define SHA1_K20 0x6ed9eba1
+       #define SHA1_K40 0x8f1bbcdc
+       #define SHA1_K60 0xca62c1d6
+
+       const uint8_t sha1InitState[] = {
+               0x01,0x23,0x45,0x67, // H0
+               0x89,0xab,0xcd,0xef, // H1
+               0xfe,0xdc,0xba,0x98, // H2
+               0x76,0x54,0x32,0x10, // H3
+               0xf0,0xe1,0xd2,0xc3     // H4
+       };
+
+       void sha1_init(sha1nfo *s) {
+               memcpy(s->state.b,sha1InitState,HASH_LENGTH);
+               s->byteCount = 0;
+               s->bufferOffset = 0;
+       }
+
+       uint32_t sha1_rol32(uint32_t number, uint8_t bits) {
+               return ((number << bits) | (number >> (32-bits)));
+       }
+
+       void sha1_hashBlock(sha1nfo *s) {
+               uint8_t i;
+               uint32_t a,b,c,d,e,t;
+
+               a=s->state.w[0];
+               b=s->state.w[1];
+               c=s->state.w[2];
+               d=s->state.w[3];
+               e=s->state.w[4];
+               for (i=0; i<80; i++) {
+                       if (i>=16) {
+                               t = s->buffer.w[(i+13)&15] ^ s->buffer.w[(i+8)&15] ^ s->buffer.w[(i+2)&15] ^ s->buffer.w[i&15];
+                               s->buffer.w[i&15] = sha1_rol32(t,1);
+                       }
+                       if (i<20) {
+                               t = (d ^ (b & (c ^ d))) + SHA1_K0;
+                       } else if (i<40) {
+                               t = (b ^ c ^ d) + SHA1_K20;
+                       } else if (i<60) {
+                               t = ((b & c) | (d & (b | c))) + SHA1_K40;
+                       } else {
+                               t = (b ^ c ^ d) + SHA1_K60;
+                       }
+                       t+=sha1_rol32(a,5) + e + s->buffer.w[i&15];
+                       e=d;
+                       d=c;
+                       c=sha1_rol32(b,30);
+                       b=a;
+                       a=t;
+               }
+               s->state.w[0] += a;
+               s->state.w[1] += b;
+               s->state.w[2] += c;
+               s->state.w[3] += d;
+               s->state.w[4] += e;
+       }
+
+       void sha1_addUncounted(sha1nfo *s, uint8_t data) {
+               s->buffer.b[s->bufferOffset ^ 3] = data;
+               s->bufferOffset++;
+               if (s->bufferOffset == BLOCK_LENGTH) {
+                       sha1_hashBlock(s);
+                       s->bufferOffset = 0;
+               }
+       }
+
+       void sha1_writebyte(sha1nfo *s, uint8_t data) {
+               ++s->byteCount;
+               sha1_addUncounted(s, data);
+       }
+
+       void sha1_write(sha1nfo *s, const char *data, size_t len) {
+               for (;len--;) sha1_writebyte(s, (uint8_t) *data++);
+       }
+
+       void sha1_pad(sha1nfo *s) {
+               // Implement SHA-1 padding (fips180-2 Â§5.1.1)
+
+               // Pad with 0x80 followed by 0x00 until the end of the block
+               sha1_addUncounted(s, 0x80);
+               while (s->bufferOffset != 56) sha1_addUncounted(s, 0x00);
+
+               // Append length in the last 8 bytes
+               sha1_addUncounted(s, 0); // We're only using 32 bit lengths
+               sha1_addUncounted(s, 0); // But SHA-1 supports 64 bit lengths
+               sha1_addUncounted(s, 0); // So zero pad the top bits
+               sha1_addUncounted(s, s->byteCount >> 29); // Shifting to multiply by 8
+               sha1_addUncounted(s, s->byteCount >> 21); // as SHA-1 supports bitstreams as well as
+               sha1_addUncounted(s, s->byteCount >> 13); // byte.
+               sha1_addUncounted(s, s->byteCount >> 5);
+               sha1_addUncounted(s, s->byteCount << 3);
+       }
+
+       uint8_t* sha1_result(sha1nfo *s) {
+               int i;
+               // Pad to complete the last block
+               sha1_pad(s);
+
+               // Swap byte order back
+               for (i=0; i<5; i++) {
+                       uint32_t a,b;
+                       a=s->state.w[i];
+                       b=a<<24;
+                       b|=(a<<8) & 0x00ff0000;
+                       b|=(a>>8) & 0x0000ff00;
+                       b|=a>>24;
+                       s->state.w[i]=b;
+               }
+
+               // Return pointer to hash (20 characters)
+               return s->state.b;
+       }
+
+       #define HMAC_IPAD 0x36
+       #define HMAC_OPAD 0x5c
+
+       void sha1_initHmac(sha1nfo *s, const uint8_t* key, int keyLength) {
+               uint8_t i;
+               memset(s->keyBuffer, 0, BLOCK_LENGTH);
+               if (keyLength > BLOCK_LENGTH) {
+                       // Hash long keys
+                       sha1_init(s);
+                       for (;keyLength--;) sha1_writebyte(s, *key++);
+                       memcpy(s->keyBuffer, sha1_result(s), HASH_LENGTH);
+               } else {
+                       // Block length keys are used as is
+                       memcpy(s->keyBuffer, key, keyLength);
+               }
+               // Start inner hash
+               sha1_init(s);
+               for (i=0; i<BLOCK_LENGTH; i++) {
+                       sha1_writebyte(s, s->keyBuffer[i] ^ HMAC_IPAD);
+               }
+       }
+
+       uint8_t* sha1_resultHmac(sha1nfo *s) {
+               uint8_t i;
+               // Complete inner hash
+               memcpy(s->innerHash,sha1_result(s),HASH_LENGTH);
+               // Calculate outer hash
+               sha1_init(s);
+               for (i=0; i<BLOCK_LENGTH; i++) sha1_writebyte(s, s->keyBuffer[i] ^ HMAC_OPAD);
+               for (i=0; i<HASH_LENGTH; i++) sha1_writebyte(s, s->innerHash[i]);
+               return sha1_result(s);
+       }
+`}
+
+redef class String
+
+       # Computes the SHA1 of the receiver
+       #
+       # Returns a digest of 20 bytes as a String,
+       # note that all the characters are not necessarily ASCII.
+       # If you want the hex string version of the digest, use
+       # sha1_to_s.
+       #
+       #     import base64
+       #     assert "The quick brown fox jumps over the lazy dog".sha1.encode_base64 == "L9ThxnotKPzthJ7hu3bnORuT6xI="
+       fun sha1: String import String.to_cstring, String.length, NativeString.to_s_with_length `{
+               uint32_t a;
+               sha1nfo s;
+
+               sha1_init(&s);
+               sha1_write(&s, String_to_cstring(recv), String_length(recv));
+               uint8_t* digest = sha1_result(&s);
+
+               char* digested = malloc(21);
+
+               memcpy(digested, digest, 20);
+
+               digested[20] = '\0';
+
+               return NativeString_to_s_with_length(digested, 20);
+       `}
+
+       # Computes the SHA1 of the receiver.
+       #
+       # Returns a 40 char String containing the Hexadecimal
+       # Digest in its Char form.
+       #
+       #     assert "The quick brown fox jumps over the lazy dog".sha1_to_s == "2FD4E1C67A2D28FCED849EE1BB76E7391B93EB12"
+       fun sha1_to_s: String import String.to_cstring, String.length, NativeString.to_s_with_length `{
+               uint32_t a;
+               sha1nfo s;
+
+               sha1_init(&s);
+               sha1_write(&s, String_to_cstring(recv), String_length(recv));
+               uint8_t* digest = sha1_result(&s);
+
+               char* ret_str = malloc(41);
+               char* hexmap = "0123456789ABCDEF";
+
+               int i;
+               for(i=0;i<20;i++){
+                       uint8_t q = digest[i];
+                       ret_str[i*2] = hexmap[q >> 4];
+                       ret_str[(i*2)+1] = hexmap[q & 0x0F];
+               }
+               ret_str[40] = '\0';
+
+               return NativeString_to_s_with_length(ret_str, 40);
+       `}
+
+end
+
index 78424ff..166cef4 100644 (file)
@@ -59,7 +59,7 @@ class Process
        # Internal code to handle execution
        protected init execute(command: String, arguments: nullable Array[String], pipeflags: Int)
        do
-               var args = new Buffer
+               var args = new FlatBuffer
                var l = 1 # Number of elements in args
                args.append(command)
                if arguments != null then
index 0d00cdd..b851876 100644 (file)
@@ -99,12 +99,12 @@ class IFStream
 
        redef fun fill_buffer
        do
-               var nb = _file.io_read(_buffer._items, _buffer._capacity)
+               var nb = _file.io_read(_buffer.items, _buffer.capacity)
                if nb <= 0 then
                        _end_reached = true
                        nb = 0
                end
-               _buffer._length = nb
+               _buffer.length = nb
                _buffer_pos = 0
        end
        
@@ -274,7 +274,7 @@ redef class String
        #     assert "".basename("")                            == ""
        fun basename(ext: String): String
        do
-               var l = _length - 1 # Index of the last char
+               var l = length - 1 # Index of the last char
                while l > 0 and self.chars[l] == '/' do l -= 1 # remove all trailing `/`
                if l == 0 then return "/"
                var pos = last_index_of_from('/', l)
@@ -297,7 +297,7 @@ redef class String
        #     assert "".dirname                            == "."
        fun dirname: String
        do
-               var l = _length - 1 # Index of the last char
+               var l = length - 1 # Index of the last char
                while l > 0 and self.chars[l] == '/' do l -= 1 # remove all trailing `/`
                var pos = last_index_of_from('/', l)
                if pos > 0 then
@@ -375,7 +375,7 @@ redef class String
        fun mkdir
        do
                var dirs = self.split_with("/")
-               var path = new Buffer
+               var path = new FlatBuffer
                if dirs.is_empty then return
                if dirs[0].is_empty then
                        # it was a starting /
index 49453ab..ad093ae 100644 (file)
@@ -45,7 +45,7 @@ abstract class Rope
        end
 
        # Initializes a new Rope with a text embedded in directly
-       init with_string(str: AbstractString) do
+       init with_string(str: String) do
                self.parent_node = new ConcatNode
                parent_node.as(ConcatNode).right_child = new LeafNode(str)
                parent_node.as(ConcatNode).update_data
@@ -71,7 +71,7 @@ abstract class Rope
        end
 
        # Stores a flat version of self in cache
-       private fun flatten: String
+       private fun flatten: FlatString
        do
                var native_final_str = calloc_string(length + 1)
 
@@ -82,7 +82,7 @@ abstract class Rope
                var iter = new DFSRopeLeafIterator(self)
 
                while iter.is_ok do
-                       iter.item.value._items.copy_to(native_final_str, iter.item.value.length, 0, offset)
+                       iter.item.value.as(FlatString).items.copy_to(native_final_str, iter.item.value.length, 0, offset)
                        offset += iter.item.value.length
                        iter.next
                end
@@ -276,7 +276,7 @@ abstract class Rope
        # Compares the current Rope to another object (either another rope or a String)
        redef fun == (other)
        do
-               if other == null or not (other isa Rope or other isa AbstractString) then return false
+               if other == null or not (other isa Rope or other isa FlatText) then return false
                var self_iter = new RopeCharIterator(self)
                if other isa Rope then
                        if self.length != other.length then return false
@@ -286,7 +286,7 @@ abstract class Rope
                                self_iter.next
                                other_iterator.next
                        end
-               else if other isa AbstractString then
+               else if other isa FlatText then
                        var pos = 0
                        if self.length != other.length then return false
                        while self_iter.is_ok do
@@ -449,45 +449,37 @@ class BufferRope
        ############################################################################
 
        # Appends a new Collection[Char] at the end of the current rope
-       fun append(str: Collection[Char]): BufferRope
+       fun append(str: String): BufferRope
        do
-               if str isa AbstractString then
-                       var last_node = parent_node
+               var last_node = parent_node
 
-                       while last_node isa ConcatNode and last_node.right_child != null do
-                               last_node = last_node.right_child.as(not null)
-                       end
-
-                       if last_node isa ConcatNode then
-                               last_node.right_child = new LeafNode(str.to_s)
-                       else if last_node isa LeafNode then
-                               var last_node_parent = last_node.parent
-                               var new_concat = new ConcatNode
-                               last_node_parent.right_child = new_concat
-                               new_concat.left_child = last_node
-                               new_concat.right_child = new LeafNode(str.to_s)
-                               last_node = new_concat
-                       else
-                               print "Fatal Error, please report to the developers for more insight."
-                               abort
-                       end
+               while last_node isa ConcatNode and last_node.right_child != null do
+                       last_node = last_node.right_child.as(not null)
+               end
 
-                       balance_from_node(last_node)
+               if last_node isa ConcatNode then
+                       last_node.right_child = new LeafNode(str.to_s)
+               else if last_node isa LeafNode then
+                       var last_node_parent = last_node.parent
+                       var new_concat = new ConcatNode
+                       last_node_parent.right_child = new_concat
+                       new_concat.left_child = last_node
+                       new_concat.right_child = new LeafNode(str.to_s)
+                       last_node = new_concat
                else
-                       var buf = new Buffer.with_capacity(str.length)
-                       for i in str do
-                               buf.add(i)
-                       end
-                       append(buf)
+                       print "Fatal Error, please report to the developers for more insight."
+                       abort
                end
 
-               if not is_dirty then is_dirty = true
+               balance_from_node(last_node)
+
+               is_dirty = true
 
                return self
        end
 
        # Variatic function to append several collections of Chars
-       fun append_multi(strs: Collection[Char]...): BufferRope
+       fun append_multi(strs: String...): BufferRope
        do
                for i in strs do
                        append(i)
@@ -496,46 +488,38 @@ class BufferRope
        end
 
        # Adds a new Collection[Char] at the beginning of the rope
-       fun prepend(str: Collection[Char]): BufferRope
+       fun prepend(str: String): BufferRope
        do
-               if str isa AbstractString then
-                       var curr_node = parent_node
-
-                       while curr_node isa ConcatNode and curr_node.left_child != null do
-                               curr_node = curr_node.left_child.as(not null)
-                       end
+               var curr_node = parent_node
 
-                       if curr_node isa ConcatNode then
-                               curr_node.left_child = new LeafNode(str.to_s)
-                       else if curr_node isa LeafNode then
-                               var parent = curr_node.parent
-                               var new_concat = new ConcatNode
-                               var new_leaf = new LeafNode(str.to_s)
-                               new_concat.left_child = new_leaf
-                               new_concat.right_child = curr_node
-                               parent.left_child = new_concat
-                               curr_node = new_concat
-                       else
-                               print "Fatal Error"
-                               abort
-                       end
+               while curr_node isa ConcatNode and curr_node.left_child != null do
+                       curr_node = curr_node.left_child.as(not null)
+               end
 
-                       balance_from_node(curr_node)
+               if curr_node isa ConcatNode then
+                       curr_node.left_child = new LeafNode(str.to_s)
+               else if curr_node isa LeafNode then
+                       var parent = curr_node.parent
+                       var new_concat = new ConcatNode
+                       var new_leaf = new LeafNode(str.to_s)
+                       new_concat.left_child = new_leaf
+                       new_concat.right_child = curr_node
+                       parent.left_child = new_concat
+                       curr_node = new_concat
                else
-                       var buf = new Buffer.with_capacity(str.length)
-                       for i in str do
-                               buf.add(i)
-                       end
-                       prepend(buf.to_s)
+                       print "Fatal Error"
+                       abort
                end
 
-               if not is_dirty then is_dirty = true
+               balance_from_node(curr_node)
+
+               is_dirty = true
 
                return self
        end
 
        # Variatic function to prepend several collections of Chars
-       fun prepend_multi(strs: Collection[Char]...): BufferRope
+       fun prepend_multi(strs: String...): BufferRope
        do
                for i in strs do
                        prepend(i)
@@ -1055,7 +1039,7 @@ private class LeafNode
        # Encapsulated string in the leaf node
        private var _value: String
 
-       init(val: AbstractString)
+       init(val: String)
        do
                self._value = val.to_s
                self.length = val.length
index 5724e94..d65d377 100644 (file)
@@ -37,7 +37,7 @@ interface IStream
        # Read at most i bytes
        fun read(i: Int): String
        do
-               var s = new Buffer.with_capacity(i)
+               var s = new FlatBuffer.with_capacity(i)
                while i > 0 and not eof do
                        var c = read_char
                        if c >= 0 then
@@ -52,7 +52,7 @@ interface IStream
        fun read_line: String
        do
                assert not eof
-               var s = new Buffer
+               var s = new FlatBuffer
                append_line_to(s)
                return s.to_s
        end
@@ -60,7 +60,7 @@ interface IStream
        # Read all the stream until the eof.
        fun read_all: String
        do
-               var s = new Buffer
+               var s = new FlatBuffer
                while not eof do
                        var c = read_char
                        if c >= 0 then s.add(c.ascii)
@@ -146,7 +146,7 @@ abstract class BufferedIStream
 
        redef fun read(i)
        do
-               var s = new Buffer.with_capacity(i)
+               var s = new FlatBuffer.with_capacity(i)
                var j = _buffer_pos
                var k = _buffer.length
                while i > 0 do
@@ -168,7 +168,7 @@ abstract class BufferedIStream
 
        redef fun read_all
        do
-               var s = new Buffer
+               var s = new FlatBuffer
                while not eof do
                        var j = _buffer_pos
                        var k = _buffer.length
@@ -221,7 +221,7 @@ abstract class BufferedIStream
        redef fun eof do return _buffer_pos >= _buffer.length and end_reached
 
        # The buffer
-       var _buffer: nullable Buffer = null
+       var _buffer: nullable FlatBuffer = null
 
        # The current position in the buffer
        var _buffer_pos: Int = 0
@@ -235,7 +235,7 @@ abstract class BufferedIStream
        # Allocate a `_buffer` for a given `capacity`.
        protected fun prepare_buffer(capacity: Int)
        do
-               _buffer = new Buffer.with_capacity(capacity)
+               _buffer = new FlatBuffer.with_capacity(capacity)
                _buffer_pos = 0 # need to read
        end
 end
index 0b3d6d9..29a25ff 100644 (file)
@@ -25,18 +25,26 @@ intrude import collection # FIXME should be collection::array
 # String                                                                      #
 ###############################################################################
 
-# Common subclass for String and Buffer
-abstract class AbstractString
-       super AbstractArrayRead[Char]
+# High-level abstraction for all text representations
+abstract class Text
+       super Comparable
+       super StringCapable
 
-       readable private var _items: NativeString
+       redef type OTHER: Text
 
-       fun chars: StringCharView is abstract
+       # Type of the view on self (.chars)
+       type SELFVIEW: StringCharView
 
-       # Access a character at `index` in the string.
-       #
-       #     assert "abcd"[2]         == 'c'
-       redef fun [](index) do return _items[index]
+       # Type of self (used for factorization of several methods, ex : substring_from, empty...)
+       type SELFTYPE: Text
+
+       var hash_cache: nullable Int = null
+
+       # Gets a view on the chars of the Text object
+       fun chars: SELFVIEW is abstract
+
+       # Number of characters contained in self.
+       fun length: Int is abstract
 
        # Create a substring.
        #
@@ -48,24 +56,115 @@ abstract class AbstractString
        # A `from` index < 0 will be replaced by 0.
        # Unless a `count` value is > 0 at the same time.
        # In this case, `from += count` and `count -= from`.
-       fun substring(from: Int, count: Int): String
+       fun substring(from: Int, count: Int): SELFTYPE is abstract
+
+       # Concatenates `o` to `self`
+       fun +(o: Text): SELFTYPE is abstract
+
+       # Auto-concatenates self `i` times
+       fun *(i: Int): SELFTYPE is abstract
+
+       # Is the current Text empty (== "")
+       #       assert "".is_empty
+       #       assert not "foo".is_empty
+       fun is_empty: Bool do return self.length == 0
+
+       # Returns an empty Text of the right type
+       fun empty: SELFTYPE is abstract
+
+       # Gets the first char of the Text
+       #
+       # DEPRECATED : Use self.chars.first instead
+       fun first: Char do return self.chars[0]
+
+       # Access a character at `index` in the string.
+       #
+       #     assert "abcd"[2]         == 'c'
+       #
+       # DEPRECATED : Use self.chars.[] instead
+       fun [](index: Int): Char do return self.chars[index]
+
+       # Gets the index of the first occurence of 'c'
+       #
+       # Returns -1 if not found
+       #
+       # DEPRECATED : Use self.chars.index_of instead
+       fun index_of(c: Char): Int
        do
-               assert count >= 0
-               count += from
-               if from < 0 then from = 0
-               if count > length then count = length
-               if from < count then
-                       var r = new Buffer.with_capacity(count - from)
-                       while from < count do
-                               r.chars.push(_items[from])
-                               from += 1
-                       end
-                       return r.to_s
-               else
-                       return ""
+               return index_of_from(c, 0)
+       end
+
+       # Gets the last char of self
+       #
+       # DEPRECATED : Use self.chars.last instead
+       fun last: Char do return self.chars[length-1]
+
+       # Gets the index of the first occurence of Â´c´ starting from Â´pos´
+       #
+       # Returns -1 if not found
+       #
+       # DEPRECATED : Use self.chars.index_of_from instead
+       fun index_of_from(c: Char, pos: Int): Int
+       do
+               var iter = self.chars.iterator_from(pos)
+               while iter.is_ok do
+                       if iter.item == c then return iter.index
                end
+               return -1
        end
 
+       # Gets the last index of char Â´c´
+       #
+       # Returns -1 if not found
+       #
+       # DEPRECATED : Use self.chars.last_index_of instead
+       fun last_index_of(c: Char): Int
+       do
+               return last_index_of_from(c, length - 1)
+       end
+
+       # Return a null terminated char *
+       fun to_cstring: NativeString do return flatten.to_cstring
+
+       # The index of the last occurrence of an element starting from pos (in reverse order).
+       # Example :
+       #               assert "/etc/bin/test/test.nit".last_index_of_from('/', length-1) == 13
+       #               assert "/etc/bin/test/test.nit".last_index_of_from('/', 12) == 8
+       #
+       # Returns -1 if not found
+       #
+       # DEPRECATED : Use self.chars.last_index_of_from instead
+       fun last_index_of_from(item: Char, pos: Int): Int
+       do
+               var iter = self.chars.reverse_iterator_from(pos)
+               while iter.is_ok do
+                       if iter.item == item then return iter.index
+                       iter.next
+               end
+               return -1
+       end
+
+       # Gets an iterator on the chars of self
+       #
+       # DEPRECATED : Use self.chars.iterator instead
+       fun iterator: Iterator[Char]
+       do
+               return self.chars.iterator
+       end
+
+       # Is 'c' contained in self ?
+       #
+       # DEPRECATED : Use self.chars.has instead
+       fun has(c: Char): Bool
+       do
+               return self.chars.has(c)
+       end
+
+       # Gets an Array containing the chars of self
+       #
+       # DEPRECATED : Use self.chars.to_a instead
+       fun to_a: Array[Char] do return chars.to_a
+
        # Create a substring from `self` beginning at the `from` position
        #
        #     assert "abcd".substring_from(1)    ==  "bcd"
@@ -73,30 +172,30 @@ abstract class AbstractString
        #     assert "abcd".substring_from(2)    ==  "cd"
        #
        # As with substring, a `from` index < 0 will be replaced by 0
-       fun substring_from(from: Int): String
+       fun substring_from(from: Int): SELFTYPE
        do
-               assert from < length
+               if from > self.length then return empty
+               if from < 0 then from = 0
                return substring(from, length - from)
        end
 
+       # Returns a reversed version of self
+       fun reversed: SELFTYPE is abstract
+
        # Does self have a substring `str` starting from position `pos`?
        #
        #     assert "abcd".has_substring("bc",1)            ==  true
        #     assert "abcd".has_substring("bc",2)            ==  false
        fun has_substring(str: String, pos: Int): Bool
        do
-               var itsindex = str.length - 1
-               var myindex = pos + itsindex
-               var myitems = _items
-               var itsitems = str._items
-               if myindex > length or itsindex > myindex  then return false
-               var its_index_from = str._index_from
-               itsindex += its_index_from
-               while itsindex >= its_index_from do
-                       if myitems[myindex] != itsitems[itsindex] then return false
-                       myindex -= 1
-                       itsindex -= 1
+               var myiter = self.chars.iterator_from(pos)
+               var itsiter = str.iterator
+               while myiter.is_ok and itsiter.is_ok do
+                       if myiter.item != itsiter.item then return false
+                       myiter.next
+                       itsiter.next
                end
+               if itsiter.is_ok then return false
                return true
        end
 
@@ -194,21 +293,35 @@ abstract class AbstractString
        # A upper case version of `self`
        #
        #     assert "Hello World!".to_upper     == "HELLO WORLD!"
-       fun to_upper: String
-       do
-               var s = new Buffer.with_capacity(length)
-               for i in self.chars do s.add(i.to_upper)
-               return s.to_s
-       end
+       fun to_upper: SELFTYPE is abstract
 
        # A lower case version of `self`
        #
        #     assert "Hello World!".to_lower     == "hello world!"
-       fun to_lower : String
+       fun to_lower : SELFTYPE is abstract
+
+       # Removes the whitespaces at the beginning of self
+       fun l_trim: SELFTYPE
        do
-               var s = new Buffer.with_capacity(length)
-               for i in self.chars do s.add(i.to_lower)
-               return s.to_s
+               var iter = self.chars.iterator
+               while iter.is_ok do
+                       if iter.item.ascii > 32 then break
+                       iter.next
+               end
+               if iter.index == length then return self.empty
+               return self.substring_from(iter.index)
+       end
+
+       # Removes the whitespaces at the end of self
+       fun r_trim: SELFTYPE
+       do
+               var iter = self.chars.reverse_iterator
+               while iter.is_ok do
+                       if iter.item.ascii > 32 then break
+                       iter.next
+               end
+               if iter.index == length then return self.empty
+               return self.substring(0, iter.index + 1)
        end
 
        # Trims trailing and preceding white spaces
@@ -216,37 +329,12 @@ abstract class AbstractString
        #
        #     assert "  Hello  World !  ".trim   == "Hello  World !"
        #     assert "\na\nb\tc\t".trim          == "a\nb\tc"
-       fun trim: String
-       do
-               if self.length == 0 then return self.to_s
-               # find position of the first non white space char (ascii < 32) from the start of the string
-               var start_pos = 0
-               while self.chars[start_pos].ascii <= 32 do
-                       start_pos += 1
-                       if start_pos == length then return ""
-               end
-               # find position of the first non white space char from the end of the string
-               var end_pos = length - 1
-               while self.chars[end_pos].ascii <= 32 do
-                       end_pos -= 1
-                       if end_pos == start_pos then return self.chars[start_pos].to_s
-               end
-               return self.substring(start_pos, end_pos - start_pos + 1)
-       end
-
-       redef fun output
-       do
-               var i = 0
-               while i < length do
-                       _items[i].output
-                       i += 1
-               end
-       end
+       fun trim: SELFTYPE do return (self.l_trim).r_trim
 
        # Mangle a string to be a unique string only made of alphanumeric characters
        fun to_cmangle: String
        do
-               var res = new Buffer
+               var res = new FlatBuffer
                var underscore = false
                for c in self.chars do
                        if (c >= 'a' and c <= 'z') or (c >='A' and c <= 'Z') then
@@ -280,7 +368,7 @@ abstract class AbstractString
        #     assert "\n\"'\\".escape_to_c         == "\\n\\\"\\'\\\\"
        fun escape_to_c: String
        do
-               var b = new Buffer
+               var b = new FlatBuffer
                for c in self.chars do
                        if c == '\n' then
                                b.append("\\n")
@@ -307,9 +395,9 @@ abstract class AbstractString
        #     assert "ab|\{\}".escape_more_to_c("|\{\}") == "ab\\|\\\{\\\}"
        fun escape_more_to_c(chars: String): String
        do
-               var b = new Buffer
+               var b = new FlatBuffer
                for c in escape_to_c do
-                       if chars.has(c) then
+                       if chars.chars.has(c) then
                                b.add('\\')
                        end
                        b.add(c)
@@ -332,7 +420,7 @@ abstract class AbstractString
        #     assert u[0].ascii      ==  10 # (the ASCII value of the "new line" character)
        fun unescape_nit: String
        do
-               var res = new Buffer.with_capacity(self.length)
+               var res = new FlatBuffer.with_capacity(self.length)
                var was_slash = false
                for c in self do
                        if not was_slash then
@@ -358,14 +446,77 @@ abstract class AbstractString
                end
                return res.to_s
        end
+
+       redef fun ==(o)
+       do
+               if o == null then return false
+               if not o isa Text then return false
+               if self.is_same_instance(o) then return true
+               if self.length != o.length then return false
+               return self.chars == o.chars
+       end
+
+       redef fun <(o)
+       do
+               return self.chars < o.chars
+       end
+
+       # Flat representation of self
+       fun flatten: FlatText is abstract
+
+       redef fun hash
+       do
+               if hash_cache == null then
+                       # djb2 hash algorithm
+                       var h = 5381
+                       var i = length - 1
+
+                       for char in self.chars do
+                               h = (h * 32) + h + char.ascii
+                               i -= 1
+                       end
+
+                       hash_cache = h
+               end
+               return hash_cache.as(not null)
+       end
+
+end
+
+# All kinds of array-based text representations.
+abstract class FlatText
+       super Text
+
+       private var items: NativeString
+
+       # Real items, used as cache for to_cstring is called
+       private var real_items: nullable NativeString = null
+
+       redef var length: Int
+
+       init do end
+
+       redef fun output
+       do
+               var i = 0
+               while i < length do
+                       items[i].output
+                       i += 1
+               end
+       end
+
+       redef fun flatten do return self
 end
 
 # Abstract class for the SequenceRead compatible
 # views on String and Buffer objects
 abstract class StringCharView
        super SequenceRead[Char]
+       super Comparable
+
+       type SELFTYPE: Text
 
-       type SELFTYPE: AbstractString
+       redef type OTHER: StringCharView
 
        private var target: SELFTYPE
 
@@ -378,6 +529,44 @@ abstract class StringCharView
 
        redef fun length do return target.length
 
+       redef fun iterator: IndexedIterator[Char] do return self.iterator_from(0)
+
+       # Gets a new Iterator starting at position `pos`
+       #
+       # Ex :
+       #       var iter = "abcd".iterator_from(2)
+       #       while iter.is_ok do
+       #               printn iter.item
+       #               iter.next
+       #       end
+       #
+       # Outputs : cd
+       fun iterator_from(pos: Int): IndexedIterator[Char] is abstract
+
+       # Gets an iterator starting at the end and going backwards
+       #
+       # Ex :
+       #       var reviter = "now step live...".reverse_iterator
+       #       while reviter.is_ok do
+       #               printn reviter.item
+       #               reviter.next
+       #       end
+       #
+       # Outputs : ...evil pets won
+       fun reverse_iterator: IndexedIterator[Char] do return self.reverse_iterator_from(self.length - 1)
+
+       # Gets an iterator on the chars of self starting from `pos`
+       #
+       # Ex :
+       #       var iter = "abcd".reverse_iterator_from(1)
+       #       while iter.is_ok do
+       #               printn iter.item
+       #               iter.next
+       #       end
+       #
+       # Outputs : ba
+       fun reverse_iterator_from(pos: Int): IndexedIterator[Char] is abstract
+
        redef fun has(c: Char): Bool
        do
                for i in self do
@@ -386,6 +575,36 @@ abstract class StringCharView
                return false
        end
 
+       redef fun ==(other)
+       do
+               if other == null then return false
+               if not other isa StringCharView then return false
+               var other_chars = other.iterator
+               for i in self do
+                       if i != other_chars.item then return false
+                       other_chars.next
+               end
+               return true
+       end
+
+       redef fun <(other)
+       do
+               var self_chars = self.iterator
+               var other_chars = other.iterator
+
+               while self_chars.is_ok and other_chars.is_ok do
+                       if self_chars.item < other_chars.item then return true
+                       if self_chars.item > other_chars.item then return false
+                       self_chars.next
+                       other_chars.next
+               end
+
+               if self_chars.is_ok then
+                       return false
+               else
+                       return true
+               end
+       end
 end
 
 # View on Buffer objects, extends Sequence
@@ -398,21 +617,29 @@ abstract class BufferCharView
 
 end
 
+abstract class String
+       super Text
+
+       redef type SELFTYPE: String
+
+       redef fun to_s do return self
+
+end
+
 # Immutable strings of characters.
-class String
-       super Comparable
-       super AbstractString
-       super StringCapable
+class FlatString
+       super FlatText
+       super String
 
-       redef type OTHER: String
+       redef type SELFTYPE: FlatString
 
        # Index in _items of the start of the string
-       readable var _index_from: Int
+       private var index_from: Int
 
        # Indes in _items of the last item of the string
-       readable var _index_to: Int
+       private var index_to: Int
 
-       redef var chars: StringCharView = new FlatStringCharView(self)
+       redef var chars: SELFVIEW = new FlatStringCharView(self)
 
        ################################################
        #       AbstractString specific methods        #
@@ -422,11 +649,24 @@ class String
                assert index >= 0
                # Check that the index (+ index_from) is not larger than indexTo
                # In other terms, if the index is valid
-               assert (index + _index_from) <= _index_to
-               return _items[index + _index_from]
+               assert (index + index_from) <= index_to
+               return items[index + index_from]
+       end
+
+       redef fun reversed
+       do
+               var native = calloc_string(self.length + 1)
+               var reviter = chars.reverse_iterator
+               var pos = 0
+               while reviter.is_ok do
+                       native[pos] = reviter.item
+                       pos += 1
+                       reviter.next
+               end
+               return native.to_s_with_length(self.length)
        end
 
-       redef fun substring(from: Int, count: Int): String
+       redef fun substring(from, count)
        do
                assert count >= 0
 
@@ -436,56 +676,27 @@ class String
                        from = 0
                end
 
-               var realFrom = _index_from + from
+               var realFrom = index_from + from
 
-               if (realFrom + count) > _index_to then return new String.with_infos(_items, _index_to - realFrom + 1, realFrom, _index_to)
+               if (realFrom + count) > index_to then return new FlatString.with_infos(items, index_to - realFrom + 1, realFrom, index_to)
 
-               if count == 0 then return ""
+               if count == 0 then return empty
 
                var to = realFrom + count - 1
 
-               return new String.with_infos(_items, to - realFrom + 1, realFrom, to)
+               return new FlatString.with_infos(items, to - realFrom + 1, realFrom, to)
        end
 
-       redef fun substring_from(from: Int): String
-       do
-               if from > _length then return ""
-               if from < 0 then from = 0
-               return substring(from, _length)
-       end
-
-       redef fun has_substring(str: String, pos: Int): Bool
-       do
-               var itsindex = str._length - 1
-
-               var myindex = pos + itsindex
-               var myitems = _items
-
-               var itsitems = str._items
-
-               if myindex > _length or itsindex > myindex then return false
-
-               var itsindexfrom = str.index_from
-               itsindex += itsindexfrom
-               myindex += index_from
-
-               while itsindex >= itsindexfrom do
-                       if myitems[myindex] != itsitems[itsindex] then return false
-                       myindex -= 1
-                       itsindex -= 1
-               end
+       redef fun empty do return "".as(FlatString)
 
-               return true
-       end
-
-       redef fun to_upper: String
+       redef fun to_upper
        do
-               var outstr = calloc_string(self._length + 1)
+               var outstr = calloc_string(self.length + 1)
                var out_index = 0
 
-               var myitems = self._items
-               var index_from = self._index_from
-               var max = self._index_to
+               var myitems = self.items
+               var index_from = self.index_from
+               var max = self.index_to
 
                while index_from <= max do
                        outstr[out_index] = myitems[index_from].to_upper
@@ -495,17 +706,17 @@ class String
 
                outstr[self.length] = '\0'
 
-               return outstr.to_s_with_length(self._length)
+               return outstr.to_s_with_length(self.length)
        end
 
-       redef fun to_lower : String
+       redef fun to_lower
        do
-               var outstr = calloc_string(self._length + 1)
+               var outstr = calloc_string(self.length + 1)
                var out_index = 0
 
-               var myitems = self._items
-               var index_from = self._index_from
-               var max = self._index_to
+               var myitems = self.items
+               var index_from = self.index_from
+               var max = self.index_to
 
                while index_from <= max do
                        outstr[out_index] = myitems[index_from].to_lower
@@ -515,35 +726,15 @@ class String
 
                outstr[self.length] = '\0'
 
-               return outstr.to_s_with_length(self._length)
-       end
-
-       redef fun trim: String
-       do
-               if self._length == 0 then return self
-               # find position of the first non white space char (ascii < 32) from the start of the string
-               var start_pos = self._index_from
-               while _items[start_pos].ascii <= 32 do
-                       start_pos += 1
-                       if start_pos == _index_to + 1 then return ""
-               end
-               # find position of the first non white space char from the end of the string
-               var end_pos = _index_to
-               while _items[end_pos].ascii <= 32 do
-                       end_pos -= 1
-                       if end_pos == start_pos then return _items[start_pos].to_s
-               end
-               start_pos -= index_from
-               end_pos -= index_from
-               return self.substring(start_pos, end_pos - start_pos + 1)
+               return outstr.to_s_with_length(self.length)
        end
 
        redef fun output
        do
-               var i = self._index_from
-               var imax = self._index_to
+               var i = self.index_from
+               var imax = self.index_to
                while i <= imax do
-                       _items[i].output
+                       items[i].output
                        i += 1
                end
        end
@@ -554,41 +745,43 @@ class String
 
        private init with_infos(items: NativeString, len: Int, from: Int, to: Int)
        do
-               self._items = items
-               _length = len
-               _index_from = from
-               _index_to = to
+               self.items = items
+               length = len
+               index_from = from
+               index_to = to
        end
 
        # Return a null terminated char *
-       fun to_cstring: NativeString
+       redef fun to_cstring: NativeString
        do
-               if _index_from > 0 or _index_to != items.cstring_length - 1 then
-                       var newItems = calloc_string(_length + 1)
-                       self.items.copy_to(newItems, _length, _index_from, 0)
+               if real_items != null then return real_items.as(not null)
+               if index_from > 0 or index_to != items.cstring_length - 1 then
+                       var newItems = calloc_string(length + 1)
+                       self.items.copy_to(newItems, length, index_from, 0)
                        newItems[length] = '\0'
+                       self.real_items = newItems
                        return newItems
                end
-               return _items
+               return items
        end
 
        redef fun ==(other)
        do
-               if not other isa String then return false
+               if not other isa FlatString then return super
 
                if self.object_id == other.object_id then return true
 
-               var my_length = _length
+               var my_length = length
 
-               if other._length != my_length then return false
+               if other.length != my_length then return false
 
-               var my_index = _index_from
-               var its_index = other._index_from
+               var my_index = index_from
+               var its_index = other.index_from
 
                var last_iteration = my_index + my_length
 
-               var itsitems = other._items
-               var myitems = self._items
+               var itsitems = other.items
+               var myitems = self.items
 
                while my_index < last_iteration do
                        if myitems[my_index] != itsitems[its_index] then return false
@@ -604,19 +797,21 @@ class String
        #     assert ("aa" < "b")      ==  true
        redef fun <(other)
        do
+               if not other isa FlatString then return super
+
                if self.object_id == other.object_id then return false
 
                var my_curr_char : Char
                var its_curr_char : Char
 
-               var curr_id_self = self._index_from
-               var curr_id_other = other._index_from
+               var curr_id_self = self.index_from
+               var curr_id_other = other.index_from
 
-               var my_items = self._items
-               var its_items = other._items
+               var my_items = self.items
+               var its_items = other.items
 
-               var my_length = self._length
-               var its_length = other._length
+               var my_length = self.length
+               var its_length = other.length
 
                var max_iterations = curr_id_self + my_length
 
@@ -639,37 +834,45 @@ class String
        # The concatenation of `self` with `s`
        #
        #     assert "hello " + "world!"         == "hello world!"
-       fun +(s: String): String
+       redef fun +(s)
        do
-               var my_length = self._length
-               var its_length = s._length
+               var my_length = self.length
+               var its_length = s.length
 
                var total_length = my_length + its_length
 
                var target_string = calloc_string(my_length + its_length + 1)
 
-               self._items.copy_to(target_string, my_length, _index_from, 0)
-               s._items.copy_to(target_string, its_length, s._index_from, my_length)
+               self.items.copy_to(target_string, my_length, index_from, 0)
+               if s isa FlatString then
+                       s.items.copy_to(target_string, its_length, s.index_from, my_length)
+               else if s isa FlatBuffer then
+                       s.items.copy_to(target_string, its_length, 0, my_length)
+               else
+                       var curr_pos = my_length
+                       for i in s.chars do
+                               target_string[curr_pos] = i
+                               curr_pos += 1
+                       end
+               end
 
                target_string[total_length] = '\0'
 
                return target_string.to_s_with_length(total_length)
        end
 
-       # `i` repetitions of `self`
-       #
        #     assert "abc"*3           == "abcabcabc"
        #     assert "abc"*1           == "abc"
        #     assert "abc"*0           == ""
-       fun *(i: Int): String
+       redef fun *(i)
        do
                assert i >= 0
 
-               var my_length = self._length
+               var my_length = self.length
 
                var final_length = my_length * i
 
-               var my_items = self._items
+               var my_items = self.items
 
                var target_string = calloc_string((final_length) + 1)
 
@@ -685,38 +888,66 @@ class String
                return target_string.to_s_with_length(final_length)
        end
 
-       redef fun to_s do return self
-
        redef fun hash
        do
-               # djb2 hash algorythm
-               var h = 5381
-               var i = _length - 1
+               if hash_cache == null then
+                       # djb2 hash algorythm
+                       var h = 5381
+                       var i = length - 1
+
+                       var myitems = items
+                       var strStart = index_from
 
-               var myitems = _items
-               var strStart = _index_from
+                       i += strStart
 
-               i += strStart
+                       while i >= strStart do
+                               h = (h * 32) + h + self.items[i].ascii
+                               i -= 1
+                       end
 
-               while i >= strStart do
-                       h = (h * 32) + h + self._items[i].ascii
-                       i -= 1
+                       hash_cache = h
                end
 
-               return h
+               return hash_cache.as(not null)
        end
 end
 
+private class FlatStringReverseIterator
+       super IndexedIterator[Char]
+
+       var target: FlatString
+
+       var target_items: NativeString
+
+       var curr_pos: Int
+
+       init with_pos(tgt: FlatString, pos: Int)
+       do
+               target = tgt
+               target_items = tgt.items
+               curr_pos = pos + tgt.index_from
+       end
+
+       redef fun is_ok do return curr_pos >= 0
+
+       redef fun item do return target_items[curr_pos]
+
+       redef fun next do curr_pos -= 1
+
+       redef fun index do return curr_pos - target.index_from
+
+end
+
 private class FlatStringIterator
        super IndexedIterator[Char]
 
-       var target: String
+       var target: FlatString
 
        var target_items: NativeString
 
        var curr_pos: Int
 
-       init with_pos(tgt: String, pos: Int)
+       init with_pos(tgt: FlatString, pos: Int)
        do
                target = tgt
                target_items = tgt.items
@@ -736,155 +967,265 @@ end
 private class FlatStringCharView
        super StringCharView
 
-       redef type SELFTYPE: String
+       redef type SELFTYPE: FlatString
 
        redef fun [](index)
        do
                # Check that the index (+ index_from) is not larger than indexTo
                # In other terms, if the index is valid
                assert index >= 0
-               assert (index + target._index_from) <= target._index_to
-               return target._items[index + target._index_from]
+               assert (index + target.index_from) <= target.index_to
+               return target.items[index + target.index_from]
        end
 
-       redef fun iterator: IndexedIterator[Char] do return new FlatStringIterator.with_pos(target, 0)
+       redef fun iterator_from(start) do return new FlatStringIterator.with_pos(target, start)
+
+       redef fun reverse_iterator_from(start) do return new FlatStringReverseIterator.with_pos(target, start)
+
+end
+
+abstract class Buffer
+       super Text
+
+       redef type SELFVIEW: BufferCharView
+       redef type SELFTYPE: Buffer
+
+       var is_dirty = true
+
+       # Modifies the char contained at pos `index`
+       #
+       # DEPRECATED : Use self.chars.[]= instead
+       fun []=(index: Int, item: Char) is abstract
+
+       # Adds a char `c` at the end of self
+       #
+       # DEPRECATED : Use self.chars.add instead
+       fun add(c: Char) is abstract
+
+       # Clears the buffer
+       fun clear is abstract
+
+       # Enlarges the subsequent array containing the chars of self
+       fun enlarge(cap: Int) is abstract
+
+       # Adds the content of text `s` at the end of self
+       fun append(s: Text) is abstract
+
+       redef fun hash
+       do
+               if is_dirty then hash_cache = null
+               return super
+       end
 
 end
 
 # Mutable strings of characters.
-class Buffer
-       super AbstractString
-       super Comparable
-       super StringCapable
-       super AbstractArray[Char]
+class FlatBuffer
+       super FlatText
+       super Buffer
+
+       redef type SELFTYPE: FlatBuffer
 
-       redef type OTHER: String
+       redef var chars: SELFVIEW = new FlatBufferCharView(self)
 
-       redef var chars: BufferCharView = new FlatBufferCharView(self)
+       var capacity: Int
 
        redef fun []=(index, item)
        do
+               is_dirty = true
                if index == length then
                        add(item)
                        return
                end
                assert index >= 0 and index < length
-               _items[index] = item
+               items[index] = item
        end
 
        redef fun add(c)
        do
-               if _capacity <= length then enlarge(length + 5)
-               _items[length] = c
-               _length += 1
+               is_dirty = true
+               if capacity <= length then enlarge(length + 5)
+               items[length] = c
+               length += 1
+       end
+
+       redef fun clear do
+               is_dirty = true
+               length = 0
        end
 
+       redef fun empty do return new FlatBuffer
+
        redef fun enlarge(cap)
        do
-               var c = _capacity
+               is_dirty = true
+               var c = capacity
                if cap <= c then return
                while c <= cap do c = c * 2 + 2
                var a = calloc_string(c+1)
-               _items.copy_to(a, length, 0, 0)
-               _items = a
-               _capacity = c
+               items.copy_to(a, length, 0, 0)
+               items = a
+               capacity = c
+               items.copy_to(a, length, 0, 0)
        end
 
-       redef fun append(s)
+       redef fun to_s: String
+       do
+               return to_cstring.to_s_with_length(length)
+       end
+
+       redef fun to_cstring
        do
-               if s isa String then
-                       var sl = s.length
-                       if _capacity < _length + sl then enlarge(_length + sl)
-                       s.items.copy_to(_items, sl, s._index_from, _length)
-                       _length += sl
+               if is_dirty then
+                       var new_native = calloc_string(length + 1)
+                       new_native[length] = '\0'
+                       items.copy_to(new_native, length, 0, 0)
+                       real_items = new_native
+                       is_dirty = false
+               end
+               return real_items.as(not null)
+       end
+
+       # Create a new empty string.
+       init do with_capacity(5)
+
+       init from(s: Text)
+       do
+               capacity = s.length + 1
+               length = s.length
+               items = calloc_string(capacity)
+               if s isa FlatString then
+                       s.items.copy_to(items, length, s.index_from, 0)
+               else if s isa FlatBuffer then
+                       s.items.copy_to(items, length, 0, 0)
                else
-                       super
+                       var curr_pos = 0
+                       for i in s.chars do
+                               items[curr_pos] = i
+                               curr_pos += 1
+                       end
                end
        end
 
-       redef fun to_s: String
+       # Create a new empty string with a given capacity.
+       init with_capacity(cap: Int)
        do
-               var l = length
-               var a = calloc_string(l+1)
-               _items.copy_to(a, l, 0, 0)
+               assert cap >= 0
+               # _items = new NativeString.calloc(cap)
+               items = calloc_string(cap+1)
+               capacity = cap
+               length = 0
+       end
 
-               # Ensure the afterlast byte is '\0' to nul-terminated char *
-               a[length] = '\0'
+       redef fun append(s)
+       do
+               is_dirty = true
+               var sl = s.length
+               if capacity < length + sl then enlarge(length + sl)
+               if s isa FlatString then
+                       s.items.copy_to(items, sl, s.index_from, length)
+               else if s isa FlatBuffer then
+                       s.items.copy_to(items, sl, 0, length)
+               else
+                       var curr_pos = self.length
+                       for i in s.chars do
+                               items[curr_pos] = i
+                               curr_pos += 1
+                       end
+               end
+               length += sl
+       end
 
-               return a.to_s_with_length(length)
+       # Copies the content of self in `dest`
+       fun copy(start: Int, len: Int, dest: Buffer, new_start: Int)
+       do
+               var self_chars = self.chars
+               var dest_chars = dest.chars
+               for i in [0..len-1] do
+                       dest_chars[new_start+i] = self_chars[start+i]
+               end
        end
 
-       redef fun <(s)
+       redef fun substring(from, count)
        do
-               var i = 0
-               var l1 = length
-               var l2 = s.length
-               while i < l1 and i < l2 do
-                       var c1 = self.chars[i].ascii
-                       var c2 = s.chars[i].ascii
-                       if c1 < c2 then
-                               return true
-                       else if c2 < c1 then
-                               return false
+               assert count >= 0
+               count += from
+               if from < 0 then from = 0
+               if count > length then count = length
+               if from < count then
+                       var r = new FlatBuffer.with_capacity(count - from)
+                       while from < count do
+                               r.chars.push(items[from])
+                               from += 1
                        end
-                       i += 1
-               end
-               if l1 < l2 then
-                       return true
+                       return r
                else
-                       return false
+                       return new FlatBuffer
                end
        end
 
-       # Create a new empty string.
-       init
+       redef fun reversed
        do
-               with_capacity(5)
+               var new_buf = new FlatBuffer.with_capacity(self.length)
+               var reviter = self.chars.reverse_iterator
+               while reviter.is_ok do
+                       new_buf.add(reviter.item)
+                       reviter.next
+               end
+               return new_buf
        end
 
-       init from(s: String)
+       redef fun +(other)
        do
-               _capacity = s.length + 1
-               _length = s.length
-               _items = calloc_string(_capacity)
-               s.items.copy_to(_items, _length, s._index_from, 0)
+               var new_buf = new FlatBuffer.with_capacity(self.length + other.length)
+               new_buf.append(self)
+               new_buf.append(other)
+               return new_buf
        end
 
-       # Create a new empty string with a given capacity.
-       init with_capacity(cap: Int)
+       redef fun *(repeats)
        do
-               assert cap >= 0
-               # _items = new NativeString.calloc(cap)
-               _items = calloc_string(cap+1)
-               _capacity = cap
-               _length = 0
+               var new_buf = new FlatBuffer.with_capacity(self.length * repeats)
+               for i in [0..repeats[ do
+                       new_buf.append(self)
+               end
+               return new_buf
        end
+end
 
-       redef fun ==(o)
+private class FlatBufferReverseIterator
+       super IndexedIterator[Char]
+
+       var target: FlatBuffer
+
+       var target_items: NativeString
+
+       var curr_pos: Int
+
+       init with_pos(tgt: FlatBuffer, pos: Int)
        do
-               if not o isa Buffer then return false
-               var l = length
-               if o.length != l then return false
-               var i = 0
-               var it = _items
-               var oit = o._items
-               while i < l do
-                       if it[i] != oit[i] then return false
-                       i += 1
-               end
-               return true
+               target = tgt
+               target_items = tgt.items
+               curr_pos = pos
        end
 
-       readable private var _capacity: Int
+       redef fun index do return curr_pos
+
+       redef fun is_ok do return curr_pos >= 0
+
+       redef fun item do return target_items[curr_pos]
+
+       redef fun next do curr_pos -= 1
+
 end
 
 private class FlatBufferCharView
        super BufferCharView
        super StringCapable
 
-       redef type SELFTYPE: Buffer
+       redef type SELFTYPE: FlatBuffer
 
-       redef fun [](index) do return target._items[index]
+       redef fun [](index) do return target.items[index]
 
        redef fun []=(index, item)
        do
@@ -893,7 +1234,7 @@ private class FlatBufferCharView
                        add(item)
                        return
                end
-               target._items[index] = item
+               target.items[index] = item
        end
 
        redef fun push(c)
@@ -918,20 +1259,22 @@ private class FlatBufferCharView
                if target.capacity < s.length then enlarge(s_length + target.length)
        end
 
-       redef fun iterator: IndexedIterator[Char] do return new FlatBufferIterator.with_pos(target, 0)
+       redef fun iterator_from(pos) do return new FlatBufferIterator.with_pos(target, pos)
+
+       redef fun reverse_iterator_from(pos) do return new FlatBufferReverseIterator.with_pos(target, pos)
 
 end
 
 private class FlatBufferIterator
        super IndexedIterator[Char]
 
-       var target: Buffer
+       var target: FlatBuffer
 
        var target_items: NativeString
 
        var curr_pos: Int
 
-       init with_pos(tgt: Buffer, pos: Int)
+       init with_pos(tgt: FlatBuffer, pos: Int)
        do
                target = tgt
                target_items = tgt.items
@@ -1041,7 +1384,7 @@ redef class Int
        fun to_base(base: Int, signed: Bool): String
        do
                var l = digit_count(base)
-               var s = new Buffer.from(" " * l)
+               var s = new FlatBuffer.from(" " * l)
                fill_buffer(s, base, signed)
                return s.to_s
        end
@@ -1116,7 +1459,7 @@ redef class Char
        #     assert 'x'.to_s    == "x"
        redef fun to_s
        do
-               var s = new Buffer.with_capacity(1)
+               var s = new FlatBuffer.with_capacity(1)
                s.chars[0] = self
                return s.to_s
        end
@@ -1150,7 +1493,7 @@ redef class Collection[E]
        # Concatenate elements.
        redef fun to_s
        do
-               var s = new Buffer
+               var s = new FlatBuffer
                for e in self do if e != null then s.append(e.to_s)
                return s.to_s
        end
@@ -1163,7 +1506,7 @@ redef class Collection[E]
        do
                if is_empty then return ""
 
-               var s = new Buffer # Result
+               var s = new FlatBuffer # Result
 
                # Concat first item
                var i = iterator
@@ -1186,7 +1529,7 @@ redef class Array[E]
        # Fast implementation
        redef fun to_s
        do
-               var s = new Buffer
+               var s = new FlatBuffer
                var i = 0
                var l = length
                while i < l do
@@ -1211,7 +1554,7 @@ redef class Map[K,V]
        do
                if is_empty then return ""
 
-               var s = new Buffer # Result
+               var s = new FlatBuffer # Result
 
                # Concat first item
                var i = iterator
@@ -1259,18 +1602,18 @@ class NativeString
                return to_s_with_length(cstring_length)
        end
 
-       fun to_s_with_length(length: Int): String
+       fun to_s_with_length(length: Int): FlatString
        do
                assert length >= 0
-               return new String.with_infos(self, length, 0, length - 1)
+               return new FlatString.with_infos(self, length, 0, length - 1)
        end
 
-       fun to_s_with_copy: String
+       fun to_s_with_copy: FlatString
        do
                var length = cstring_length
                var new_self = calloc_string(length + 1)
                copy_to(new_self, length, 0, 0)
-               return new String.with_infos(new_self, length, 0, length - 1)
+               return new FlatString.with_infos(new_self, length, 0, length - 1)
        end
 
 end
index 6cd67c4..846de56 100644 (file)
@@ -45,10 +45,10 @@ interface Pattern
        # Search all `self` occurrences into `s`.
        #
        #     assert 'l'.search_all_in("hello world").length  == 3
-       #     assert 'z'.search_all_in("hello world"),length  == 0
+       #     assert 'z'.search_all_in("hello world").length  == 0
        #
        # Note: Is used by `String::search_all`.
-       fun search_all_in(s: String): Array[Match]
+       protected fun search_all_in(s: String): Array[Match]
        do
                var res = new Array[Match] # Result
                var match = search_in(s, 0)
@@ -68,7 +68,7 @@ interface Pattern
        #     assert 'z'.split_in("hello world").join("|")  == "hello world"
        #
        # Note: is used by `String::split`
-       fun split_in(s: String): Array[Match]
+       protected fun split_in(s: String): Array[Match]
        do
                var res = new Array[Match] # Result
                var i = 0 # Cursor
index 0db3b4d..96948ea 100644 (file)
@@ -238,7 +238,7 @@ redef class ANewExpr
                if args != null then
                        n_args.n_exprs.add_all(args)
                end
-               callsite = new CallSite(self, mtype, true, mmethod, mmethod.intro, mmethod.intro.msignature.as(not null), false)
+               callsite = new CallSite(self, mtype, mmethod.intro.mclassdef.mmodule, mtype, true, mmethod, mmethod.intro, mmethod.intro.msignature.as(not null), false)
                self.mtype = mtype
        end
 end
@@ -255,7 +255,7 @@ redef class ACallExpr
                        self.n_args.n_exprs.add_all(args)
                end
                var mtype = recv.mtype.as(not null)
-               callsite = new CallSite(self, mtype, true, mmethod, mmethod.intro, mmethod.intro.msignature.as(not null), false)
+               callsite = new CallSite(self, mtype, mmethod.intro.mclassdef.mmodule, mmethod.intro.mclassdef.bound_mtype, true, mmethod, mmethod.intro, mmethod.intro.msignature.as(not null), false)
                self.mtype = t
                self.is_typed = true
        end
index f304d04..8e210cc 100644 (file)
@@ -106,7 +106,7 @@ redef class AConcreteMethPropdef
                        var msignature = candidatedef.msignature
                        msignature = msignature.resolve_for(recvtype, anchor, mmodule, true)
 
-                       var callsite = new CallSite(self, recvtype, true, candidate, candidatedef, msignature, false)
+                       var callsite = new CallSite(self, recvtype, mmodule, anchor, true, candidate, candidatedef, msignature, false)
                        auto_super_inits.add(callsite)
                end
                if auto_super_inits.is_empty then
index 3d5fbb6..ee2f52f 100644 (file)
@@ -305,28 +305,35 @@ redef class MNullableType
        do
                super
 
+               var base_cname = "null_{mtype.mangled_cname}"
+               var full_cname = "NIT_NULL___{base_cname}"
+
                # In nitni files, declare internal function as extern 
-               var full_friendly_csignature = "{cname} {v.compiler.mainmodule.name}___null_{mtype.mangled_cname}()"
+               var full_friendly_csignature = "{cname_blind} {full_cname}()"
                ccu.header_decl.add("extern {full_friendly_csignature};\n")
 
                # In nitni files, #define friendly as extern
-               var base_cname = "null_{mtype.mangled_cname}"
-               ccu.header_decl.add("#define {base_cname} {v.compiler.mainmodule.name}___{base_cname}\n")
+               ccu.header_decl.add("#define {base_cname} {full_cname}\n")
+
+               # FIXME: This is ugly an broke the separate compilation principle
+               # The real function MUST be compiled only once, #define pragma only protect the compiler, not the loader
+               # However, I am not sure of the right approach here (eg. week refs are ugly)
+               if is_already_compiled then return
+               is_already_compiled = true
 
                # Internally, implement internal function
                var nitni_visitor = v.compiler.new_visitor
                nitni_visitor.frame = v.frame
-               var full_internal_csignature = "{cname_blind} {v.compiler.mainmodule.name}___null_{mtype.mangled_cname}()"
-               nitni_visitor.add("#ifndef NIT_NULL_null_{mtype.mangled_cname}")
-               nitni_visitor.add("#define NIT_NULL_null_{mtype.mangled_cname}")
+               var full_internal_csignature = "{cname_blind} {full_cname}()"
                nitni_visitor.add("{full_internal_csignature} \{")
                nitni_visitor.add("struct nitni_instance* ret_for_c;")
                nitni_visitor.add("ret_for_c = malloc(sizeof(struct nitni_instance));")
                nitni_visitor.add("ret_for_c->value = NULL;")
                nitni_visitor.add("return ret_for_c;")
                nitni_visitor.add("\}")
-               nitni_visitor.add("#endif")
        end
+
+       private var is_already_compiled = false # FIXME to remove, show above
 end
 
 redef class MExplicitCall
index 02276be..a73bab5 100644 (file)
@@ -109,7 +109,7 @@ redef class ToolContext
                                message_sorter.sort(messages)
 
                                for m in messages do
-                                       if "Warning".search_in(m.text, 0) == null then had_error = true
+                                       if m.text.search("Warning") == null then had_error = true
                                        stderr.write("{m.to_color_string}\n")
                                end
                        end
@@ -480,7 +480,7 @@ class Debugger
                else if command == "nit" then
                        printn "$~> "
                        command = gets
-                       var nit_buf = new Buffer
+                       var nit_buf = new FlatBuffer
                        while not command == ":q" do
                                nit_buf.append(command)
                                nit_buf.append("\n")
@@ -818,10 +818,10 @@ class Debugger
 
        # Gets all the identifiers of an instruction (uses the rules of Nit as of Mar 05 2013)
        #
-       fun get_identifiers_in_current_instruction(instruction: AbstractString): Array[String]
+       fun get_identifiers_in_current_instruction(instruction: Text): Array[String]
        do
                var result_array = new Array[String]
-               var instruction_buffer = new Buffer
+               var instruction_buffer = new FlatBuffer
 
                var trigger_char_escape = false
                var trigger_string_escape = false
@@ -866,9 +866,9 @@ class Debugger
 
        # Takes a function call or declaration and strips all but the arguments
        #
-       fun get_function_arguments(function: AbstractString): String
+       fun get_function_arguments(function: Text): String
        do
-               var buf = new Buffer
+               var buf = new FlatBuffer
                var trigger_copy = false
 
                for i in function.chars do
@@ -904,7 +904,7 @@ class Debugger
        fun get_real_variable_name(name: String): String
        do
                var explode_string = name.split_with(".")
-               var final_string = new Buffer
+               var final_string = new FlatBuffer
                for i in explode_string do
                        var alias_resolved = get_variable_name_by_alias(i)
                        if alias_resolved != null then
@@ -1152,7 +1152,7 @@ class Debugger
        # Returns an array containing their content
        fun remove_braces(braces: String): nullable Array[String]
        do
-               var buffer = new Buffer
+               var buffer = new FlatBuffer
 
                var result_array = new Array[String]
 
index bcb66ba..a85f889 100644 (file)
@@ -902,8 +902,8 @@ private class CustomizedRuntimeFunction
                var frame = new Frame(v, mmethoddef, recv, arguments)
                v.frame = frame
 
-               var sig = new Buffer
-               var comment = new Buffer
+               var sig = new FlatBuffer
+               var comment = new FlatBuffer
                var ret = mmethoddef.msignature.return_mtype
                if ret != null then
                        ret = v.resolve_for(ret, selfvar)
index 753acea..2737580 100644 (file)
@@ -193,7 +193,7 @@ class Location
                        lmid = ""
                        lend = ""
                end
-               var indent = new Buffer
+               var indent = new FlatBuffer
                for j in [line_start..line_start+l.column_start-1[ do
                        if string.chars[j] == '\t' then
                                indent.add '\t'
index 7a85a5d..455ed83 100644 (file)
@@ -67,7 +67,7 @@ end
 # Create a dot file representing the class hierarchy of a model.
 fun generate_class_hierarchy(toolcontext: ToolContext, mmodule: MModule)
 do
-       var buf = new Buffer
+       var buf = new FlatBuffer
        buf.append("digraph \{\n")
        buf.append("node [shape=box];\n")
        buf.append("rankdir=BT;\n")
@@ -88,7 +88,7 @@ end
 # For a simple user of the model, the classdef hierarchy is not really usefull, it is more an internal thing.
 fun generate_classdef_hierarchy(toolcontext: ToolContext, model: Model)
 do
-       var buf = new Buffer
+       var buf = new FlatBuffer
        buf.append("digraph \{\n")
        buf.append("node [shape=box];\n")
        buf.append("rankdir=BT;\n")
index 6cffa50..ae7fccf 100644 (file)
@@ -39,7 +39,7 @@ end
 # The generated file contains the description of each entity of the model
 fun generate_model_hyperdoc(toolcontext: ToolContext, model: Model)
 do
-       var buf = new Buffer
+       var buf = new FlatBuffer
        buf.append("<html>\n<body>\n")
        buf.append("<h1>Model</h1>\n")
 
index 7e31319..40408f3 100644 (file)
@@ -80,12 +80,40 @@ private class RTAMetricsPhase
                gmetrics.to_console(1, not toolcontext.opt_nocolors.value)
                if csv then gmetrics.to_csv.save("{out}/complexity.csv")
 
+               callsite_info(analysis)
+
                # dump type and method infos
                if csv then
                        analysis.live_types_to_csv.save("{out}/rta_types.csv")
                        analysis.live_methods_to_tree.write_to_file("{out}/rta_methods.dat")
                end
        end
+
+       fun callsite_info(rta: RapidTypeAnalysis)
+       do
+               print toolcontext.format_h2("\n ## Callsites")
+               print "* {rta.live_callsites.length} live callsites"
+
+               var csep = new Counter[MPropDef]
+               var cglo = new Counter[MPropDef]
+               var morphisme = new Counter[Int]
+               for cs in rta.live_callsites do
+                       csep.inc(cs.mpropdef)
+                       var targets = rta.live_targets(cs)
+                       for d in targets do
+                               cglo.inc(d)
+                       end
+                       morphisme.inc(targets.length)
+               end
+
+               print toolcontext.format_h3("MMethodDef locally designated (by number of CallSites)")
+               csep.print_summary
+               csep.print_elements(5)
+
+               print toolcontext.format_h3("MMethodDef possibly invoked at runtime (by number of CallSites)")
+               cglo.print_summary
+               cglo.print_elements(5)
+       end
 end
 
 # Summary metrics
index 79fee97..5c76a56 100644 (file)
@@ -1418,7 +1418,7 @@ class MSignature
 
        redef fun to_s
        do
-               var b = new Buffer
+               var b = new FlatBuffer
                if not mparameters.is_empty then
                        b.append("(")
                        for i in [0..mparameters.length[ do
index 409b66b..39df50b 100644 (file)
@@ -59,8 +59,8 @@ class MVisibility
        end
 end
 
-fun intrude_visibility: MVisibility do return once new MVisibility("intrude", 4)
+fun intrude_visibility: MVisibility do return once new MVisibility("intrude", 5)
 fun public_visibility: MVisibility do return once new MVisibility("public", 4)
 fun protected_visibility: MVisibility do return once new MVisibility("protected", 3)
 fun private_visibility: MVisibility do return once new MVisibility("private", 2)
-fun none_visibility: MVisibility do return once new MVisibility("none", 2)
+fun none_visibility: MVisibility do return once new MVisibility("none", 1)
index b916077..ef75a3f 100644 (file)
@@ -43,10 +43,13 @@ redef class ToolContext
        # Option --only-parse
        var opt_only_parse: OptionBool = new OptionBool("Only proceed to parse step of loaders", "--only-parse")
 
+       # Option --ignore-visibility
+       var opt_ignore_visibility: OptionBool = new OptionBool("Do not check, and produce errors, on visibility issues.", "--ignore-visibility")
+
        redef init
        do
                super
-               option_context.add_option(opt_path, opt_only_parse, opt_only_metamodel)
+               option_context.add_option(opt_path, opt_only_parse, opt_only_metamodel, opt_ignore_visibility)
        end
 
        fun modelbuilder: ModelBuilder do return modelbuilder_real.as(not null)
@@ -65,6 +68,7 @@ redef class ToolContext
                        mainmodule.set_imported_mmodules(mmodules)
                end
                for phase in phases_list do
+                       if phase.disabled then continue
                        phase.process_mainmodule(mainmodule, mmodules)
                end
        end
index 730ea74..4bd3267 100644 (file)
@@ -249,7 +249,7 @@ private class NaiveInterpreter
        # Return a new native string initialized with `txt`
        fun native_string_instance(txt: String): Instance
        do
-               var val = new Buffer.from(txt)
+               var val = new FlatBuffer.from(txt)
                val.add('\0')
                var ic = self.mainmodule.get_primitive_class("NativeString")
                return new PrimitiveInstance[Buffer](ic.mclass_type, val)
@@ -264,7 +264,7 @@ private class NaiveInterpreter
        # Return a stack stace. One line per function
        fun stack_trace: String
        do
-               var b = new Buffer
+               var b = new FlatBuffer
                b.append(",---- Stack trace -- - -  -\n")
                for f in frames do
                        b.append("| {f.mpropdef} ({f.current_node.location})\n")
@@ -771,7 +771,7 @@ redef class AInternMethPropdef
                                return null
                        else if pname == "copy_to" then
                                # sig= copy_to(dest: NativeString, length: Int, from: Int, to: Int)
-                               var destval = args[1].val.as(Buffer)
+                               var destval = args[1].val.as(FlatBuffer)
                                var lenval = args[2].to_i
                                var fromval = args[3].to_i
                                var toval = args[4].to_i
@@ -787,7 +787,7 @@ redef class AInternMethPropdef
                                if toval + lenval >= destval.length then
                                        debug("Illegal access on {destval} for element {toval}+{lenval}/{destval.length}")
                                end
-                               recvval.copy(fromval, lenval, destval, toval)
+                               recvval.as(FlatBuffer).copy(fromval, lenval, destval, toval)
                                return null
                        else if pname == "atoi" then
                                return v.int_instance(recvval.to_i)
@@ -874,12 +874,12 @@ redef class AExternMethPropdef
                        var recvval = args.first.val
                        if pname == "io_write" then
                                var a1 = args[1].val.as(Buffer)
-                               recvval.as(OStream).write(a1.substring(0, args[2].to_i))
+                               recvval.as(OStream).write(a1.substring(0, args[2].to_i).to_s)
                                return args[2]
                        else if pname == "io_read" then
                                var str = recvval.as(IStream).read(args[2].to_i)
                                var a1 = args[1].val.as(Buffer)
-                               new Buffer.from(str).copy(0, str.length, a1, 0)
+                               new FlatBuffer.from(str).copy(0, str.length, a1.as(FlatBuffer), 0)
                                return v.int_instance(str.length)
                        else if pname == "io_close" then
                                recvval.as(IOS).close
index cac7dd5..7fc38aa 100644 (file)
@@ -152,7 +152,7 @@ redef class Stdin
        var connection: nullable Socket = null
 
        # Used to store data that has been read from the connection
-       var buf: Buffer = new Buffer
+       var buf: Buffer = new FlatBuffer
        var buf_pos: Int = 0
 
        # Checks if data is available for reading
@@ -165,7 +165,7 @@ redef class Stdin
        # Blocking if the buffer is empty
        redef fun read_all
        do
-               var loc_buf = new Buffer
+               var loc_buf = new FlatBuffer
                if connection.ready_to_read(0) then buf.append(connection.read)
                for i in [buf_pos .. buf.length-1] do loc_buf.add(buf.chars[i])
                buf.clear
@@ -193,7 +193,7 @@ redef class Stdin
        # If the buffer is empty, the read_line call is blocking
        redef fun read_line
        do
-               var line_buf = new Buffer
+               var line_buf = new FlatBuffer
                if connection.ready_to_read(0) then buf.append(connection.read)
                var has_found_eol: Bool = false
                loop
index 3b06cf5..4b01ecd 100644 (file)
@@ -89,7 +89,7 @@ class DebugClient
 
        fun read_command: String
        do
-               var buff = new Buffer
+               var buff = new FlatBuffer
                while debugger_connection.ready_to_read(40) do buff.append(debugger_connection.read)
                return buff.to_s
        end
index 57af655..4715068 100644 (file)
@@ -436,7 +436,7 @@ class NitdocOverview
                        end
                end
                # build graph
-               var op = new Buffer
+               var op = new FlatBuffer
                op.append("digraph dep \{ rankdir=BT; node[shape=none,margin=0,width=0,height=0,fontsize=10]; edge[dir=none,color=gray]; ranksep=0.2; nodesep=0.1;\n")
                for mmodule in poset do
                        op.append("\"{mmodule.name}\"[URL=\"{mmodule.url}\"];\n")
@@ -707,7 +707,7 @@ class NitdocModule
                        end
                end
                # build graph
-               var op = new Buffer
+               var op = new FlatBuffer
                var name = "dep_{mmodule.name}"
                op.append("digraph {name} \{ rankdir=BT; node[shape=none,margin=0,width=0,height=0,fontsize=10]; edge[dir=none,color=gray]; ranksep=0.2; nodesep=0.1;\n")
                for mmodule in poset do
@@ -1091,7 +1091,7 @@ class NitdocClass
                end
                cla.add_all(pe.greaters)
 
-               var op = new Buffer
+               var op = new FlatBuffer
                var name = "dep_{mclass.name}"
                op.append("digraph {name} \{ rankdir=BT; node[shape=none,margin=0,width=0,height=0,fontsize=10]; edge[dir=none,color=gray]; ranksep=0.2; nodesep=0.1;\n")
                for c in cla do
@@ -1132,7 +1132,7 @@ redef class MModule
        #       module_owner_name.html
        private fun url: String do
                if url_cache == null then
-                       var res = new Buffer
+                       var res = new FlatBuffer
                        res.append("module_")
                        var mowner = public_owner
                        if mowner != null then
@@ -1149,7 +1149,7 @@ redef class MModule
        #       MOD_owner_name
        private fun anchor: String do
                if anchor_cache == null then
-                       var res = new Buffer
+                       var res = new FlatBuffer
                        res.append("MOD_")
                        var mowner = public_owner
                        if mowner != null then
@@ -1166,7 +1166,7 @@ redef class MModule
        #       <a href="url" title="short_comment">html_name</a>
        private fun html_link(page: NitdocPage) do
                if html_link_cache == null then
-                       var res = new Buffer
+                       var res = new FlatBuffer
                        if page.ctx.mbuilder.mmodule2nmodule.has_key(self) then
                                res.append("<a href='{url}' title='{page.ctx.mbuilder.mmodule2nmodule[self].short_comment}'>{html_name}</a>")
                        else
@@ -1278,7 +1278,7 @@ redef class MClass
        #       <a href="url" title="short_comment">html_name(signature)</a>
        private fun html_link(page: NitdocPage) do
                if html_link_cache == null then
-                       var res = new Buffer
+                       var res = new FlatBuffer
                        res.append("<a href='{url}'")
                        if page.ctx.mbuilder.mclassdef2nclassdef.has_key(intro) then
                                var nclass = page.ctx.mbuilder.mclassdef2nclassdef[intro]
@@ -1297,7 +1297,7 @@ redef class MClass
        #       <a href="url" title="short_comment">html_name</a>
        private fun html_short_link(page: NitdocPage) do
                if html_short_link_cache == null then
-                       var res = new Buffer
+                       var res = new FlatBuffer
                        res.append("<a href='{url}'")
                        if page.ctx.mbuilder.mclassdef2nclassdef.has_key(intro) then
                                var nclass = page.ctx.mbuilder.mclassdef2nclassdef[intro]
@@ -1316,7 +1316,7 @@ redef class MClass
        #       <a href="url" title="short_comment">html_name</a>
        private fun html_link_anchor(page: NitdocPage) do
                if html_link_anchor_cache == null then
-                       var res = new Buffer
+                       var res = new FlatBuffer
                        res.append("<a href='#{anchor}'")
                        if page.ctx.mbuilder.mclassdef2nclassdef.has_key(intro) then
                                var nclass = page.ctx.mbuilder.mclassdef2nclassdef[intro]
@@ -1578,7 +1578,7 @@ redef class MPropDef
        #       <a href="url" title="short_comment">html_name</a>
        private fun html_link(page: NitdocPage) do
                if html_link_cache == null then
-                       var res = new Buffer
+                       var res = new FlatBuffer
                        if page.ctx.mbuilder.mpropdef2npropdef.has_key(self) then
                                var nprop = page.ctx.mbuilder.mpropdef2npropdef[self]
                                res.append("<a href=\"{url}\" title=\"{nprop.short_comment}\">{mproperty.html_name}</a>")
@@ -1741,7 +1741,7 @@ redef class MSignature
        end
 
        private fun untyped_signature(page: NitdocPage): String do
-               var res = new Buffer
+               var res = new FlatBuffer
                if not mparameters.is_empty then
                        res.append("(")
                        for i in [0..mparameters.length[ do
@@ -1781,7 +1781,7 @@ redef class ADoc
        end
 
        private fun full_comment: String do
-               var res = new Buffer
+               var res = new FlatBuffer
                for t in n_comment do
                        var text = t.text
                        text = text.substring_from(1)
index 4dceda0..b429a19 100644 (file)
@@ -93,7 +93,7 @@ class NitUnitExecutor
                end
                f.close
 
-               var cmd = "../bin/nitg --no-color '{file}' -I . >'{file}.out1' 2>&1 </dev/null -o '{file}.bin'"
+               var cmd = "../bin/nitg --ignore-visibility --no-color '{file}' -I . >'{file}.out1' 2>&1 </dev/null -o '{file}.bin'"
                var res = sys.system(cmd)
                var res2 = 0
                if res == 0 then
index d70c9e3..7f865b1 100644 (file)
@@ -352,7 +352,7 @@ private class PagerMatchesRenderer
 end
 
 private class Pager
-       var content = new Buffer
+       var content = new FlatBuffer
        var indent = 0
        fun add(text: String) do
                add_indent
@@ -458,7 +458,7 @@ redef class MClass
        # return the generic signature of the class
        #       [E, F]
        private fun signature: String do
-               var res = new Buffer
+               var res = new FlatBuffer
                if arity > 0 then
                        res.append("[")
                        for i in [0..intro.parameter_names.length[ do
@@ -474,7 +474,7 @@ redef class MClass
        # class name is displayed with colors depending on visibility
        #       abstract interface Foo[E]
        private fun prototype: String do
-               var res = new Buffer
+               var res = new FlatBuffer
                res.append("{kind} ")
                if visibility.to_s == "public" then res.append("{name}{signature}".bold.green)
                if visibility.to_s == "private" then res.append("{name}{signature}".bold.red)
@@ -568,7 +568,7 @@ redef class MClassDef
        end
 
        fun to_console: String do
-               var res = new Buffer
+               var res = new FlatBuffer
                if not is_intro then res.append("redef ")
                res.append(mclass.prototype)
                return res.to_s
@@ -692,7 +692,7 @@ end
 
 redef class MMethodDef
        redef fun to_console do
-               var res = new Buffer
+               var res = new FlatBuffer
                if not is_intro then res.append("redef ")
                if not mproperty.is_init then res.append("fun ")
                res.append(mproperty.to_console.bold)
@@ -707,7 +707,7 @@ end
 
 redef class MVirtualTypeDef
        redef fun to_console do
-               var res = new Buffer
+               var res = new FlatBuffer
                res.append("type ")
                res.append(mproperty.to_console.bold)
                res.append(": {bound.to_console}")
@@ -717,7 +717,7 @@ end
 
 redef class MAttributeDef
        redef fun to_console do
-               var res = new Buffer
+               var res = new FlatBuffer
                res.append("var ")
                res.append(mproperty.to_console.bold)
                res.append(": {static_mtype.to_console}")
@@ -727,7 +727,7 @@ end
 
 redef class MSignature
        redef fun to_console do
-               var res = new Buffer
+               var res = new FlatBuffer
                if not mparameters.is_empty then
                        res.append("(")
                        for i in [0..mparameters.length[ do
@@ -745,7 +745,7 @@ end
 
 redef class MParameter
        fun to_console: String do
-               var res = new Buffer
+               var res = new FlatBuffer
                res.append("{name}: {mtype.to_console}")
                if is_vararg then res.append("...")
                return res.to_s
@@ -762,7 +762,7 @@ end
 
 redef class MGenericType
        redef fun to_console do
-               var res = new Buffer
+               var res = new FlatBuffer
                res.append("{mclass.name}[")
                for i in [0..arguments.length[ do
                        res.append(arguments[i].to_console)
@@ -837,7 +837,7 @@ redef class String
 
        private fun escape: String
        do
-               var b = new Buffer
+               var b = new FlatBuffer
                for c in self.chars do
                        if c == '\n' then
                                b.append("\\n")
index 3a93084..ace2cb9 100644 (file)
@@ -27,6 +27,43 @@ redef class ToolContext
        # it is often simpler to use the constructor in `Phase`
        var phases = new POSet[Phase]
 
+       # --disable-phase
+       var opt_disable_phase = new OptionArray("DEBUG: Disable a specific phase; use `list` to get the list.", "--disable-phase")
+
+       redef init
+       do
+               super
+
+               option_context.add_option(opt_disable_phase)
+       end
+
+       redef fun process_options(args)
+       do
+               super
+
+               for v in opt_disable_phase.value do
+                       if v == "list" then
+                               for p in phases_list do
+                                       var deps = p.in_hierarchy.direct_greaters
+                                       if deps.is_empty then
+                                               print p
+                                       else
+                                               print "{p} (dep: {deps.join(", ")})"
+                                       end
+                               end
+                               exit 0
+                       end
+
+                       var found = false
+                       for p in phases do
+                               if v != p.to_s then continue
+                               found = true
+                               p.disabled = true
+                       end
+                       if not found then fatal_error(null, "Error: no phase named `{v}`. Use `list` to list all phases.")
+               end
+       end
+
        fun phases_list: Sequence[Phase]
        do
                var phases = self.phases.to_a
@@ -44,13 +81,14 @@ redef class ToolContext
                var phases = phases_list
 
                for phase in phases do
-                       self.info(" registered phases: {phase.class_name}", 2)
+                       self.info(" registered phases: {phase}", 2)
                end
 
                for nmodule in nmodules do
                        self.info("Semantic analysis module {nmodule.location.file.filename}", 2)
                        for phase in phases do
-                               self.info(" phase: {phase.class_name}", 3)
+                               if phase.disabled then continue
+                               self.info(" phase: {phase}", 3)
                                assert phase.toolcontext == self
                                var errcount = self.error_count
                                phase.process_nmodule(nmodule)
@@ -60,7 +98,7 @@ redef class ToolContext
                                end
                                errcount = self.error_count
                                for nclassdef in nmodule.n_classdefs do
-                                       self.info(" phase: {phase.class_name} for {nclassdef.location}", 3)
+                                       self.info(" phase: {phase} for {nclassdef.location}", 3)
                                        assert phase.toolcontext == self
                                        phase.process_nclassdef(nclassdef)
                                        for npropdef in nclassdef.n_propdefs do
@@ -122,6 +160,13 @@ abstract class Phase
                end
        end
 
+       # By default, the name is the lowercased prefix of the classname
+       redef fun to_s do return class_name.strip_extension("Phase").to_lower
+
+       # Is the phase globally disabled?
+       # A disabled phase is not called automatically called by `ToolContext::run_phases` and cie.
+       var disabled = false
+
        # Specific actions to execute on the whole tree of a module
        # @toimplement
        fun process_nmodule(nmodule: AModule) do end
index aad2de0..c68d33a 100644 (file)
@@ -31,6 +31,8 @@ import auto_super_init
 import csv # for live_types_to_csv
 import ordered_tree # for live_methods_to_tree
 
+private import more_collections
+
 redef class ModelBuilder
        fun do_rapid_type_analysis(mainmodule: MModule): RapidTypeAnalysis
        do
@@ -75,6 +77,36 @@ class RapidTypeAnalysis
        # Live methods.
        var live_methods = new HashSet[MMethod]
 
+       # Live callsites.
+       var live_callsites = new HashSet[CallSite]
+
+       private var live_targets_cache = new HashMap2[MType, MProperty, Set[MMethodDef]]
+
+       # The live targets of a specific callsite.
+       fun live_targets(callsite: CallSite): Set[MMethodDef]
+       do
+               var mtype = callsite.recv
+               var anchor = callsite.anchor
+               if anchor != null then mtype = mtype.anchor_to(callsite.mmodule, anchor)
+               if mtype isa MNullableType then mtype = mtype.mtype
+               assert mtype isa MClassType
+               mtype = mtype.mclass.intro.bound_mtype
+               var mproperty = callsite.mproperty
+               var res = live_targets_cache[mtype, mproperty]
+               if res != null then return res
+               res = new ArraySet[MMethodDef]
+               live_targets_cache[mtype, mproperty] = res
+
+               for c in live_classes do
+                       var tc = c.intro.bound_mtype
+                       if not tc.is_subtype(mainmodule, null, mtype) then continue
+                       var d = mproperty.lookup_first_definition(mainmodule, tc)
+                       res.add d
+               end
+
+               return res
+       end
+
        # Live call-to-super.
        var live_super_sends = new HashSet[MMethodDef]
 
@@ -442,7 +474,10 @@ class RapidTypeVisitor
 
        fun add_cast_type(mtype: MType) do analysis.add_cast(mtype)
 
-       fun add_callsite(callsite: nullable CallSite) do if callsite != null then analysis.add_send(callsite.recv, callsite.mproperty)
+       fun add_callsite(callsite: nullable CallSite) do if callsite != null then
+               analysis.add_send(callsite.recv, callsite.mproperty)
+               analysis.live_callsites.add(callsite)
+       end
 end
 
 ###
index f5dd05d..2352646 100644 (file)
@@ -1022,8 +1022,8 @@ class SeparateCompilerVisitor
                        res = self.new_var(ret)
                end
 
-               var s = new Buffer
-               var ss = new Buffer
+               var s = new FlatBuffer
+               var ss = new FlatBuffer
 
                var recv = arguments.first
                s.append("val*")
@@ -1695,8 +1695,8 @@ class SeparateRuntimeFunction
 
                var msignature = mmethoddef.msignature.resolve_for(mmethoddef.mclassdef.bound_mtype, mmethoddef.mclassdef.bound_mtype, mmethoddef.mclassdef.mmodule, true)
 
-               var sig = new Buffer
-               var comment = new Buffer
+               var sig = new FlatBuffer
+               var comment = new FlatBuffer
                var ret = msignature.return_mtype
                if ret != null then
                        sig.append("{ret.ctype} ")
@@ -1768,8 +1768,8 @@ class VirtualRuntimeFunction
                var frame = new Frame(v, mmethoddef, recv, arguments)
                v.frame = frame
 
-               var sig = new Buffer
-               var comment = new Buffer
+               var sig = new FlatBuffer
+               var comment = new FlatBuffer
 
                # Because the function is virtual, the signature must match the one of the original class
                var intromclassdef = self.mmethoddef.mproperty.intro.mclassdef
index c001f3a..fbd3f36 100644 (file)
@@ -242,8 +242,8 @@ private class TypeVisitor
                end
 
                assert mproperty isa MMethod
-               if mproperty.visibility == protected_visibility and not recv_is_self and self.mmodule.visibility_for(mproperty.intro_mclassdef.mmodule) < intrude_visibility then
-                       self.modelbuilder.error(node, "Error: Method '{name}' is protected and can only acceded by self. {mproperty.intro_mclassdef.mmodule.visibility_for(self.mmodule)}")
+               if mproperty.visibility == protected_visibility and not recv_is_self and self.mmodule.visibility_for(mproperty.intro_mclassdef.mmodule) < intrude_visibility and not modelbuilder.toolcontext.opt_ignore_visibility.value then
+                       self.modelbuilder.error(node, "Error: Method '{name}' is protected and can only acceded by self.")
                        return null
                end
 
@@ -274,7 +274,7 @@ private class TypeVisitor
                        end
                end
 
-               var callsite = new CallSite(node, recvtype, recv_is_self, mproperty, mpropdef, msignature, erasure_cast)
+               var callsite = new CallSite(node, recvtype, mmodule, anchor, recv_is_self, mproperty, mpropdef, msignature, erasure_cast)
                return callsite
        end
 
@@ -386,9 +386,15 @@ class CallSite
        # The assiciated node for location
        var node: ANode
 
-       # The statis type of the receiver
+       # The static type of the receiver (possibly unresolved)
        var recv: MType
 
+       # The module where the callsite is present
+       var mmodule: MModule
+
+       # The anchor to use with `recv` or `msignature`
+       var anchor: nullable MClassType
+
        # Is the receiver self?
        # If "for_self", virtual types of the signature are keeped
        # If "not_for_self", virtual type are erased
@@ -1498,7 +1504,7 @@ redef class ASuperExpr
                end
 
                var msignature = v.resolve_signature_for(superprop, recvtype, true)
-               var callsite = new CallSite(self, recvtype, true, superprop.mproperty, superprop, msignature, false)
+               var callsite = new CallSite(self, recvtype, v.mmodule, v.anchor, true, superprop.mproperty, superprop, msignature, false)
                self.callsite = callsite
 
                var args = self.n_args.to_a
index c7e2930..95d1065 100644 (file)
@@ -1,7 +1,5 @@
 # This file is part of NIT ( http://www.nitlanguage.org ).
 #
-# Copyright 2008 Jean Privat <jean@pryen.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
@@ -16,7 +14,9 @@
 
 import kernel
 
-class A
+import base_prot0
+
+redef class A
        fun pub do 0.output
        protected fun pro do 1.output
        private fun pri do 2.output
@@ -30,6 +30,7 @@ class O1
                a.pub
                a.pro
                a.pri
+               3.output
        end
        init do end
 end
diff --git a/tests/base_prot0.nit b/tests/base_prot0.nit
new file mode 100644 (file)
index 0000000..9be3552
--- /dev/null
@@ -0,0 +1,18 @@
+# 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 kernel
+
+class A
+end
index 4611f85..b6dbfcb 100644 (file)
@@ -1,7 +1,5 @@
 # This file is part of NIT ( http://www.nitlanguage.org ).
 #
-# Copyright 2008 Jean Privat <jean@pryen.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
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+import base_prot0
 private import base_prot
 
-class A2
+class B
        super A
-       fun o
-       do
+       redef fun pub do 10.output
+       redef fun pro do 11.output
+       #alt1#redef fun pri do 12.output
+       fun o do
                pub
                pro
-               #alt1#pri
+               #alt2#pri
        end
-       init do end
 end
 
 class O2
        fun o
        do
-               var a = new A
+               var a = new B
                a.pub
-               #alt2#a.pro
-               #alt3#a.pri
-
-               var a2 = new A2
-               a2.o
-               a2.pub
-               #alt4#a2.pro
-               #alt5#a2.pri
+               #alt3#a.pro
+               #alt4#a.pri
+               13.output
        end
        init do end
 end
index df87cd0..191cfa2 100644 (file)
@@ -1,7 +1,5 @@
 # This file is part of NIT ( http://www.nitlanguage.org ).
 #
-# Copyright 2008 Jean Privat <jean@pryen.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
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+import base_prot0
 private import base_prot2
-intrude import base_prot
+
+class C
+       super A
+       #alt5#redef fun pub do 20.output
+       #alt6#redef fun pro do 21.output
+       #alt1#redef fun pri do 22.output
+       fun o do
+               #alt7#pub
+               #alt8#pro
+               #alt2#pri
+       end
+end
 
 class O3
        fun o
        do
-               var a = new A
-               a.pub
-               a.pro
-               a.pri
+               var a = new C
+               #alt9#a.pub
+               #alt3#a.pro
+               #alt4#a.pri
+               23.output
        end
        init do end
 end
 
 (new O3).o
-
index 97c6c63..6c7125d 100644 (file)
@@ -27,4 +27,4 @@ assert 'd'.object_id.to_s.is_numeric
 assert 1.0.object_id.to_s.is_numeric
 
 # Check NativeString.object_id
-assert "Test"._items.object_id.to_s.is_numeric
+assert "Test".as(FlatString).items.object_id.to_s.is_numeric
index 6a2d643..3dff2fc 100644 (file)
@@ -22,7 +22,7 @@ end
 var s = "*"
 var i = 0
 while i < n do
-       var s2 = new Buffer.from("Je dis Â«")
+       var s2 = new FlatBuffer.from("Je dis Â«")
        s2.append(s)
        s2.append("» et redis Â«")
        s2.append(s)
@@ -33,16 +33,15 @@ while i < n do
        s = s2.to_s
        i = i + 1
 end
-print("Je dis Â«Je dis".search_all_in(s).length)
+print(s.search_all("Je dis Â«Je dis").length)
 
 i = 0
 var j = 0
 while j >= 0 do
-       j = "Je dis Â«Je dis".search_index_in(s, j)
-       if j >= 0 then
-               i = i + 1
-               j = j + 1
-       end
+       var r = s.search_from("Je dis Â«Je dis", j)
+       if r == null then break
+       i = i + 1
+       j = r.from + 1
 end
 print(i)
 
index 1bcc313..a0f69d6 100644 (file)
@@ -101,7 +101,7 @@ private
        do
                # Les variables sont déclarées par "var", leur portée va de leur
                # déclaration jusqu'au "end" correspondant
-               var s = new Buffer              # Là où on calcule le résultat
+               var s = new FlatBuffer          # Là où on calcule le résultat
                # Les chaînes littérales sont déclarées avec des guillemets
                s.append("*** Entrepôt ")       # On initialise "s"
                # puis on concatène des chaînes Ã  "s"
@@ -218,7 +218,7 @@ private
                # Si une expression est passée comme valeur initiale d'une
                # variable, le type statique de la variable est implicitement
                # celui de l'expression.
-               var s = new Buffer
+               var s = new FlatBuffer
                s.append("* Rayon : ")
                # Ici, le type statique de s est implicitement String
 
@@ -245,7 +245,7 @@ private
 
        redef fun to_s: String
        do
-               var s = new Buffer
+               var s = new FlatBuffer
                s.append(to_s_head)
                # Les boucles en NIT sont des structures puissantes, toutefois
                # la manipulation des itérateurs peut Ãªtre facilité par la
index a78d01f..c00d979 100644 (file)
@@ -18,7 +18,7 @@
 
 fun first_word(s: String): String
 do
-       var result = new Buffer
+       var result = new FlatBuffer
        var i = 0
        while i < s.length and s.chars[i] != ' ' do
                result.add(s.chars[i])
index 006efff..f066eac 100644 (file)
@@ -27,7 +27,7 @@ printn("The value of a is: ", a, ".\n")
 # Second way: Build a string and display it.
 # Pro: Eiffel way (rigourous).
 # Con: Eiffel way (heavy).
-var s = new Buffer.from("The value of a is: ")
+var s = new FlatBuffer.from("The value of a is: ")
 s.append(a.to_s)
 s.append(".\n")
 printn(s)
index 37c350e..d7b62f6 100644 (file)
@@ -1,10 +1,17 @@
 alt/base_attr3_alt2.nit:49,3--10: Error: Method 'a1=' doesn't exists in A.
+alt/base_attr3_alt2.nit:50,3--6: Error: Method 'a2' is protected and can only acceded by self.
 alt/base_attr3_alt2.nit:51,3--10: Error: Method 'a2=' doesn't exists in A.
 alt/base_attr3_alt2.nit:52,3--6: Error: Method 'a3' doesn't exists in A.
 alt/base_attr3_alt2.nit:53,3--10: Error: Method 'a3=' doesn't exists in A.
+alt/base_attr3_alt2.nit:56,3--6: Error: Method 'a5' is protected and can only acceded by self.
 alt/base_attr3_alt2.nit:58,3--6: Error: Method 'a6' doesn't exists in A.
+alt/base_attr3_alt2.nit:61,3--10: Error: Method 'a7=' is protected and can only acceded by self.
+alt/base_attr3_alt2.nit:62,3--6: Error: Method 'a8' is protected and can only acceded by self.
+alt/base_attr3_alt2.nit:63,3--10: Error: Method 'a8=' is protected and can only acceded by self.
 alt/base_attr3_alt2.nit:64,3--6: Error: Method 'a9' doesn't exists in A.
+alt/base_attr3_alt2.nit:65,3--10: Error: Method 'a9=' is protected and can only acceded by self.
 alt/base_attr3_alt2.nit:67,3--11: Error: Method 'a10=' doesn't exists in A.
+alt/base_attr3_alt2.nit:68,3--7: Error: Method 'a11' is protected and can only acceded by self.
 alt/base_attr3_alt2.nit:69,3--11: Error: Method 'a11=' doesn't exists in A.
 alt/base_attr3_alt2.nit:70,3--7: Error: Method 'a12' doesn't exists in A.
 alt/base_attr3_alt2.nit:71,3--11: Error: Method 'a12=' doesn't exists in A.
index bda1613..c762e5c 100644 (file)
@@ -1,10 +1,17 @@
 alt/base_attr3_alt3.nit:80,2--9: Error: Method 'a1=' doesn't exists in A.
+alt/base_attr3_alt3.nit:81,2--5: Error: Method 'a2' is protected and can only acceded by self.
 alt/base_attr3_alt3.nit:82,2--9: Error: Method 'a2=' doesn't exists in A.
 alt/base_attr3_alt3.nit:83,2--5: Error: Method 'a3' doesn't exists in A.
 alt/base_attr3_alt3.nit:84,2--9: Error: Method 'a3=' doesn't exists in A.
+alt/base_attr3_alt3.nit:87,2--5: Error: Method 'a5' is protected and can only acceded by self.
 alt/base_attr3_alt3.nit:89,2--5: Error: Method 'a6' doesn't exists in A.
+alt/base_attr3_alt3.nit:92,2--9: Error: Method 'a7=' is protected and can only acceded by self.
+alt/base_attr3_alt3.nit:93,2--5: Error: Method 'a8' is protected and can only acceded by self.
+alt/base_attr3_alt3.nit:94,2--9: Error: Method 'a8=' is protected and can only acceded by self.
 alt/base_attr3_alt3.nit:95,2--5: Error: Method 'a9' doesn't exists in A.
+alt/base_attr3_alt3.nit:96,2--9: Error: Method 'a9=' is protected and can only acceded by self.
 alt/base_attr3_alt3.nit:98,2--10: Error: Method 'a10=' doesn't exists in A.
+alt/base_attr3_alt3.nit:99,2--6: Error: Method 'a11' is protected and can only acceded by self.
 alt/base_attr3_alt3.nit:100,2--10: Error: Method 'a11=' doesn't exists in A.
 alt/base_attr3_alt3.nit:101,2--6: Error: Method 'a12' doesn't exists in A.
 alt/base_attr3_alt3.nit:102,2--10: Error: Method 'a12=' doesn't exists in A.
index c48963f..4ccdc82 100644 (file)
@@ -1,10 +1,17 @@
 alt/base_attr3_alt4.nit:110,2--9: Error: Method 'a1=' doesn't exists in B.
+alt/base_attr3_alt4.nit:111,2--5: Error: Method 'a2' is protected and can only acceded by self.
 alt/base_attr3_alt4.nit:112,2--9: Error: Method 'a2=' doesn't exists in B.
 alt/base_attr3_alt4.nit:113,2--5: Error: Method 'a3' doesn't exists in B.
 alt/base_attr3_alt4.nit:114,2--9: Error: Method 'a3=' doesn't exists in B.
+alt/base_attr3_alt4.nit:117,2--5: Error: Method 'a5' is protected and can only acceded by self.
 alt/base_attr3_alt4.nit:119,2--5: Error: Method 'a6' doesn't exists in B.
+alt/base_attr3_alt4.nit:122,2--9: Error: Method 'a7=' is protected and can only acceded by self.
+alt/base_attr3_alt4.nit:123,2--5: Error: Method 'a8' is protected and can only acceded by self.
+alt/base_attr3_alt4.nit:124,2--9: Error: Method 'a8=' is protected and can only acceded by self.
 alt/base_attr3_alt4.nit:125,2--5: Error: Method 'a9' doesn't exists in B.
+alt/base_attr3_alt4.nit:126,2--9: Error: Method 'a9=' is protected and can only acceded by self.
 alt/base_attr3_alt4.nit:128,2--10: Error: Method 'a10=' doesn't exists in B.
+alt/base_attr3_alt4.nit:129,2--6: Error: Method 'a11' is protected and can only acceded by self.
 alt/base_attr3_alt4.nit:130,2--10: Error: Method 'a11=' doesn't exists in B.
 alt/base_attr3_alt4.nit:131,2--6: Error: Method 'a12' doesn't exists in B.
 alt/base_attr3_alt4.nit:132,2--10: Error: Method 'a12=' doesn't exists in B.
index 34cdf5b..35e4ebe 100644 (file)
@@ -1,4 +1,4 @@
-String
+FlatString
 Int
 Test
 Test
diff --git a/tests/sav/base_prot0.res b/tests/sav/base_prot0.res
new file mode 100644 (file)
index 0000000..e69de29
index 0e4b84c..c18edb9 100644 (file)
@@ -1 +1 @@
-alt/base_prot2_alt1.nit:25,3--5: Error: Method or variable 'pri' unknown in A2.
+alt/base_prot2_alt1.nit:22,12--14: Error: No property B::pri is inherited. Remove the redef keyword to define a new property.
index be87afb..f861feb 100644 (file)
@@ -1 +1 @@
-alt/base_prot2_alt2.nit:35,3--7: Error: Method 'pro' is protected and can only acceded by self. none
+alt/base_prot2_alt2.nit:26,3--5: Error: Method or variable 'pri' unknown in B.
index d6e7a77..f597f61 100644 (file)
@@ -1 +1 @@
-alt/base_prot2_alt3.nit:36,3--7: Error: Method 'pri' doesn't exists in A.
+alt/base_prot2_alt3.nit:35,3--7: Error: Method 'pro' is protected and can only acceded by self.
index 0142026..221e070 100644 (file)
@@ -1 +1 @@
-alt/base_prot2_alt4.nit:41,3--8: Error: Method 'pro' is protected and can only acceded by self. none
+alt/base_prot2_alt4.nit:36,3--7: Error: Method 'pri' doesn't exists in B.
diff --git a/tests/sav/base_prot3_alt1.res b/tests/sav/base_prot3_alt1.res
new file mode 100644 (file)
index 0000000..5ecf371
--- /dev/null
@@ -0,0 +1 @@
+alt/base_prot3_alt1.nit:22,12--14: Error: No property C::pri is inherited. Remove the redef keyword to define a new property.
diff --git a/tests/sav/base_prot3_alt2.res b/tests/sav/base_prot3_alt2.res
new file mode 100644 (file)
index 0000000..956aacd
--- /dev/null
@@ -0,0 +1 @@
+alt/base_prot3_alt2.nit:26,3--5: Error: Method or variable 'pri' unknown in C.
diff --git a/tests/sav/base_prot3_alt3.res b/tests/sav/base_prot3_alt3.res
new file mode 100644 (file)
index 0000000..a384502
--- /dev/null
@@ -0,0 +1 @@
+alt/base_prot3_alt3.nit:35,3--7: Error: Method 'pro' doesn't exists in C.
diff --git a/tests/sav/base_prot3_alt4.res b/tests/sav/base_prot3_alt4.res
new file mode 100644 (file)
index 0000000..d7f2b51
--- /dev/null
@@ -0,0 +1 @@
+alt/base_prot3_alt4.nit:36,3--7: Error: Method 'pri' doesn't exists in C.
diff --git a/tests/sav/base_prot3_alt5.res b/tests/sav/base_prot3_alt5.res
new file mode 100644 (file)
index 0000000..d375312
--- /dev/null
@@ -0,0 +1 @@
+alt/base_prot3_alt5.nit:20,12--14: Error: No property C::pub is inherited. Remove the redef keyword to define a new property.
diff --git a/tests/sav/base_prot3_alt6.res b/tests/sav/base_prot3_alt6.res
new file mode 100644 (file)
index 0000000..da112d3
--- /dev/null
@@ -0,0 +1 @@
+alt/base_prot3_alt6.nit:21,12--14: Error: No property C::pro is inherited. Remove the redef keyword to define a new property.
diff --git a/tests/sav/base_prot3_alt7.res b/tests/sav/base_prot3_alt7.res
new file mode 100644 (file)
index 0000000..06cbec1
--- /dev/null
@@ -0,0 +1 @@
+alt/base_prot3_alt7.nit:24,3--5: Error: Method or variable 'pub' unknown in C.
diff --git a/tests/sav/base_prot3_alt8.res b/tests/sav/base_prot3_alt8.res
new file mode 100644 (file)
index 0000000..168d1c8
--- /dev/null
@@ -0,0 +1 @@
+alt/base_prot3_alt8.nit:25,3--5: Error: Method or variable 'pro' unknown in C.
diff --git a/tests/sav/base_prot3_alt9.res b/tests/sav/base_prot3_alt9.res
new file mode 100644 (file)
index 0000000..a708c8f
--- /dev/null
@@ -0,0 +1 @@
+alt/base_prot3_alt9.nit:34,3--7: Error: Method 'pub' doesn't exists in C.
index ec635ed..4bb419d 100644 (file)
          std: 0.926
        cnbip: number of introduced properties
          avg: 2.0
-         max: C (7)
+         max: C (5)
          min: Bool (0)
-         std: 2.42
+         std: 1.69
        cnbrp: number of redefined properties
          avg: 0.0
          max: Object (0)
          std: 0.866
        cnbip: number of introduced properties
          avg: 2.0
-         max: C (7)
+         max: C (5)
          min: Bool (0)
-         std: 2.291
+         std: 1.62
        cnbrp: number of redefined properties
          avg: 0.0
          max: Object (0)
          std: 0.866
        cnbip: number of introduced properties
          avg: 2.0
-         max: C (7)
+         max: C (5)
          min: Bool (0)
-         std: 2.291
+         std: 1.62
        cnbrp: number of redefined properties
          avg: 0.0
          max: Object (0)
@@ -849,6 +849,51 @@ generating out/nitmetrics_args1.write/module_hierarchy.dot
          max: Sys (0)
          min: Sys (0)
          std: 0.0
+
+ ## Callsites
+* 22 live callsites
+MMethodDef locally designated (by number of CallSites)
+ population: 13
+ minimum value: 1
+ maximum value: 10
+ total value: 22
+ average value: 1.69
+ distribution:
+  <=1: sub-population=12 (92.30%); cumulated value=12 (54.54%)
+  <=16: sub-population=1 (7.69%); cumulated value=10 (45.45%)
+ list:
+  base_simple3#Int#output: 10 (45.45%)
+  base_simple3#B#val: 1 (4.54%)
+  base_simple3#B#val=: 1 (4.54%)
+  base_simple3#C#val2: 1 (4.54%)
+  base_simple3#C#val1: 1 (4.54%)
+  ...
+  base_simple3#A#init: 1 (4.54%)
+  base_simple3#Object#baz: 1 (4.54%)
+  base_simple3#Object#bar: 1 (4.54%)
+  base_simple3#Object#foo: 1 (4.54%)
+  base_simple3#C#init: 1 (4.54%)
+MMethodDef possibly invoked at runtime (by number of CallSites)
+ population: 13
+ minimum value: 1
+ maximum value: 10
+ total value: 22
+ average value: 1.69
+ distribution:
+  <=1: sub-population=12 (92.30%); cumulated value=12 (54.54%)
+  <=16: sub-population=1 (7.69%); cumulated value=10 (45.45%)
+ list:
+  base_simple3#Int#output: 10 (45.45%)
+  base_simple3#B#val: 1 (4.54%)
+  base_simple3#B#val=: 1 (4.54%)
+  base_simple3#C#val2: 1 (4.54%)
+  base_simple3#C#val1: 1 (4.54%)
+  ...
+  base_simple3#A#init: 1 (4.54%)
+  base_simple3#Object#baz: 1 (4.54%)
+  base_simple3#Object#bar: 1 (4.54%)
+  base_simple3#Object#foo: 1 (4.54%)
+  base_simple3#C#init: 1 (4.54%)
 class_hierarchy.dot
 classdef_hierarchy.dot
 inheritance/
index e9e11a6..4f5bee8 100644 (file)
@@ -1,11 +1,12 @@
 1111223
 123
 12132
-1007
-1020101010302
+123451211132
+102030405
 232
 12
-9991000
-9991000
-12
+345
+345
+45
+123
 3
index c8277d4..76c6e5c 100644 (file)
@@ -3,25 +3,25 @@ searches:
 * [1, 2[ = " "
 * [8, 9[ = " "
 splits:
-* [0, 1[ = "A"
-* [2, 8[ = "simple"
-* [9, 16[ = "example"
+* "A"
+* "simple"
+* "example"
 join: A, simple, example
 string: "A simple example" ; pattern: "ple"
 searches:
 * [5, 8[ = "ple"
 * [13, 16[ = "ple"
 splits:
-* [0, 5[ = "A sim"
-* [8, 13[ = " exam"
-* [16, 16[ = ""
+* "A sim"
+* " exam"
+* ""
 join: A sim,  exam, 
 string: "A simple example" ; pattern: "ple"
 searches:
 * [5, 8[ = "ple"
 * [13, 16[ = "ple"
 splits:
-* [0, 5[ = "A sim"
-* [8, 13[ = " exam"
-* [16, 16[ = ""
+* "A sim"
+* " exam"
+* ""
 join: A sim,  exam, 
index b0ecf41..acc2856 100644 (file)
@@ -17,7 +17,7 @@
 fun nsieve(n: Int): Int
 do
        var count = 0
-       var array = new Buffer.with_capacity(n)
+       var array = new FlatBuffer.with_capacity(n)
        for i in [0..n[ do
                array.chars[i] = 'o'
        end
index 2f8e168..040226a 100644 (file)
@@ -16,6 +16,9 @@
 
 module string_ffi_ref_test
 
+intrude import string
+import file
+
 class StringTest
 
        var copied_str: nullable String
@@ -28,16 +31,16 @@ class StringTest
                referenced_str = null
        end
 
-       fun get_c_string import String.items, NativeString.to_s, NativeString.to_s_with_copy, StringTest.ref_test, StringTest.copy_test `{
+       fun get_c_string import FlatString.items, NativeString.to_s, NativeString.to_s_with_copy, StringTest.ref_test, StringTest.copy_test `{
                char* string = "This is a test string";
 
-               String ref_string = NativeString_to_s(string);
+               FlatString ref_string = NativeString_to_s(string);
                StringTest_ref_test(recv, ref_string);
 
-               String copy_string = NativeString_to_s_with_copy(string);
+               FlatString copy_string = NativeString_to_s_with_copy(string);
                StringTest_copy_test(recv, copy_string);
 
-               int same_refs = String_items(copy_string) == String_items(ref_string);
+               int same_refs = FlatString_items(copy_string) == FlatString_items(ref_string);
 
                printf("Do the strings have the same NativeString reference ? ");
 
index 09bd541..387c8b1 100644 (file)
@@ -4,7 +4,7 @@ var trimtest = "   \t nono nono   \n \t"
 
 var subtrim = trimtest.substring(2,15)
 
-var buffertrimtest = new Buffer.from(trimtest)
+var buffertrimtest = new FlatBuffer.from(trimtest)
 
 print "resulttrim = {buffertrimtest.trim}"
 
@@ -14,7 +14,7 @@ print "thirdtrim = {subtrim.trim}"
 
 var emptytrim = "         \t  "
 
-var bufferemptytest = new Buffer.from(emptytrim)
+var bufferemptytest = new FlatBuffer.from(emptytrim)
 
 print "emptytrim = {emptytrim.trim}"
 
@@ -22,7 +22,7 @@ print "bufferemptytrim = {bufferemptytest.trim}"
 
 var onelettertrim = "    \n   d      \n\t  "
 
-var oneletterbuftest = new Buffer.from(onelettertrim)
+var oneletterbuftest = new FlatBuffer.from(onelettertrim)
 
 print "onelettertrim = {onelettertrim.trim}"
 
@@ -30,7 +30,7 @@ print "oneletterbuftest = {oneletterbuftest.trim}"
 
 var twolettertrim = "    \n   hg      \n\t  "
 
-var twoletterbuftest = new Buffer.from(twolettertrim)
+var twoletterbuftest = new FlatBuffer.from(twolettertrim)
 
 print "twolettertrim = {twolettertrim.trim}"
 
@@ -38,7 +38,7 @@ print "twoletterbuftest = {twoletterbuftest.trim}"
 
 var firstlettertrim = "d                "
 
-var firstlettertrimbuf = new Buffer.from(firstlettertrim)
+var firstlettertrimbuf = new FlatBuffer.from(firstlettertrim)
 
 print "firstlettertrimtest = {firstlettertrim.trim}"
 
@@ -46,7 +46,7 @@ print "firstlettertrimbuftest = {firstlettertrimbuf.trim}"
 
 var lastlettertrim = "                     d"
 
-var lastlettertrimbuf = new Buffer.from(lastlettertrim)
+var lastlettertrimbuf = new FlatBuffer.from(lastlettertrim)
 
 print "lastlettertrimtest = {lastlettertrim.trim}"
 
index f008c34..feb1e65 100644 (file)
@@ -28,7 +28,7 @@ print("string:")
 var a2: Object = "Bonjour"
 print(not a2 isa Int)
 print(a2 isa String)
-print(a2 isa AbstractArrayRead[Char])
+print(a2 isa Text)
 print(not a2 isa Iterator[Int])
 print(not a2 isa Discrete)
 print(a2 isa Object)
index 37d66b6..f29f2dd 100644 (file)
 
 import pipeline
 
-var a1 = [1..1000]
+var a1 = [1,2,3,4,5]
 var a2 = [1,2,1,1,1,3,2]
 
-print a2.sort_filter.to_a
-print a2.uniq.to_a
-print a2.seq_uniq.to_a
+print a2.iterator.sort.to_a
+print a2.iterator.uniq.to_a
+print a2.iterator.seq_uniq.to_a
 
 ##
 
-print((a1 + a2).length)
+print((a1.iterator + a2.iterator).to_a)
 
-print a2.alternate(0).to_a
+print a1.iterator.alternate(0).to_a
 
-print a2.skip(1).to_a
+print a2.iterator.skip(1).to_a
 
 ##
 
-print a1.head(2).to_a
-print a1.skip_head(998).to_a
-print a1.tail(2).to_a
-print a1.skip_tail(998).to_a
+var i = a1.iterator
+print i.head(2).to_a
+print i.to_a
 
-print a1.skip_head(1).head(3).skip_tail(1).tail(1).to_a
+print a1.iterator.skip_head(2).to_a
+print a1.iterator.tail(2).to_a
+print a1.iterator.skip_tail(2).to_a
+
+print a1.iterator.skip_head(1).head(3).skip_tail(1).tail(1).to_a
index aa02268..fcf7ea2 100644 (file)
@@ -52,7 +52,7 @@ print "585,210.52".is_numeric
 #False
 print "21,52,210.52".is_numeric
 
-var buf = new Buffer
+var buf = new FlatBuffer
 
 buf.append("45.3")
 
index 1b59ba8..04655ba 100644 (file)
@@ -16,8 +16,8 @@
 
 
 var s = "Bonjour !\n"
-var r = new Buffer.with_capacity(50)
-var r2 = new Buffer
+var r = new FlatBuffer.with_capacity(50)
+var r2 = new FlatBuffer
 
 var i = 0
 while i < 5000 do
index 26aaf9d..0702869 100644 (file)
@@ -23,11 +23,11 @@ fun search_and_split(s: String, p: Pattern)
            print("* [{m.from}, {m.after}[ = \"{m}\"")
        end
        print("splits:")
-       for m in p.split_in(s) do
-           print("* [{m.from}, {m.after}[ = \"{m}\"")
+       for m in s.split(p) do
+           print("* \"{m}\"")
        end
 
-       print("join: {s.split_with(p).join(", ")}")
+       print("join: {s.split(p).join(", ")}")
     end
     
 search_and_split("A simple example", ' ')