carbon-core 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +13 -0
  3. data/.rspec +2 -0
  4. data/.rubocop.yml +38 -0
  5. data/.travis.yml +4 -0
  6. data/.yardopts +1 -0
  7. data/CODE_OF_CONDUCT.md +49 -0
  8. data/Gemfile +11 -0
  9. data/LICENSE.txt +21 -0
  10. data/README.md +41 -0
  11. data/Rakefile +14 -0
  12. data/carbon.gemspec +30 -0
  13. data/lib/carbon.rb +54 -0
  14. data/lib/carbon/concrete.rb +43 -0
  15. data/lib/carbon/concrete/build.rb +63 -0
  16. data/lib/carbon/concrete/index.rb +324 -0
  17. data/lib/carbon/concrete/item.rb +37 -0
  18. data/lib/carbon/concrete/item/base.rb +153 -0
  19. data/lib/carbon/concrete/item/data.rb +22 -0
  20. data/lib/carbon/concrete/item/function.rb +97 -0
  21. data/lib/carbon/concrete/item/internal.rb +83 -0
  22. data/lib/carbon/concrete/item/struct.rb +65 -0
  23. data/lib/carbon/concrete/item/struct/element.rb +42 -0
  24. data/lib/carbon/concrete/item/trait.rb +72 -0
  25. data/lib/carbon/concrete/item/trait/expectation.rb +55 -0
  26. data/lib/carbon/concrete/request.rb +137 -0
  27. data/lib/carbon/concrete/type.rb +260 -0
  28. data/lib/carbon/concrete/type/function.rb +91 -0
  29. data/lib/carbon/concrete/type/generic.rb +118 -0
  30. data/lib/carbon/concrete/type/name.rb +147 -0
  31. data/lib/carbon/concrete/type/parse.rb +172 -0
  32. data/lib/carbon/concrete/type/part.rb +100 -0
  33. data/lib/carbon/core.rb +61 -0
  34. data/lib/carbon/core/int.rb +87 -0
  35. data/lib/carbon/core/integer.rb +109 -0
  36. data/lib/carbon/core/integer/cast.rb +83 -0
  37. data/lib/carbon/core/integer/math.rb +198 -0
  38. data/lib/carbon/core/integer/misc.rb +145 -0
  39. data/lib/carbon/core/integer/pole.rb +133 -0
  40. data/lib/carbon/core/integer/ship.rb +71 -0
  41. data/lib/carbon/core/integer/sign.rb +52 -0
  42. data/lib/carbon/core/integer/type.rb +42 -0
  43. data/lib/carbon/core/integer/zero.rb +52 -0
  44. data/lib/carbon/core/pointer.rb +54 -0
  45. data/lib/carbon/core/pointer/access.rb +123 -0
  46. data/lib/carbon/core/pointer/cast.rb +55 -0
  47. data/lib/carbon/core/pointer/math.rb +187 -0
  48. data/lib/carbon/core/pointer/memory.rb +85 -0
  49. data/lib/carbon/core/pointer/type.rb +23 -0
  50. data/lib/carbon/tacky.rb +21 -0
  51. data/lib/carbon/tacky/block.rb +96 -0
  52. data/lib/carbon/tacky/builder.rb +310 -0
  53. data/lib/carbon/tacky/context.rb +66 -0
  54. data/lib/carbon/tacky/function.rb +137 -0
  55. data/lib/carbon/tacky/instruction.rb +170 -0
  56. data/lib/carbon/tacky/parameter.rb +23 -0
  57. data/lib/carbon/tacky/reference.rb +23 -0
  58. data/lib/carbon/tacky/value.rb +40 -0
  59. data/lib/carbon/version.rb +9 -0
  60. metadata +186 -0
