# encoding: utf-8 # frozen_string_literal: true module Carbon module Core module Integer # Defines the "spaceship" function on all integers except booleans. The # spaceship operator compares two integers, and returns three possible # values depending on the order of the integers: `1` if the receiver # (`this`) is greater than the right (`other`), `0` if `this` is equal # to `other`, and `-1` if `this` is less than `other`. This is useful # for determining the order of things. This module defines a single # function on all integers except boolean: # # - `.<=>(self, other: T): Carbon::Int8` # # The function returns `Carbon::Int8` because it is the smallest possible # integer type that retains sign information. module Ship # Defines the spaceship function (`:<=>`). The left and right integer # types are given. The spaceship function works the same as the one # in Ruby: # # - If the left value is less than the right value, return -1; # otherwise, # - If the left value is equal to the right value, return 0; # otherwise, # - The left value is greater than the right value, return 1. # # @param left [Core::Int] The left (receiver) value. # @param right [Core::Int] The right value. # @return [void] def define_ship_function(left, right) return if left.size == 1 || right.size == 1 function_name = left.name.call(:<=>, [left.name, right.name]) Core.define(function: function_name) do |function| function[:return] = Carbon::Type("Carbon::Int8") define_ship_definition(left, right, function[:definition]) end end private def define_ship_definition(left, right, definition) blocks = %w(entry thisother) .map { |n| definition.add(n) } params = definition.params params[0].name, params[1].name = %w(self other) params = force_same_cast(params, blocks[0].build, left, right) define_ship_definition_returns(blocks) define_ship_definition_compare(params, blocks) end def define_ship_definition_returns(blocks) blocks[1].build.ret(1) blocks[3].build.ret(0) blocks[4].build.ret(-1) end def define_ship_definition_compare(params, blocks) blocks[0] .build { |b| b.br(b.icmp(:lt, *params).as(Carbon::Boolean), blocks[1], blocks[2]) } blocks[2] .build { |b| b.br(b.icmp(:eq, *params).as(Carbon::Boolean), blocks[3], blocks[4]) } end end end end end