# encoding: utf-8 # frozen_string_literal: true module Carbon module Core module Pointer # Defines pointer arithmatic. This allows for addition and subtraction, # as well as comparison. This module defines the following functions: # # - `.+(self, other: N): self` # - `.-(self, other: N): self` # - `.<(self, other: N): Carbon::Boolean` # - `.>(self, other: N): Carbon::Boolean` # - `.<=(self, other: N): Carbon::Boolean` # - `.>=(self, other: N): Carbon::Boolean` # - `.<=>(self, other: N): Carbon::Int8` # - `.<(self, other: self): Carbon::Boolean` # - `.>(self, other: self): Carbon::Boolean` # - `.<=(self, other: self): Carbon::Boolean` # - `.>=(self, other: self): Carbon::Boolean` # - `.<=>(self, other: self): Carbon::Int8` # # These are defined for all integers except boolean. module Math # The math operations that can be applied to pointers. # # @return [<::Symbol>] MATH_OPERATIONS = %i(+ -).freeze # The comparison operations that can be applied to pointers. # # @return [<::Symbol>] COMP_OPERATIONS = %i(< > <= >=).freeze # Comprehensively defines all of the math, comparison, and spaceship # operations for pointers. # # @see #define_math_function # @see #define_comp_function # @see #define_space_function # @see #define_comp_pointer_function # @see #define_space_pointer_function # @return [void] def define_math_functions Ints.each do |int| next if int.size == 1 MATH_OPERATIONS.each { |op| define_math_function(int, op) } COMP_OPERATIONS.each { |op| define_comp_function(int, op) } define_space_function(int) end COMP_OPERATIONS.each { |op| define_comp_pointer_function(op) } define_space_pointer_function define_null_function end def define_null_function function_name = PTYPE.call(:null, []) Core.define(function: function_name) do |function| function[:return] = PTYPE define_null_definition(function[:definition]) end end # Defines the `<=>` function for two pointers. This returns `-1`, # `0`, or `1`, if the receiver is less than, equal to, or greater than # the parameter, respectively. # # @return [void] def define_space_pointer_function function_name = PTYPE.call(:<=>, [PTYPE, PTYPE]) Core.define(function: function_name) do |function| function[:return] = Carbon::Type("Carbon::Int8") define_space_pointer_definition(function[:definition]) end end # Defines a comparison function for two pointers. # # @param op [::Symbol] The operation that the function performs. # This should be one of {COMP_OPERATIONS}. # @return [void] def define_comp_pointer_function(op) function_name = PTYPE.call(op, [PTYPE, PTYPE]) Core.define(function: function_name) do |function| function[:return] = Carbon::Boolean define_comp_pointer_definition(op, function[:definition]) end end # Defines the space function (`<=>`) for a pointer and an integer. # It returns `-1`, `0`, or `1`, if the receiver is less than, equal to, # or greater than the parameter, respectively. # # @param int [Core::Int] The integer type to compare to. # @return [void] def define_space_function(int) function_name = PTYPE.call(:<=>, [PTYPE, int.name]) Core.define(function: function_name) do |function| function[:return] = Carbon::Type("Carbon::Int8") define_space_definition(int, function[:definition]) end end # Defines a given math function on a pointer. # # @param int [Core::Int] The integer type that the operation uses. # @param op [::Symbol] The math operation to perform. This should be # one of {MATH_OPERATIONS}. # @return [void] def define_math_function(int, op) function_name = PTYPE.call(op, [PTYPE, int.name]) Core.define(function: function_name) do |function| function[:return] = PTYPE define_math_definition(int, op, function[:definition]) end end # Defines a given comparison operation on a pointer. # # @param int [Core::Int] The integer type that the operation uses. # @param op [::Symbol] The comparison operation to perform. This should # be one of {COMP_OPERATIONS}. def define_comp_function(int, op) function_name = PTYPE.call(op, [PTYPE, int.name]) Core.define(function: function_name) do |function| function[:return] = Carbon::Boolean define_comp_definition(int, op, function[:definition]) end end private def perform_pointer_cast(entry, params, int) this, other = params this.name, other.name = %w(self other) fname = PTYPE.call(int.cast, [PTYPE]) thisint = entry.call(fname, this).as(int.name) otherint = entry.call(fname, other).as(int.name) [thisint, otherint] end def define_space_pointer_definition(definition) entry = definition.add("entry").build params = definition.params int = Int.find(sign: :signed, size: 64) this, other = perform_pointer_cast(entry, params, int) fname = PTYPE.call(:<=>, [int.name, int.name]) call = entry.call(fname, this, other) entry.ret(call.as(Carbon::Type("Carbon::Int8"))) end def define_comp_pointer_definition(op, definition) entry = definition.add("entry").build params = definition.params int = Ints.find { |i| i.sign == :signed && i.size == 64 } this, other = perform_pointer_cast(entry, params, int) icmp = Integer::Math::COMP_OPERATIONS_MAP.fetch([:signed, op]) entry.ret(entry.icmp(icmp, this, other).as(Carbon::Boolean)) end def define_space_definition(int, definition) entry = definition.add("entry").build this, other = definition.params this.name, other.name = %w(self other) fname = PTYPE.call(int.cast, [PTYPE]) intptr = entry.call(fname, this).as(int.name) fname = PTYPE.call(:<=>, [int.name, int.name]) compare = entry.call(fname, intptr, other) entry.ret(compare.as(Carbon::Type("Carbon::Int8"))) end def define_comp_definition(int, op, definition) entry = definition.add("entry").build this, other = definition.params this.name, other.name = %w(self other) fname = PTYPE.call(int.cast, [PTYPE]) intptr = entry.call(fname, this).as(int.name) icmp = Integer::Math::COMP_OPERATIONS_MAP.fetch([int.sign, op]) entry.ret(entry.icmp(icmp, intptr, other).as(Carbon::Boolean)) end def define_math_definition(_int, op, definition) entry = definition.add("entry").build this, other = definition.params this.name, other.name = %w(self other) other = entry.mul(other, -1).as(other.type) if op == :- entry.ret(entry.gep(this, other).as(PTYPE)) end def define_null_definition(definition) entry = definition.add("entry").build entry.ret(entry.null(PTYPE).as(PTYPE)) end end end end end