@@ -0,0 +1,100 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ module Carbon
5
+ module Concrete
6
+ class Type
7
+ # A single part of the type. This only contains the name of the part,
8
+ # and the generics for the part. For most parts, the generics are
9
+ # ignored (or even stripped; see {#strip}).
10
+ #
11
+ # @note
12
+ # **This class is frozen upon initialization.** This means that any
13
+ # attempt to modify it will result in an error. In most cases, the
14
+ # attributes on this class will also be frozen, as well.
15
+ class Part
16
+ # The value of the part. This is normally the lexeme or the string
17
+ # associated with the part.
18
+ #
19
+ # @api public
20
+ # @example
21
+ # type = Carbon::Type("Carbon::Pointer<T>")
22
+ # part = type.name.last
23
+ # part.value # => "Pointer"
24
+ # @return [::String] The value.
25
+ attr_reader :value
26
+
27
+ # The generics of the part. This is normally an empty array unless
28
+ # it is both the last part of a name, and contain generic information
29
+ # from the original source text.
30
+ #
31
+ # @api public
32
+ # @example
33
+ # type = Carbon::Type("Carbon::Pointer<T>")
34
+ # type.name.first.generics # => []
35
+ # type.name.last.generics # => [#<Carbon::Concrete::Type::Generic T>]
36
+ # @return [<Type::Generic>] The generics.
37
+ attr_reader :generics
38
+
39
+ # Initialize the part with the given value and generics.
40
+ #
41
+ # @see #value
42
+ # @see #generics
43
+ # @param value [::String] The value.
44
+ # @param generics [<Type::Generic>] The generics.
45
+ def initialize(value, generics)
46
+ @value = value
47
+ @generics = generics
48
+ deep_freeze!
49
+ end
50
+
51
+ # Strips the part. This returns a new part with all of the generic
52
+ # information removed. During parsing, this is applied to all parts
53
+ # except the last part of the name, since the generics for the parts
54
+ # except the last are ignored.
55
+ #
56
+ # @api public
57
+ # @example
58
+ # type = Carbon::Type("Carbon::Pointer<T>")
59
+ # part = type.name.last
60
+ # part.generics.map(&:to_s) # => ["T"]
61
+ # part.strip.generics.map(&:to_s) # => []
62
+ # @return [Part] The new part.
63
+ def strip
64
+ Part.new(value, [])
65
+ end
66
+
67
+ # Returns the interned value of this part. This contains no generic
68
+ # information, and as such, is the same as the value of the part.
69
+ #
70
+ # @api public
71
+ # @example
72
+ # type = Carbon::Type("Carbon::Pointer<T>")
73
+ # type.name.last.intern # => "Pointer"
74
+ # @note See {Item::Base#intern} For more information about interned
75
+ # names.
76
+ # @return [::String] The interned value of this part.
77
+ def intern
78
+ value
79
+ end
80
+
81
+ # Returns a string representation of this part. This contains all of
82
+ # the generic information, if it exists; otherwise, it is the same as
83
+ # {#intern}.
84
+ #
85
+ # @api public
86
+ # @example
87
+ # type = Carbon::Type("Carbon::Pointer<T>")
88
+ # type.name.last.to_s # => "Pointer<T>"
89
+ # @return [::String] The string representation of the part.
90
+ def to_s
91
+ if @generics.any?
92
+ "#{@value}<#{@generics.map(&:to_s).join(', ')}>".freeze
93
+ else
94
+ @value
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,61 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ require "pathname"
5
+
6
+ module Carbon
7
+ # The Carbon Core library. This is the library that is loaded for every
8
+ # program, and contains definitions that cannot be defined from within
9
+ # Carbon. The Carbon Core library is required for any Carbon program
10
+ # to function.
11
+ #
12
+ # @api private
13
+ module Core
14
+ PATH = Pathname.new(File.expand_path("../core/core.clib", __FILE__))
15
+ # The core index. This can either be loaded from a core library file or
16
+ # from the definitions in this library.
17
+ #
18
+ # @return [Concrete::Index] The Carbon Core library index.
19
+ def self.index
20
+ @index ||= find
21
+ end
22
+
23
+ # Defines an item on the core index.
24
+ #
25
+ # @see .index
26
+ # @see Concrete::Index#define
27
+ # @api semipublic
28
+ # @example (see Concrete::Index#define)
29
+ # @param (see Concrete::Index#define)
30
+ # @yield (see Concrete::Index#define)
31
+ # @yieldparam (see Concrete::Index#define)
32
+ # @raise (see Concrete::Index#define)
33
+ # @return (see Concrete::Index#define)
34
+ def self.define(*options, &block)
35
+ index.define(*options, &block)
36
+ end
37
+
38
+ # Finalizes the index by defining all of the types on it.
39
+ #
40
+ # @api private
41
+ # @return [void]
42
+ def self.finalize
43
+ Core::Integer.define_integer
44
+ Core::Pointer.define_pointer
45
+ index
46
+ end
47
+
48
+ def self.find
49
+ if PATH.exist?
50
+ Concrete.load(PATH.read)
51
+ else
52
+ @index = Concrete::Index.new
53
+ finalize.tap { |i| PATH.write(Concrete.dump(i)) }
54
+ end
55
+ end
56
+
57
+ require "carbon/core/int"
58
+ require "carbon/core/integer"
59
+ require "carbon/core/pointer"
60
+ end
61
+ end
@@ -0,0 +1,87 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ module Carbon
5
+ module Core
6
+ # An integer type in Carbon. The integer types are kept in here in order
7
+ # to keep track of the properties of each integer type.
8
+ #
9
+ # @api private
10
+ class Int
11
+ # The name of the integer type.
12
+ #
13
+ # @api public
14
+ # @example
15
+ # int.name # => #<Carbon::Concrete::Type Carbon::Boolean>
16
+ # @return [Carbon::Concrete::Type] The name.
17
+ attr_reader :name
18
+
19
+ # The name of the function that casts another integer to this one.
20
+ #
21
+ # @api public
22
+ # @example
23
+ # int.cast # => "to-bool"
24
+ # @return [::String] The cast function name.
25
+ attr_reader :cast
26
+
27
+ # The signage of the integer type. This is either `:signed` or
28
+ # `:unsigned`. `:signed` implies two's compliment.
29
+ #
30
+ # @api public
31
+ # @example
32
+ # int.sign # => :unsigned
33
+ # @return [::Symbol] How the integer is signed.
34
+ attr_reader :sign
35
+
36
+ # The number of bits in the integer. This is normally a power of two.
37
+ #
38
+ # @api public
39
+ # @example
40
+ # int.size # => 1
41
+ # @return [::Integer] The size of the integer.
42
+ attr_reader :size
43
+
44
+ # Finds a specific integer with the given size and signage. Uses
45
+ # {Ints} as the base.
46
+ #
47
+ # @param size [::Integer] The size of the integer.
48
+ # @param sign [::Symbol] How the integer should be signed.
49
+ # @return [Int] If an integer with the given size and signage is found.
50
+ # @return [nil] Otherwise.
51
+ def self.find(size:, sign:)
52
+ Ints.find { |i| i.size == size && i.sign == sign }
53
+ end
54
+
55
+ # Initialize the int.
56
+ #
57
+ # @param name [Carbon::Concrete::Type] The type of the integer.
58
+ # @param cast [::String] The cast function name.
59
+ # @param sign [::Symbol] How the integer is signed.
60
+ # @param size [::Integer] The size of the integer, in bits.
61
+ def initialize(name, cast, sign, size)
62
+ @name = name
63
+ @cast = cast
64
+ @sign = sign
65
+ @size = size
66
+
67
+ deep_freeze!
68
+ end
69
+ end
70
+
71
+ # The integeral types that are defined in Carbon, and all information
72
+ # pertaining to them.
73
+ #
74
+ # @return [<Int>]
75
+ Ints = [
76
+ ["Carbon::Int64", "to-int64", :signed, 64],
77
+ ["Carbon::UInt64", "to-uint64", :unsigned, 64],
78
+ ["Carbon::Int32", "to-int32", :signed, 32],
79
+ ["Carbon::UInt32", "to-uint32", :unsigned, 32],
80
+ ["Carbon::Int16", "to-int16", :signed, 16],
81
+ ["Carbon::UInt16", "to-uint16", :unsigned, 16],
82
+ ["Carbon::Int8", "to-int8", :signed, 8],
83
+ ["Carbon::UInt8", "to-uint8", :unsigned, 8],
84
+ ["Carbon::Boolean", "to-bool", :unsigned, 1]
85
+ ].map { |a| Int.new(Carbon::Type(a[0]), *a[1..-1]) }.deep_freeze!
86
+ end
87
+ end
@@ -0,0 +1,109 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ require "carbon/core/integer/cast"
5
+ require "carbon/core/integer/math"
6
+ require "carbon/core/integer/misc"
7
+ require "carbon/core/integer/pole"
8
+ require "carbon/core/integer/ship"
9
+ require "carbon/core/integer/sign"
10
+ require "carbon/core/integer/type"
11
+ require "carbon/core/integer/zero"
12
+
13
+ module Carbon
14
+ module Core
15
+ # Manages all Integer definitions for the Core library. This includes
16
+ # all nine (9) types and all 1298 integer functions.
17
+ #
18
+ # @api private
19
+ module Integer
20
+ extend Integer::Cast
21
+ extend Integer::Math
22
+ extend Integer::Misc
23
+ extend Integer::Pole
24
+ extend Integer::Ship
25
+ extend Integer::Sign
26
+ extend Integer::Type
27
+ extend Integer::Zero
28
+
29
+ class << self
30
+ # Defines all integer definitions on the Core library. This just calls
31
+ # {.define_integer_types} and {.define_integer_functions}.
32
+ #
33
+ # @api private
34
+ # @see #define_integer_types
35
+ # @see .define_integer_functions
36
+ # @return [self]
37
+ def define_integer
38
+ define_integer_types
39
+ define_integer_functions
40
+ self
41
+ end
42
+
43
+ # Defines all integer functions on the Core library.
44
+ #
45
+ # @api private
46
+ # @see #define_cast_function
47
+ # @see #define_math_functions
48
+ # @see #define_comp_functions
49
+ # @see #define_ship_function
50
+ # @see #define_next_function
51
+ # @see #define_prev_function
52
+ # @see #define_iabs_function
53
+ # @see #define_size_function
54
+ # @see #define_even_function
55
+ # @see #define_odd_function
56
+ # @see #define_positive_function
57
+ # @see #define_negative_function
58
+ # @see #define_sign_function
59
+ # @see #define_zero_function
60
+ # @see #define_nonzero_function
61
+ # @return [void]
62
+ def define_integer_functions
63
+ performed = Set.new
64
+ Ints.product(Ints).each do |(first, second)|
65
+ define_integer_functions_pair(first, second)
66
+ define_integer_functions_one(first) unless performed.include?(first)
67
+ performed << first
68
+ end
69
+ end
70
+
71
+ private
72
+
73
+ def define_integer_functions_pair(first, second)
74
+ define_cast_function(first, second) unless second.size == 1
75
+ return if first.size == 1 || second.size == 1
76
+
77
+ define_math_functions(first, second)
78
+ define_comp_functions(first, second)
79
+ define_ship_function(first, second)
80
+ end
81
+
82
+ # rubocop:disable Metrics/MethodLength
83
+ def define_integer_functions_one(first)
84
+ define_bool_function(first)
85
+ return if first.size == 1
86
+
87
+ # MISC
88
+ define_next_function(first)
89
+ define_prev_function(first)
90
+ define_iabs_function(first)
91
+ define_size_function(first)
92
+
93
+ # POLE
94
+ define_even_function(first)
95
+ define_odd_function(first)
96
+ define_positive_function(first)
97
+ define_negative_function(first)
98
+
99
+ # SIGN
100
+ define_sign_functions(first)
101
+
102
+ # ZERO
103
+ define_zero_function(first)
104
+ define_nonzero_function(first)
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,83 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ module Carbon
5
+ module Core
6
+ module Integer
7
+ # Defines cast functions for integers. This applies to all integers.
8
+ # This guarentees that the following functions exist on all integers:
9
+ #
10
+ # - `.to-int64(self): Carbon::Int64`
11
+ # - `.to-uint64(self): Carbon::UInt64`
12
+ # - `.to-int32(self): Carbon::Int32`
13
+ # - `.to-uint32(self): Carbon::UInt32`
14
+ # - `.to-int16(self): Carbon::Int16`
15
+ # - `.to-uint16(self): Carbon::UInt16`
16
+ # - `.to-int8(self): Carbon::Int8`
17
+ # - `.to-uint8(self): Carbon::UInt8`
18
+ #
19
+ # These functions upcast and downcast as nessicary, but use the sign of
20
+ # the original number to determine how the casting should be handled.
21
+ # For example, an `Int32` is upcast to a `UInt64` using the
22
+ # sign-extension instruction; however, a `UInt32` is upcast to a `Int32`
23
+ # using the zero-extension instruction. This is to keep the same number
24
+ # as the value, but just converted to a longer number. This is in line
25
+ # with the behavior of C.
26
+ #
27
+ # @api private
28
+ module Cast
29
+ # Defines a cast function for a single pair of integers.
30
+ #
31
+ # @param from [Core::Int] The source integer.
32
+ # @param to [Core::Int] The destination integer.
33
+ # @return [void]
34
+ def define_cast_function(from, to)
35
+ function_name = from.name.call(to.cast, [from.name])
36
+ Core.define(function: function_name) do |function|
37
+ function[:return] = to.name
38
+ perform_cast(from, to, function[:definition])
39
+ end
40
+ end
41
+
42
+ private
43
+
44
+ # rubocop:disable Metrics/AbcSize
45
+ # rubocop:disable Metrics/MethodLength
46
+ def perform_cast(from, to, definition)
47
+ entry = definition.add("entry").build
48
+ this = definition.params[0]
49
+ this.name = "self"
50
+
51
+ # from <=> to -> from - to
52
+ case [from.sign, from.size <=> to.size]
53
+ when [:unsigned, 0], [:signed, 0]
54
+ sidecast(entry, this, to.name)
55
+ when [:unsigned, 1], [:signed, 1]
56
+ downcast(entry, this, to.name)
57
+ when [:unsigned, -1]
58
+ upcast_unsigned(entry, this, to.name)
59
+ when [:signed, -1]
60
+ upcast_signed(entry, this, to.name)
61
+ else fail # no way you can get here
62
+ end
63
+ end
64
+
65
+ def upcast_signed(entry, this, to)
66
+ entry.ret(entry.sext(this, to))
67
+ end
68
+
69
+ def upcast_unsigned(entry, this, to)
70
+ entry.ret(entry.zext(this, to))
71
+ end
72
+
73
+ def downcast(entry, this, to)
74
+ entry.ret(entry.trunc(this, to))
75
+ end
76
+
77
+ def sidecast(entry, this, to)
78
+ entry.ret(entry.int_cast(this, to))
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,198 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ module Carbon
5
+ module Core
6
+ module Integer
7
+ # Defines math operations on almost all integers except booleans.
8
+ # Provides the following methods on all integer types except booleans:
9
+ #
10
+ # - `.+<T: Carbon::Numeric>(self, T: other): self`
11
+ # - `.-<T: Carbon::Numeric>(self, T: other): self`
12
+ # - `.*<T: Carbon::Numeric>(self, T: other): self`
13
+ # - `./<T: Carbon::Numeric>(self, T: other): self`
14
+ # - `.%<T: Carbon::Numeric>(self, T: other): self`
15
+ # - `.|<T: Carbon::Numeric>(self, T: other): self`
16
+ # - `.&<T: Carbon::Numeric>(self, T: other): self`
17
+ # - `.<<<T: Carbon::Numeric>(self, T: other): self`
18
+ # - `.>><T: Carbon::Numeric>(self, T: other): self`
19
+ # - `.^<T: Carbon::Numeric>(self, T: other): self`
20
+ # - `.==<T: Carbon::Numeric>(self, T: other): Carbon::Boolean`
21
+ # - `.===<T: Carbon::Numeric>(self, T: other): Carbon::Boolean`
22
+ # - `.<<T: Carbon::Numeric>(self, T: other): Carbon::Boolean`
23
+ # - `.><T: Carbon::Numeric>(self, T: other): Carbon::Boolean`
24
+ # - `.<=<T: Carbon::Numeric>(self, T: other): Carbon::Boolean`
25
+ # - `.>=<T: Carbon::Numeric>(self, T: other): Carbon::Boolean`
26
+ #
27
+ # Note that the core library never actually uses generics. Instead,
28
+ # all math operations are defined relative to another integer, and
29
+ # overloading is used to match to the right function. For example,
30
+ # `Int32.+(Int32, Int8)` is a different function than
31
+ # `Int32.+(Int32, UInt8)`; the functions use no actual generics.
32
+ #
33
+ # @api private
34
+ module Math
35
+ # The math operations that can be performed. Note that for LLVM,
36
+ # `:/`, `:%`, and `:>>` are sign-dependant.
37
+ #
38
+ #
39
+ # @return [<::Symbol>]
40
+ MATH_OPERATIONS = %i(+ - * / % | & << >> ^).freeze
41
+
42
+ # The comparison operations that can be performed. Note that for
43
+ # LLVM, `:<`, `:>`, `:<=`, and `:>=` are sign-dependant.
44
+ #
45
+ # @return [<::Symbol>]
46
+ COMP_OPERATIONS = %i(== === < > <= >=).freeze
47
+
48
+ # A mapping of comparison operations to their _icmp_ equivalents.
49
+ # Since most of the _icmp_ values are sign-dependant, the keys also
50
+ # contain sign information.
51
+ #
52
+ # @return [{(::Symbol, ::Symbol) => ::Symbol}]
53
+ COMP_OPERATIONS_MAP = {
54
+ [:unsigned, :==] => :eq, [:signed, :==] => :eq,
55
+ [:unsigned, :===] => :eq, [:signed, :===] => :eq,
56
+ [:unsigned, :<] => :ult, [:signed, :<] => :slt,
57
+ [:unsigned, :>] => :ugt, [:signed, :>] => :sgt,
58
+ [:unsigned, :<=] => :ule, [:signed, :<=] => :sle,
59
+ [:unsigned, :>=] => :uge, [:signed, :>=] => :sge
60
+ }.deep_freeze!
61
+
62
+ # Defines all of the math functions. The left and right integer types
63
+ # are given, and the {MATH_OPERATIONS} are iterated over, providing
64
+ # the operator for the {#define_math_function} method.
65
+ #
66
+ # @param left [Core::Int] The left (receiver) value.
67
+ # @param right [Core::Int] The right value.
68
+ # @return [void]
69
+ def define_math_functions(left, right)
70
+ MATH_OPERATIONS.each { |op| define_math_function(left, right, op) }
71
+ end
72
+
73
+ # Defines all of the comparison functinos. The left and right integer
74
+ # types are given, and the {COMP_OPERATIONS} are iterated over,
75
+ # providing the operator for the {#define_comp_function} method.
76
+ #
77
+ # @param left [Core::Int] The left (receiver) value.
78
+ # @param right [Core::Int] The right value.
79
+ # @return [void]
80
+ def define_comp_functions(left, right)
81
+ COMP_OPERATIONS.each { |op| define_comp_function(left, right, op) }
82
+ end
83
+
84
+ # Defines a math function. The left and right integer types are given,
85
+ # as well as the specific operation.
86
+ #
87
+ # @param left [Core::Int] The left (receiver) value.
88
+ # @param right [Core::Int] The right value.
89
+ # @param op [::Symbol] The mathmatical operation. One of
90
+ # {MATH_OPERATIONS}.
91
+ # @return [void]
92
+ def define_math_function(left, right, op)
93
+ function_name = left.name.call(op, [left.name, right.name])
94
+ Core.define(function: function_name) do |function|
95
+ function[:return] = left.name
96
+ define_math_definition(left, right, op, function[:definition])
97
+ end
98
+ end
99
+
100
+ # Defines a compare function. The left and right integer types are
101
+ # given, as well as the specific operation.
102
+ #
103
+ # @param left [Core::Int] The left (receiver) value.
104
+ # @param right [Core::Int] The right value.
105
+ # @param op [::Symbol] The comparison operation. One of
106
+ # {COMP_OPERATIONS}.
107
+ # @return [void]
108
+ def define_comp_function(left, right, op)
109
+ function_name = left.name.call(op, [left.name, right.name])
110
+ Core.define(function: function_name) do |function|
111
+ function[:return] = Carbon::Boolean
112
+ define_comp_definition(left, right, op, function[:definition])
113
+ end
114
+ end
115
+
116
+ private
117
+
118
+ def define_comp_definition(left, right, op, definition)
119
+ entry = definition.add("entry").build
120
+ params = definition.params
121
+ params[0].name, params[1].name = %w(self other)
122
+ this, other = force_same_cast(params, entry, left, right)
123
+ icmp = COMP_OPERATIONS_MAP.fetch(left.sign, op)
124
+ entry.ret(entry.icmp(icmp, this, other))
125
+ end
126
+
127
+ def define_math_definition(left, right, op, definition)
128
+ entry = definition.add("entry").build
129
+ params = definition.params
130
+ params[0].name, params[1].name = %w(self other)
131
+ this, other = force_same_cast(params, entry, left, right)
132
+ result = perform_operation(entry, [this, other], left, op)
133
+ return_original_size(entry, result, left, right)
134
+ end
135
+
136
+ OPERATIONS = {
137
+ :+ => :add, :- => :sub, :| => :or, :& => :and, :* => :mul,
138
+ :"^" => :xor, :<< => :shl
139
+ }.freeze
140
+
141
+ def perform_operation(entry, params, left, op)
142
+ if OPERATIONS.key?(op)
143
+ entry.public_send(OPERATIONS[op], *params)
144
+ elsif op == :>> then right_shift(entry, params, left)
145
+ elsif op == :/ then divide(entry, params, left)
146
+ elsif op == :% then remainder(entry, params, left)
147
+ else fail # Not possible.
148
+ end
149
+ end
150
+
151
+ def right_shift(entry, params, left)
152
+ case left.sign
153
+ when :unsigned then entry.lshr(*params)
154
+ when :signed then entry.ashr(*params)
155
+ end
156
+ end
157
+
158
+ def divide(entry, params, left)
159
+ case left.sign
160
+ when :unsigned then entry.udiv(*params)
161
+ when :signed then entry.sdiv(*params)
162
+ end
163
+ end
164
+
165
+ def remainder(entry, params, left)
166
+ case left.sign
167
+ when :unsigned then entry.urem(*params)
168
+ when :signed then entry.srem(*params)
169
+ end
170
+ end
171
+
172
+ def return_original_size(entry, result, left, right)
173
+ size = left.size <=> right.size
174
+ return entry.ret(result) if size == 0 || size == 1
175
+
176
+ type = Int.find(size: right.size, sign: left.sign)
177
+ fname = type.name.call(left.cast, [type.name])
178
+ entry.call(fname, result)
179
+ end
180
+
181
+ def force_same_cast(params, entry, left, right)
182
+ lcall, rcall = find_size(left, right)
183
+ [entry.call(lcall, params[0]),
184
+ entry.call(rcall, params[1])]
185
+ end
186
+
187
+ def find_size(left, right)
188
+ sign = left.sign
189
+ size = [left.size, right.size].max
190
+ fname = sign == :unsigned ? "to-uint#{size}" : "to-int#{size}"
191
+
192
+ [left.name.call(fname, [left.name]),
193
+ right.name.call(fname, [right.name])]
194
+ end
195
+ end
196
+ end
197
+ end
198
+ end