Merge: Extends chars, string and stream with some whitespace-related function
authorJean Privat <jean@pryen.org>
Sat, 7 Mar 2015 05:17:01 +0000 (12:17 +0700)
committerJean Privat <jean@pryen.org>
Sat, 7 Mar 2015 05:17:01 +0000 (12:17 +0700)
While thinking about the remaining task of #466 (simple parsing), I though that there useful functions where missing in order to have a sane `Reader::read_word` method

Pull-Request: #1179
Reviewed-by: Lucas Bajolet <r4pass@hotmail.com>
Reviewed-by: Alexis Laferrière <alexis.laf@xymus.net>
Reviewed-by: Alexandre Terrasa <alexandre@moz-code.org>

lib/standard/kernel.nit
lib/standard/stream.nit
lib/standard/string.nit
tests/sav/nituml_args3.res
tests/sav/nituml_args4.res

index 21b0fc1..01e72e3 100644 (file)
@@ -718,6 +718,22 @@ universal Char
        do
                return is_lower or is_upper
        end
+
+       # Is self a whitespace character?
+       #
+       # These correspond to the "Other" and "Separator" groups of the Unicode.
+       #
+       # In the ASCII encoding, this is those <= to space (0x20) plus delete (0x7F).
+       #
+       #     assert 'A'.is_whitespace  == false
+       #     assert ','.is_whitespace  == false
+       #     assert ' '.is_whitespace  == true
+       #     assert '\t'.is_whitespace == true
+       fun is_whitespace: Bool
+       do
+               var i = ascii
+               return i <= 0x20 or i == 0x7F
+       end
 end
 
 # Pointer classes are used to manipulate extern C structures.
index 476c684..1e4ba18 100644 (file)
@@ -220,6 +220,66 @@ abstract class Reader
        # Is there something to read.
        # This function returns 'false' if there is something to read.
        fun eof: Bool is abstract
+
+       # Read the next sequence of non whitespace characters.
+       #
+       # Leading whitespace characters are skipped.
+       # The first whitespace character that follows the result is consumed.
+       #
+       # An empty string is returned if the end of the file or an error is encounter.
+       #
+       # ~~~
+       # var w = new StringReader(" Hello, \n\t World!")
+       # assert w.read_word == "Hello,"
+       # assert w.read_char == '\n'.ascii
+       # assert w.read_word == "World!"
+       # assert w.read_word == ""
+       # ~~~
+       #
+       # `Char::is_whitespace` determines what is a whitespace.
+       fun read_word: String
+       do
+               var buf = new FlatBuffer
+               var c = read_nonwhitespace
+               if c > 0 then
+                       buf.add(c.ascii)
+                       while not eof do
+                               c = read_char
+                               if c < 0 then break
+                               var a = c.ascii
+                               if a.is_whitespace then break
+                               buf.add(a)
+                       end
+               end
+               var res = buf.to_s
+               return res
+       end
+
+       # Skip whitespace characters (if any) then return the following non-whitespace character.
+       #
+       # Returns the code point of the character.
+       # Return -1 on end of file or error.
+       #
+       # In fact, this method works like `read_char` except it skips whitespace.
+       #
+       # ~~~
+       # var w = new StringReader(" \nab\tc")
+       # assert w.read_nonwhitespace == 'a'.ascii
+       # assert w.read_nonwhitespace == 'b'.ascii
+       # assert w.read_nonwhitespace == 'c'.ascii
+       # assert w.read_nonwhitespace == -1
+       # ~~~
+       #
+       # `Char::is_whitespace` determines what is a whitespace.
+       fun read_nonwhitespace: Int
+       do
+               var c = -1
+               while not eof do
+                       c = read_char
+                       if c < 0 or not c.ascii.is_whitespace then break
+               end
+               return c
+       end
 end
 
 # Iterator returned by `Reader::each_line`.
index 88c4074..489654e 100644 (file)
@@ -350,12 +350,12 @@ abstract class Text
        #
        #     assert " \n\thello \n\t".l_trim == "hello \n\t"
        #
