Fuzion Logo
flang.dev — The Fuzion Language Portal
JavaScript seems to be disabled. Functionality is limited.

i32.fz


# This file is part of the Fuzion language implementation.
#
# The Fuzion language implementation is free software: you can redistribute it
# and/or modify it under the terms of the GNU General Public License as published
# by the Free Software Foundation, version 3 of the License.
#
# The Fuzion language implementation is distributed in the hope that it will be
# useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
# License for more details.
#
# You should have received a copy of the GNU General Public License along with The
# Fuzion language implementation.  If not, see <https://www.gnu.org/licenses/>.


# -----------------------------------------------------------------------
#
#  Tokiwa Software GmbH, Germany
#
#  Source code of Fuzion standard library feature i32
#
#  Author: Fridtjof Siebert (siebert@tokiwa.software)
#
# -----------------------------------------------------------------------

# i32 -- 32-bit signed integer values
#
i32(val i32) : wrappingInteger<i32>, hasInterval<i32>, i32s is

  redef thiz => i32.this.val
  redef orderedThis => i32.this.val

  # overflow checking

  # would negation -thiz cause an overflow?
  redef wrappedOnNeg => isMin

  # would addtion thiz + other cause an overflow or underflow?
  redef overflowOnAdd (other i32) => thiz > 0 && max -° thiz < other
  redef underflowOnAdd(other i32) => thiz < 0 && min -° thiz > other

  # would subtraction thiz - other cause an overflow or underflow?
  redef overflowOnSub (other i32) => thiz > 0 && thiz -° max > other
  redef underflowOnSub(other i32) => thiz < 0 && thiz -° min < other

  # would multiplication thiz * other cause an overflow or underflow?
  redef overflowOnMul (other i32) => as_i64 *° other.as_i64 > max.as_i64
  redef underflowOnMul(other i32) => as_i64 *° other.as_i64 < min.as_i64

  # neg, add, sub, mul with wrap-around semantics
  redef prefix -° i32 is intrinsic
  redef infix +° (other i32) i32 is intrinsic
  redef infix -° (other i32) i32 is intrinsic
  redef infix *° (other i32) i32 is intrinsic

  # division and remainder with check for div-by-zero
  redef infix / (other i32)
    pre
      safety: other != 0
   => div(other)
  redef infix % (other i32)
    pre
      safety: other != 0
   => mod(other)

  # private division and remainder with crash in case of div-by-zero
  private div (other i32) i32 is intrinsic
  private mod (other i32) i32 is intrinsic

  # bitwise and, or and xor operations
  redef infix &  (other i32) i32 is intrinsic
  redef infix |  (other i32) i32 is intrinsic
  redef infix ^  (other i32) i32 is intrinsic

  # shift operations (signed)
  redef infix >> (other i32) i32 is intrinsic
  redef infix << (other i32) i32 is intrinsic

  # comparison
  redef infix == (other i32) bool is intrinsic
  redef infix != (other i32) bool is intrinsic
  redef infix <  (other i32) bool is intrinsic
  redef infix <= (other i32) bool is intrinsic
  redef infix >  (other i32) bool is intrinsic
  redef infix >= (other i32) bool is intrinsic

  # conversion to u32, i64 and u64, with range check
  as_i8 i8
    pre
      thiz >= i8.min.as_i32,
      thiz <= i8.max.as_i32
    is
      low8bits.castTo_i8
  as_i16 i16
    pre
      thiz >= i16.min.as_i32,
      thiz <= i16.max.as_i32
    is
      low16bits.castTo_i16
  as_i64 i64 is intrinsic
# as_i128 NYI
  as_u8 u8
    pre
      thiz >= u8.min.as_i32,
      thiz <= u8.max.as_i32
    is
      low8bits
  as_u16 u16
    pre
      thiz >= u16.min.as_i32,
      thiz <= u16.max.as_i32
    is
      low16bits
  as_u32 u32
    pre
      debug: thiz >= 0
    is
      castTo_u32
  as_u64 u64
    pre
      debug: thiz >= 0
    is
      as_i64.as_u64
  as_u128 u128
    pre
      debug: thiz >= 0
    is
      u128 0 as_i64.as_u64

  # casting bit representation to unsigned
  low8bits    u8   is castTo_u32.low8bits   # 0x1234_5678 ->        0x78, -0x1234_5678 -> 0x88
  low16bits   u16  is castTo_u32.low16bits  # 0x1234_5678 ->      0x5678, -0x1234_5678 -> 0xa988
  castTo_u32  u32  is intrinsic             # 0x1234_5678 -> 0x1234_5678, -0x1234_5678 -> 0xedcb_a988
  castTo_u64  u64  is castTo_u32.as_u64     # 0x1234_5678 -> 0x1234_5678, -0x1234_5678 -> 0x0000_0000_edcb_a988
  castTo_u128 u128 is castTo_u32.as_u128    # 0x1234_5678 -> 0x1234_5678, -0x1234_5678 -> 0x0000_0000_0000_0000_0000_0000_edcb_a988

  # conversion to float
  as_f64 f64 is intrinsic
  as_f32 => as_f64.as_f32

  # NYI: max is redefined here only to solve repeated inheritance conflict. Since max inherited
  # from hasInterval<i32> is abstract, fz should not complain about this conflict.
  redef max => 0x_7fff_ffff


  # create hash code from this number
  hash u64 is
    castTo_u64.hash


  # find the highest 1 bit in this integer and return integer with
  # this single bit set or 0 if this is 0.
  #
  highestOneBit i32 is
    val.castTo_u32.highestOneBit.castTo_i32


  # count the number of trailing zeros in this integer.
  #
  trailingZeros i32 is
    val.castTo_u32.trailingZeros


  # count the number of 1 bits in the binary representation of this
  # integer.
  #
  onesCount i32 is
    val.castTo_u32.onesCount


# i32s -- unit type defining features related to i32 but not requiring an
# instance
#
i32s : wrappingIntegers<i32> is

  redef name => "i32"

  redef zero => 0
  redef one  => 1

  redef min => -0x_8000_0000
  redef max =>  0x_7fff_ffff


# i32 -- returns value of unit type i32s
#
# This is a convenience feature that allows using, e.g., 'i32.sum' to
# get the the monoid of (i32, infix +) instead of 'i32s.sum'.
#
# since this i32 with no arguments is a routine and not a constructor, it
# does not define a type (which would cause a name clash with i32 with one
# argument).
#
i32 => i32s