lib/core: Removed some abusive `chars` use in lib
[nit.git] / lib / core / text / abstract_text.nit
index c699d50..cb6f281 100644 (file)
@@ -50,9 +50,9 @@ abstract class Text
 
        # Number of bytes in `self`
        #
-       #     assert "12345".bytelen == 5
-       #     assert "あいうえお".bytelen == 15
-       fun bytelen: Int is abstract
+       #     assert "12345".byte_length == 5
+       #     assert "あいうえお".byte_length == 15
+       fun byte_length: Int is abstract
 
        # Create a substring.
        #
@@ -551,7 +551,7 @@ abstract class Text
                var res = new Buffer
                var underscore = false
                var start = 0
-               var c = chars[0]
+               var c = self[0]
 
                if c >= '0' and c <= '9' then
                        res.add('_')
@@ -560,7 +560,7 @@ abstract class Text
                        start = 1
                end
                for i in [start..length[ do
-                       c = chars[i]
+                       c = self[i]
                        if (c >= 'a' and c <= 'z') or (c >='A' and c <= 'Z') then
                                res.add(c)
                                underscore = false
@@ -590,10 +590,13 @@ abstract class Text
                return res.to_s
        end
 
-       # Escape " \ ' and non printable characters using the rules of literal C strings and characters
+       # Escape `"` `\` `'`, trigraphs and non printable characters using the rules of literal C strings and characters
        #
-       #     assert "abAB12<>&".escape_to_c         == "abAB12<>&"
+       #     assert "abAB12<>&".escape_to_c       == "abAB12<>&"
        #     assert "\n\"'\\".escape_to_c         == "\\n\\\"\\'\\\\"
+       #     assert "allo???!".escape_to_c        == "allo??\\?!"
+       #     assert "??=??/??'??(??)".escape_to_c == "?\\?=?\\?/??\\'?\\?(?\\?)"
+       #     assert "??!??<??>??-".escape_to_c    == "?\\?!?\\?<?\\?>?\\?-"
        #
        # Most non-printable characters (bellow ASCII 32) are escaped to an octal form `\nnn`.
        # Three digits are always used to avoid following digits to be interpreted as an element
@@ -617,6 +620,24 @@ abstract class Text
                                b.append("\\\'")
                        else if c == '\\' then
                                b.append("\\\\")
+                       else if c == '?' then
+                               # Escape if it is the last question mark of a ANSI C trigraph.
+                               var j = i + 1
+                               if j < length then
+                                       var next = chars[j]
+                                       # We ignore `??'` because it will be escaped as `??\'`.
+                                       if
+                                               next == '!' or
+                                               next == '(' or
+                                               next == ')' or
+                                               next == '-' or
+                                               next == '/' or
+                                               next == '<' or
+                                               next == '=' or
+                                               next == '>'
+                                       then b.add('\\')
+                               end
+                               b.add('?')
                        else if c.code_point < 32 then
                                b.add('\\')
                                var oct = c.code_point.to_base(8)
@@ -640,6 +661,7 @@ abstract class Text
        # The result might no be legal in C but be used in other languages
        #
        #     assert "ab|\{\}".escape_more_to_c("|\{\}") == "ab\\|\\\{\\\}"
+       #     assert "allo???!".escape_more_to_c("")     == "allo??\\?!"
        fun escape_more_to_c(chars: String): String
        do
                var b = new Buffer
@@ -822,7 +844,7 @@ abstract class Text
        #     assert "%c3%a9%e3%81%82%e3%81%84%e3%81%86".from_percent_encoding == "éあいう"
        fun from_percent_encoding: String
        do
-               var len = bytelen
+               var len = byte_length
                var has_percent = false
                for c in chars do
                        if c == '%' then
@@ -1159,7 +1181,7 @@ abstract class FlatText
 
        redef var length = 0
 
-       redef var bytelen = 0
+       redef var byte_length = 0
 
        redef fun output
        do
@@ -1204,11 +1226,11 @@ private abstract class StringByteView
 
        redef fun is_empty do return target.is_empty
 
-       redef fun length do return target.bytelen
+       redef fun length do return target.byte_length
 
        redef fun iterator do return self.iterator_from(0)
 
-       redef fun reverse_iterator do return self.reverse_iterator_from(target.bytelen - 1)
+       redef fun reverse_iterator do return self.reverse_iterator_from(target.byte_length - 1)
 end
 
 # Immutable sequence of characters.
@@ -1389,9 +1411,6 @@ abstract class Buffer
 
        redef type SELFTYPE: Buffer is fixed
 
-       # Specific implementations MUST set this to `true` in order to invalidate caches
-       protected var is_dirty = true
-
        # Copy-On-Write flag
        #
        # If the `Buffer` was to_s'd, the next in-place altering
@@ -1517,12 +1536,6 @@ abstract class Buffer
                end
        end
 
-       redef fun hash
-       do
-               if is_dirty then hash_cache = null
-               return super
-       end
-
        # In Buffers, the internal sequence of character is mutable
        # Thus, `chars` can be used to modify the buffer.
        redef fun chars: Sequence[Char] is abstract
@@ -2114,7 +2127,12 @@ end
 # see `alpha_comparator`
 private class AlphaComparator
        super Comparator
-       redef fun compare(a, b) do return a.to_s <=> b.to_s
+       redef fun compare(a, b) do
+               if a == b then return 0
+               if a == null then return -1
+               if b == null then return 1
+               return a.to_s <=> b.to_s
+       end
 end
 
 # Stateless comparator that naively use `to_s` to compare things.
@@ -2160,7 +2178,7 @@ redef class NativeString
        # use only when the data has already been verified as valid UTF-8.
        fun to_s_unsafe(length: nullable Int): String is abstract
 
-       # Get a `String` from the raw `bytelen` bytes at `self` with `unilen` Unicode characters
+       # Get a `String` from the raw `byte_length` bytes at `self` with `unilen` Unicode characters
        #
        # The created `String` points to the data at `self`.
        # This method should be used when `self` was allocated by the Nit GC,
@@ -2170,8 +2188,13 @@ redef class NativeString
        # use only when the data has already been verified as valid UTF-8.
        #
        # SEE: `abstract_text::Text` for more info on the difference
-       # between `Text::bytelen` and `Text::length`.
-       fun to_s_full(bytelen, unilen: Int): String is abstract
+       # between `Text::byte_length` and `Text::length`.
+       fun to_s_full(byte_length, unilen: Int): String is abstract
+
+       # Copies the content of `src` to `self`
+       #
+       # NOTE: `self` must be large enough to withold `self.byte_length` bytes
+       fun fill_from(src: Text) do src.copy_to_native(self, src.byte_length, 0, 0)
 end
 
 redef class NativeArray[E]