carbon-core 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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