# encoding: utf-8 # frozen_string_literal: true module Carbon module Core module Integer # Defines cast functions for integers. This applies to all integers. # This guarentees that the following functions exist on all integers: # # - `.to-int64(self): Carbon::Int64` # - `.to-uint64(self): Carbon::UInt64` # - `.to-int32(self): Carbon::Int32` # - `.to-uint32(self): Carbon::UInt32` # - `.to-int16(self): Carbon::Int16` # - `.to-uint16(self): Carbon::UInt16` # - `.to-int8(self): Carbon::Int8` # - `.to-uint8(self): Carbon::UInt8` # # These functions upcast and downcast as nessicary, but use the sign of # the original number to determine how the casting should be handled. # For example, an `Int32` is upcast to a `UInt64` using the # sign-extension instruction; however, a `UInt32` is upcast to a `Int32` # using the zero-extension instruction. This is to keep the same number # as the value, but just converted to a longer number. This is in line # with the behavior of C. # # @api private module Cast # Defines a cast function for a single pair of integers. # # @param from [Core::Int] The source integer. # @param to [Core::Int] The destination integer. # @return [void] def define_cast_function(from, to) function_name = from.name.call(to.cast, [from.name]) Core.define(function: function_name) do |function| function[:return] = to.name perform_cast(from, to, function[:definition]) end end private # rubocop:disable Metrics/AbcSize # rubocop:disable Metrics/MethodLength def perform_cast(from, to, definition) entry = definition.add("entry").build this = definition.params[0] this.name = "self" # from <=> to -> from - to case [from.sign, from.size <=> to.size] when [:unsigned, 0], [:signed, 0] sidecast(entry, this, to.name) when [:unsigned, 1], [:signed, 1] downcast(entry, this, to.name) when [:unsigned, -1] upcast_unsigned(entry, this, to.name) when [:signed, -1] upcast_signed(entry, this, to.name) else fail # no way you can get here end end def upcast_signed(entry, this, to) entry.ret(entry.sext(this, to).as(this.type)) end def upcast_unsigned(entry, this, to) entry.ret(entry.zext(this, to).as(this.type)) end def downcast(entry, this, to) entry.ret(entry.trunc(this, to).as(this.type)) end def sidecast(entry, this, to) entry.ret(entry.int_cast(this, to).as(this.type)) end end end end end