-       # A whitespace is defined as any character which ascii value is less than or equal to 32
+       # `Char::is_whitespace` determines what is a whitespace.
        fun l_trim: SELFTYPE
        do
                var iter = self.chars.iterator
                while iter.is_ok do
-                       if iter.item.ascii > 32 then break
+                       if not iter.item.is_whitespace then break
                        iter.next
                end
                if iter.index == length then return self.empty
@@ -366,12 +366,12 @@ abstract class Text
        #
        #     assert " \n\thello \n\t".r_trim == " \n\thello"
        #
-       # A whitespace is defined as any character which ascii value is less than or equal to 32
+       # `Char::is_whitespace` determines what is a whitespace.
        fun r_trim: SELFTYPE
        do
                var iter = self.chars.reverse_iterator
                while iter.is_ok do
-                       if iter.item.ascii > 32 then break
+                       if not iter.item.is_whitespace then break
                        iter.next
                end
                if iter.index < 0 then return self.empty
@@ -379,12 +379,29 @@ abstract class Text
        end
 
        # Trims trailing and preceding white spaces
-       # A whitespace is defined as any character which ascii value is less than or equal to 32
        #
        #     assert "  Hello  World !  ".trim   == "Hello  World !"
        #     assert "\na\nb\tc\t".trim          == "a\nb\tc"
+       #
+       # `Char::is_whitespace` determines what is a whitespace.
        fun trim: SELFTYPE do return (self.l_trim).r_trim
 
+       # Is the string non-empty but only made of whitespaces?
+       #
+       #    assert " \n\t ".is_whitespace    == true
+       #    assert "  hello  ".is_whitespace == false
+       #    assert "".is_whitespace          == false
+       #
+       # `Char::is_whitespace` determines what is a whitespace.
+       fun is_whitespace: Bool
+       do
+               if is_empty then return false
+               for c in self.chars do
+                       if not c.is_whitespace then return false
+               end
+               return true
+       end
+
        # Returns `self` removed from its last line terminator (if any).
        #
        #    assert "Hello\n".chomp == "Hello"
index 24adbed..94b3764 100644 (file)
@@ -57,7 +57,7 @@ Discrete -> Int [dir=back arrowtail=open style=dashed];
 Numeric -> Int [dir=back arrowtail=open style=dashed];
 
 Char [
- label = "{Char||+ to_i(): Int\l+ ascii(): Int\l+ to_lower(): Char\l+ to_upper(): Char\l+ is_digit(): Bool\l+ is_lower(): Bool\l+ is_upper(): Bool\l+ is_letter(): Bool\l}"
+ label = "{Char||+ to_i(): Int\l+ ascii(): Int\l+ to_lower(): Char\l+ to_upper(): Char\l+ is_digit(): Bool\l+ is_lower(): Bool\l+ is_upper(): Bool\l+ is_letter(): Bool\l+ is_whitespace(): Bool\l}"
 ]
 Discrete -> Char [dir=back arrowtail=open style=dashed];
 
index 81077d2..1664fce 100644 (file)
@@ -57,7 +57,7 @@ Discrete -> Int [dir=back arrowtail=open style=dashed];
 Numeric -> Int [dir=back arrowtail=open style=dashed];
 
 Char [
- label = "{Char||+ to_i(): Int\l+ ascii(): Int\l+ to_lower(): Char\l+ to_upper(): Char\l+ is_digit(): Bool\l+ is_lower(): Bool\l+ is_upper(): Bool\l+ is_letter(): Bool\l}"
+ label = "{Char||+ to_i(): Int\l+ ascii(): Int\l+ to_lower(): Char\l+ to_upper(): Char\l+ is_digit(): Bool\l+ is_lower(): Bool\l+ is_upper(): Bool\l+ is_letter(): Bool\l+ is_whitespace(): Bool\l}"
 ]
 Discrete -> Char [dir=back arrowtail=open style=dashed];