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