Numerical constants

Numerical constants are of a single type and have the form:

  1. hexdigit = digit | 'A'..'F' | 'a'..'f'
  2. octdigit = '0'..'7'
  3. bindigit = '0'..'1'
  4. HEX_LIT = '0' ('x' | 'X' ) hexdigit ( ['_'] hexdigit )*
  5. DEC_LIT = digit ( ['_'] digit )*
  6. OCT_LIT = '0' 'o' octdigit ( ['_'] octdigit )*
  7. BIN_LIT = '0' ('b' | 'B' ) bindigit ( ['_'] bindigit )*
  8. INT_LIT = HEX_LIT
  9. | DEC_LIT
  10. | OCT_LIT
  11. | BIN_LIT
  12. INT8_LIT = INT_LIT ['\''] ('i' | 'I') '8'
  13. INT16_LIT = INT_LIT ['\''] ('i' | 'I') '16'
  14. INT32_LIT = INT_LIT ['\''] ('i' | 'I') '32'
  15. INT64_LIT = INT_LIT ['\''] ('i' | 'I') '64'
  16. UINT_LIT = INT_LIT ['\''] ('u' | 'U')
  17. UINT8_LIT = INT_LIT ['\''] ('u' | 'U') '8'
  18. UINT16_LIT = INT_LIT ['\''] ('u' | 'U') '16'
  19. UINT32_LIT = INT_LIT ['\''] ('u' | 'U') '32'
  20. UINT64_LIT = INT_LIT ['\''] ('u' | 'U') '64'
  21. exponent = ('e' | 'E' ) ['+' | '-'] digit ( ['_'] digit )*
  22. FLOAT_LIT = digit (['_'] digit)* (('.' digit (['_'] digit)* [exponent]) |exponent)
  23. FLOAT32_SUFFIX = ('f' | 'F') ['32']
  24. FLOAT32_LIT = HEX_LIT '\'' FLOAT32_SUFFIX
  25. | (FLOAT_LIT | DEC_LIT | OCT_LIT | BIN_LIT) ['\''] FLOAT32_SUFFIX
  26. FLOAT64_SUFFIX = ( ('f' | 'F') '64' ) | 'd' | 'D'
  27. FLOAT64_LIT = HEX_LIT '\'' FLOAT64_SUFFIX
  28. | (FLOAT_LIT | DEC_LIT | OCT_LIT | BIN_LIT) ['\''] FLOAT64_SUFFIX

As can be seen in the productions, numerical constants can contain underscores for readability. Integer and floating point literals may be given in decimal (no prefix), binary (prefix 0b), octal (prefix 0o) and hexadecimal (prefix 0x) notation.

There exists a literal for each numerical type that is defined. The suffix starting with an apostrophe (‘’’) is called a type suffix. Literals without a type suffix are of an integer type, unless the literal contains a dot or E|e in which case it is of type float. This integer type is int if the literal is in the range low(i32)..high(i32), otherwise it is int64. For notational convenience the apostrophe of a type suffix is optional if it is not ambiguous (only hexadecimal floating point literals with a type suffix can be ambiguous).

The type suffixes are:

Type SuffixResulting type of literal
‘i8int8
‘i16int16
‘i32int32
‘i64int64
‘uuint
‘u8uint8
‘u16uint16
‘u32uint32
‘u64uint64
‘ffloat32
‘dfloat64
‘f32float32
‘f64float64

Floating point literals may also be in binary, octal or hexadecimal notation: 0B0_10001110100_0000101001000111101011101111111011000101001101001001’f64 is approximately 1.72826e35 according to the IEEE floating point standard.

Literals are bounds checked so that they fit the datatype. Non base-10 literals are used mainly for flags and bit pattern representations, therefore bounds checking is done on bit width, not value range. If the literal fits in the bit width of the datatype, it is accepted. Hence: 0b10000000’u8 == 0x80’u8 == 128, but, 0b10000000’i8 == 0x80’i8 == -1 instead of causing an overflow error.