src: Update literal to properly support underscores in decimal literals
[nit.git] / src / literal.nit
index 5af1808..f5f70b0 100644 (file)
@@ -20,6 +20,7 @@ module literal
 import phase
 
 redef class ToolContext
+       # Parses literal values in the whole AST and produces errors if needed
        var literal_phase: Phase = new LiteralPhase(self, null)
 end
 
@@ -71,22 +72,19 @@ redef class AExpr
                if not self isa AIntExpr then return null
                return self.value.as(not null)
        end
+end
 
-       # Get `self` as a single identifier.
-       # Return null if not a single identifier.
-       fun as_id: nullable String
-       do
-               if self isa AMethidExpr then
-                       return self.collect_text
+redef class Text
+       private fun remove_underscores: Text do
+               var b = new FlatBuffer
+               for i in chars do
+                       if i == '_' then continue
+                       b.add i
                end
-               if not self isa ACallExpr then return null
-               if not self.n_expr isa AImplicitSelfExpr then return null
-               if not self.n_args.n_exprs.is_empty then return null
-               return self.n_id.text
+               return b
        end
 end
 
-
 redef class AIntExpr
        # The value of the literal int once computed.
        var value: nullable Int
@@ -95,14 +93,95 @@ end
 redef class ADecIntExpr
        redef fun accept_literal(v)
        do
-               self.value = self.n_number.text.to_i
+               value = self.n_number.text.remove_underscores.to_i
        end
 end
 
 redef class AHexIntExpr
        redef fun accept_literal(v)
        do
-               self.value = self.n_hex_number.text.substring_from(2).to_hex
+               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
+               end
+               value = s.to_hex
+       end
+end
+
+redef class ABinIntExpr
+       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
+       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
+
+redef class AByteExpr
+       # The value of the literal int once computed.
+       var value: nullable Byte
+end
+
+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
+
+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
+
+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
+
+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
 
@@ -122,7 +201,7 @@ redef class ACharExpr
        do
                var txt = self.n_char.text.unescape_nit
                if txt.length != 3 then
-                       v.toolcontext.error(self.hot_location, "Invalid character literal {txt}")
+                       v.toolcontext.error(self.hot_location, "Syntax Error: invalid character literal `{txt}`.")
                        return
                end
                self.value = txt.chars[1]