compiler: Added prefix and suffix support for `Char`
[nit.git] / src / literal.nit
index f9eafa0..72df12b 100644 (file)
@@ -69,131 +69,92 @@ redef class AExpr
        # Return null if not an integer.
        fun as_int: nullable Int
        do
-               if not self isa AIntExpr then return null
-               return self.value.as(not null)
+               if not self isa AIntegerExpr then return null
+               return self.value.as(not null).to_i
        end
 end
 
-redef class AIntExpr
+redef class AIntegerExpr
        # The value of the literal int once computed.
-       var value: nullable Int
-end
-
-redef class ADecIntExpr
-       redef fun accept_literal(v)
-       do
-               value = self.n_number.text.remove_underscores.to_i
-       end
-end
+       var value: nullable Numeric
 
-redef class AHexIntExpr
-       redef fun accept_literal(v)
-       do
-               var s = self.n_hex_number.text.substring_from(2).remove_underscores
-               if s.is_empty then
-                       v.toolcontext.error(location, "Error: invalid hexadecimal literal")
-                       return
+       redef fun accept_literal(v) do
+               value = n_integer.text.to_num
+               if value == null then
+                       v.toolcontext.error(hot_location, "Error: invalid literal `{n_integer.text}`")
                end
-               value = s.to_hex
        end
 end
 
-redef class ABinIntExpr
+redef class AFloatExpr
+       # The value of the literal float once computed.
+       var value: nullable Float
        redef fun accept_literal(v)
        do
-               var s = self.n_bin_number.text.substring_from(2).remove_underscores
-               if s.is_empty then
-                       v.toolcontext.error(location, "Error: invalid binary literal")
-                       return
-               end
-               value = s.to_bin
+               self.value = self.n_float.text.to_f
        end
 end
 
-redef class AOctIntExpr
-       redef fun accept_literal(v)
-       do
-               var s = self.n_oct_number.text.substring_from(2).remove_underscores
-               if s.is_empty then
-                       v.toolcontext.error(location, "Error: invalid octal literal")
-                       return
-               end
-               value = s.to_oct
-       end
-end
+# Any kind of literal which supports a prefix or a suffix
+class AAugmentedLiteral
+       # Returns the text of the token
+       private fun text: String is abstract
 
-redef class AByteExpr
-       # The value of the literal int once computed.
-       var value: nullable Byte
-end
+       # Is the combination of prefixes and suffixes in `self` valid ?
+       fun is_valid_augmentation: Bool is abstract
 
-redef class ADecByteExpr
-       redef fun accept_literal(v)
-       do
-               var t = self.n_bytenum.text
-               value = t.substring(0, t.length - 2).remove_underscores.to_i.to_b
-       end
-end
+       private fun delimiter_start: Char is abstract
 
-redef class AHexByteExpr
-       redef fun accept_literal(v)
-       do
-               var t = self.n_hex_bytenum.text
-               var s = t.substring(2, t.length - 4).remove_underscores
-               if s.is_empty then
-                       v.toolcontext.error(location, "Error: invalid hexadecimal literal")
-                       return
-               end
-               value = s.to_hex.to_b
-       end
-end
+       private fun delimiter_end: Char is abstract
 
-redef class ABinByteExpr
-       redef fun accept_literal(v)
-       do
-               var t = self.n_bin_bytenum.text
-               var s = t.substring(2, t.length - 4).remove_underscores
-               if s.is_empty then
-                       v.toolcontext.error(location, "Error: invalid binary literal")
-                       return
-               end
-               value = s.to_bin.to_b
-       end
-end
+       # Prefix for the entity, "" if no prefix is found
+       protected var prefix: String is lazy do return text.substring(0, text.index_of(delimiter_start))
 
-redef class AOctByteExpr
-       redef fun accept_literal(v)
-       do
-               var t = self.n_oct_bytenum.text
-               var s = t.substring(2, t.length - 4).remove_underscores
-               if s.is_empty then
-                       v.toolcontext.error(location, "Error: invalid octal literal")
-                       return
-               end
-               value = s.to_oct.to_b
-       end
-end
+       # Suffix for the entity, "" if no prefix is found
+       protected var suffix: String is lazy do return text.substring_from(text.last_index_of(delimiter_end) + 1)
 
-redef class AFloatExpr
-       # The value of the literal float once computed.
-       var value: nullable Float
-       redef fun accept_literal(v)
-       do
-               self.value = self.n_float.text.to_f
-       end
+       # Content of the entity, without prefix nor suffix
+       protected var content: String is lazy do return text.substring_from(text.index_of(delimiter_start)).substring(0, text.last_index_of(delimiter_end) + 1)
 end
 
 redef class ACharExpr
+       super AAugmentedLiteral
        # The value of the literal char once computed.
-       var value: nullable Char
+       var value: nullable Char = null
+
+       redef fun delimiter_start do return '\''
+
+       redef fun delimiter_end do return '\''
+
+       # Is the expression returning an ASCII byte value ?
+       fun is_ascii: Bool do return prefix == "b"
+
+       # Is the expression returning a Code Point ?
+       fun is_code_point: Bool do return prefix == "u"
+
+       redef fun text do return n_char.text
+
+       redef fun is_valid_augmentation do
+               if suffix != "" then return false
+               if is_ascii then return true
+               if is_code_point then return true
+               if prefix != "" then return false
+               return true
+       end
+
        redef fun accept_literal(v)
        do
-               var txt = self.n_char.text.unescape_nit
+               if not is_valid_augmentation then
+                       v.toolcontext.error(hot_location, "Syntax Error: invalid prefix/suffix combination {prefix}/{suffix}")
+                       return
+               end
+               var txt = content.unescape_nit
                if txt.length != 3 then
                        v.toolcontext.error(self.hot_location, "Syntax Error: invalid character literal `{txt}`.")
                        return
                end
                self.value = txt.chars[1]
+               if is_ascii and txt.chars[1].code_point > 127 then v.toolcontext.error(self.hot_location, "Syntax Error: usage of byte prefix on multibyte character.")
        end
 end