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.
- checksums.yaml +7 -0
- data/.gitignore +13 -0
- data/.rspec +2 -0
- data/.rubocop.yml +38 -0
- data/.travis.yml +4 -0
- data/.yardopts +1 -0
- data/CODE_OF_CONDUCT.md +49 -0
- data/Gemfile +11 -0
- data/LICENSE.txt +21 -0
- data/README.md +41 -0
- data/Rakefile +14 -0
- data/carbon.gemspec +30 -0
- data/lib/carbon.rb +54 -0
- data/lib/carbon/concrete.rb +43 -0
- data/lib/carbon/concrete/build.rb +63 -0
- data/lib/carbon/concrete/index.rb +324 -0
- data/lib/carbon/concrete/item.rb +37 -0
- data/lib/carbon/concrete/item/base.rb +153 -0
- data/lib/carbon/concrete/item/data.rb +22 -0
- data/lib/carbon/concrete/item/function.rb +97 -0
- data/lib/carbon/concrete/item/internal.rb +83 -0
- data/lib/carbon/concrete/item/struct.rb +65 -0
- data/lib/carbon/concrete/item/struct/element.rb +42 -0
- data/lib/carbon/concrete/item/trait.rb +72 -0
- data/lib/carbon/concrete/item/trait/expectation.rb +55 -0
- data/lib/carbon/concrete/request.rb +137 -0
- data/lib/carbon/concrete/type.rb +260 -0
- data/lib/carbon/concrete/type/function.rb +91 -0
- data/lib/carbon/concrete/type/generic.rb +118 -0
- data/lib/carbon/concrete/type/name.rb +147 -0
- data/lib/carbon/concrete/type/parse.rb +172 -0
- data/lib/carbon/concrete/type/part.rb +100 -0
- data/lib/carbon/core.rb +61 -0
- data/lib/carbon/core/int.rb +87 -0
- data/lib/carbon/core/integer.rb +109 -0
- data/lib/carbon/core/integer/cast.rb +83 -0
- data/lib/carbon/core/integer/math.rb +198 -0
- data/lib/carbon/core/integer/misc.rb +145 -0
- data/lib/carbon/core/integer/pole.rb +133 -0
- data/lib/carbon/core/integer/ship.rb +71 -0
- data/lib/carbon/core/integer/sign.rb +52 -0
- data/lib/carbon/core/integer/type.rb +42 -0
- data/lib/carbon/core/integer/zero.rb +52 -0
- data/lib/carbon/core/pointer.rb +54 -0
- data/lib/carbon/core/pointer/access.rb +123 -0
- data/lib/carbon/core/pointer/cast.rb +55 -0
- data/lib/carbon/core/pointer/math.rb +187 -0
- data/lib/carbon/core/pointer/memory.rb +85 -0
- data/lib/carbon/core/pointer/type.rb +23 -0
- data/lib/carbon/tacky.rb +21 -0
- data/lib/carbon/tacky/block.rb +96 -0
- data/lib/carbon/tacky/builder.rb +310 -0
- data/lib/carbon/tacky/context.rb +66 -0
- data/lib/carbon/tacky/function.rb +137 -0
- data/lib/carbon/tacky/instruction.rb +170 -0
- data/lib/carbon/tacky/parameter.rb +23 -0
- data/lib/carbon/tacky/reference.rb +23 -0
- data/lib/carbon/tacky/value.rb +40 -0
- data/lib/carbon/version.rb +9 -0
- 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
|
data/lib/carbon/core.rb
ADDED
@@ -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
|