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,42 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Carbon
|
5
|
+
module Concrete
|
6
|
+
module Item
|
7
|
+
class Struct
|
8
|
+
# An element of a struct. Contains name and type information, and
|
9
|
+
# that's it.
|
10
|
+
#
|
11
|
+
# @api private
|
12
|
+
# @note
|
13
|
+
# **This class is frozen upon initialization.** This means that any
|
14
|
+
# attempt to modify it will result in an error. In most cases, the
|
15
|
+
# attributes on this class will also be frozen, as well.
|
16
|
+
class Element
|
17
|
+
# The name of the element.
|
18
|
+
#
|
19
|
+
# @return [::String]
|
20
|
+
attr_reader :name
|
21
|
+
|
22
|
+
# The type of the element.
|
23
|
+
#
|
24
|
+
# @return [Type]
|
25
|
+
attr_reader :type
|
26
|
+
|
27
|
+
# Initialize the element with the given name and type.
|
28
|
+
#
|
29
|
+
# @see #name
|
30
|
+
# @see #type
|
31
|
+
# @param name [::String] The name of the element.
|
32
|
+
# @param type [Type] The type of the element.
|
33
|
+
def initialize(name, type)
|
34
|
+
@name = name
|
35
|
+
@type = type
|
36
|
+
deep_freeze!
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "carbon/concrete/item/trait/expectation"
|
5
|
+
|
6
|
+
module Carbon
|
7
|
+
module Concrete
|
8
|
+
module Item
|
9
|
+
# A trait. This says that a specific type behaves with a certain set
|
10
|
+
# of functions.
|
11
|
+
#
|
12
|
+
# @api private
|
13
|
+
# @note
|
14
|
+
# **This class is frozen upon initialization.** This means that any
|
15
|
+
# attempt to modify it will result in an error. In most cases, the
|
16
|
+
# attributes on this class will also be frozen, as well.
|
17
|
+
class Trait
|
18
|
+
include Base
|
19
|
+
|
20
|
+
# (see Item::Base.from)
|
21
|
+
def self.from(type)
|
22
|
+
{ module: type, expectations: [] }
|
23
|
+
end
|
24
|
+
|
25
|
+
# The expectations for the trait.
|
26
|
+
#
|
27
|
+
# @api semipublic
|
28
|
+
# @example
|
29
|
+
# trait.expectations
|
30
|
+
# # => [#<Carbon::Concrete::Item::Trait::Expectation +)]
|
31
|
+
# @return [Set<Expectation>]
|
32
|
+
attr_reader :expectations
|
33
|
+
|
34
|
+
# Initialize the trait with data.
|
35
|
+
#
|
36
|
+
# @param data [::Hash] The data to initialize the trait with.
|
37
|
+
# @option data [Type] :module The name of the trait type.
|
38
|
+
# @option data [<(::String, <Type>, Type)>] :expectations
|
39
|
+
# The expectations that the trait requires.
|
40
|
+
def initialize(data)
|
41
|
+
@module = data.fetch(:module)
|
42
|
+
@generics = @module.generics
|
43
|
+
@intern = @module.intern
|
44
|
+
@name = @module.to_s
|
45
|
+
|
46
|
+
derive_expectations(data.fetch(:expectations))
|
47
|
+
derive_dependencies
|
48
|
+
deep_freeze!
|
49
|
+
end
|
50
|
+
|
51
|
+
# (see Base#call)
|
52
|
+
def call(build, generics)
|
53
|
+
super # TODO: fixme.
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def derive_expectations(expectations)
|
59
|
+
expects = expectations.map { |e| Expectation.new(*e) }
|
60
|
+
@expectations = Set.new(expects)
|
61
|
+
end
|
62
|
+
|
63
|
+
def derive_dependencies
|
64
|
+
@expectations.each do |expect|
|
65
|
+
@dependencies.merge(expect.parameters.map(&:to_request))
|
66
|
+
@dependencies << expect.return.to_request
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Carbon
|
5
|
+
module Concrete
|
6
|
+
module Item
|
7
|
+
class Trait
|
8
|
+
# An expectation of a trait. This is a function that an implementing
|
9
|
+
# data type must implement to be considered a part of the trait.
|
10
|
+
#
|
11
|
+
# @api private
|
12
|
+
# @note
|
13
|
+
# **This class is frozen upon initialization.** This means that any
|
14
|
+
# attempt to modify it will result in an error. In most cases, the
|
15
|
+
# attributes on this class will also be frozen, as well.
|
16
|
+
class Expectation
|
17
|
+
# The name of the function for this expectation. This is a string,
|
18
|
+
# and can be any valid function name for a carbon function.
|
19
|
+
#
|
20
|
+
# @return [::String] The function name.
|
21
|
+
attr_reader :name
|
22
|
+
|
23
|
+
# The parameters of the function for this expectation. This is an
|
24
|
+
# array of types, which can contain generic parameters.
|
25
|
+
#
|
26
|
+
# @return [<Type>] The parameter types.
|
27
|
+
attr_reader :parameters
|
28
|
+
|
29
|
+
# The return type of the function for this expectation. This is
|
30
|
+
# a single type, which can contain generic parameters.
|
31
|
+
#
|
32
|
+
# @return [Type] The return type.
|
33
|
+
attr_reader :return
|
34
|
+
|
35
|
+
# Initialize the expectation with the given arguments.
|
36
|
+
#
|
37
|
+
# @see #name
|
38
|
+
# @see #parameters
|
39
|
+
# @see #return
|
40
|
+
# @param name [::String] The name of the function for the expectation.
|
41
|
+
# @param parameters [<Type>] The parameters of the function for
|
42
|
+
# the expectation.
|
43
|
+
# @param ret [Type] The return type of the function for the
|
44
|
+
# expectation.
|
45
|
+
def initialize(name, parameters, ret)
|
46
|
+
@name = name
|
47
|
+
@parameters = parameters
|
48
|
+
@return = ret
|
49
|
+
deep_freeze!
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "forwardable"
|
5
|
+
|
6
|
+
module Carbon
|
7
|
+
module Concrete
|
8
|
+
# A "request." This is used to note the generics that a given module
|
9
|
+
# should be compiled with. This is used for items to note the dependencies
|
10
|
+
# that an item has; otherwise, it is used in the index for build
|
11
|
+
# information.
|
12
|
+
#
|
13
|
+
# @note
|
14
|
+
# **This class is frozen upon initialization.** This means that any
|
15
|
+
# attempt to modify it will result in an error. In most cases, the
|
16
|
+
# attributes on this class will also be frozen, as well.
|
17
|
+
class Request
|
18
|
+
extend Forwardable
|
19
|
+
|
20
|
+
# The interned name of a module. This is used for module lookup. This
|
21
|
+
# contains no generic information. For generic functions, all generics
|
22
|
+
# are pushed onto the defining module.
|
23
|
+
#
|
24
|
+
# @api public
|
25
|
+
# @example
|
26
|
+
# request.intern # => "Carbon::Pointer"
|
27
|
+
# @note See {Item::Base#intern} For more information about interned
|
28
|
+
# names.
|
29
|
+
# @return [::String]
|
30
|
+
attr_reader :intern
|
31
|
+
|
32
|
+
# The generics of the request. Even if the request has no definable
|
33
|
+
# generics, these are still kept in place for both name information and
|
34
|
+
# for placement information (e.g. identity and size).
|
35
|
+
#
|
36
|
+
# @api public
|
37
|
+
# @example
|
38
|
+
# request.generics # => [#<Carbon::Concrete::Type::Generic T>]
|
39
|
+
# @return [<Type::Generic>]
|
40
|
+
attr_reader :generics
|
41
|
+
|
42
|
+
# Initialize the request with the given interned name and generics,
|
43
|
+
# and then freezes the request.
|
44
|
+
#
|
45
|
+
# @api public
|
46
|
+
# @see #intern
|
47
|
+
# @see #generics
|
48
|
+
# @param intern [::String] The interned name.
|
49
|
+
# @param generics [<Type::Generic>] The generics.
|
50
|
+
def initialize(intern, generics)
|
51
|
+
@intern = intern
|
52
|
+
@generics = generics
|
53
|
+
deep_freeze!
|
54
|
+
end
|
55
|
+
|
56
|
+
# Replaces this request or this request's generics with the corresponding
|
57
|
+
# correct module. This is designed to resolve generic names; for
|
58
|
+
# example, it resolves `Carbon::Pointer<T>` to
|
59
|
+
# `Carbon::Pointer<Carbon::String>` with the right argument. It checks
|
60
|
+
# for three seperate cases.
|
61
|
+
#
|
62
|
+
# 1. The request has no generics, and the request's {#intern} has a
|
63
|
+
# mapping in the argument. In this case, it creates a new request
|
64
|
+
# object with the new module's name and no generics (because the
|
65
|
+
# mapping could not have added any worthwhile generics).
|
66
|
+
# 2. The request has no generics, and the request's {#intern} has no
|
67
|
+
# mapping in the argument. In this case, it returns itself.
|
68
|
+
# 3. The request has generics. In this case, the generics are mapped
|
69
|
+
# using {Type::Generic#sub}, and a new request is created with the
|
70
|
+
# mapped generics.
|
71
|
+
#
|
72
|
+
# @api public
|
73
|
+
# @example
|
74
|
+
# string # => #<Carbon::Concrete::Type::Generic Carbon::String>
|
75
|
+
# request.intern # => "Carbon::Pointer"
|
76
|
+
# request.generics # => [#<Carbon::Concrete::Type::Generic T>]
|
77
|
+
# mapped = request.sub("T" => string)
|
78
|
+
# mapped.intern # => "Carbon::Pointer"
|
79
|
+
# request.generics.first.equal?(string) # => true
|
80
|
+
# @param mapping [{::String => Type::Generic}] The mapping.
|
81
|
+
# @return [Request] The new request, if the request has no generics,
|
82
|
+
# and the request's {#intern} is not a key in the mapping, or if
|
83
|
+
# the request has generics.
|
84
|
+
# @return [self] If the request has no generics and it is not a key
|
85
|
+
# in the mapping.
|
86
|
+
def sub(mapping)
|
87
|
+
case [@generics.none?, mapping.key?(@intern)]
|
88
|
+
when [true, true]
|
89
|
+
Request.new(mapping[@intern].name.intern, [])
|
90
|
+
when [true, false]
|
91
|
+
self
|
92
|
+
else
|
93
|
+
generics = @generics.map { |generic| generic.sub(mapping) }
|
94
|
+
Request.new(intern, generics)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# Compares this request to another. If this request _is_ the other
|
99
|
+
# request, it returns true; otherwise, if the other is a request, and
|
100
|
+
# the other request's {#intern} is equal to this request's, it
|
101
|
+
# returns true; otherwise, it returns false.
|
102
|
+
#
|
103
|
+
# @api public
|
104
|
+
# @param other [Request, ::String, ::Object] The object to compare.
|
105
|
+
# @return [::Boolean]
|
106
|
+
def ==(other)
|
107
|
+
equal?(other) ||
|
108
|
+
(other.is_a?(Request) && other.intern == intern &&
|
109
|
+
other.generics == generics)
|
110
|
+
end
|
111
|
+
|
112
|
+
alias_method :eql?, :==
|
113
|
+
|
114
|
+
# Creates a hash of the request. This is used mostly in the Hash
|
115
|
+
# class.
|
116
|
+
#
|
117
|
+
# @api private
|
118
|
+
# @return [Numeric]
|
119
|
+
def hash
|
120
|
+
@intern.hash
|
121
|
+
end
|
122
|
+
|
123
|
+
# Returns a string representation of this request. This includes all
|
124
|
+
# generics that are associated with the request, if applicable.
|
125
|
+
#
|
126
|
+
# @api public
|
127
|
+
# @return [::String]
|
128
|
+
def to_s
|
129
|
+
if @generics.any?
|
130
|
+
"#{@intern}<#{@generics.map(&:to_s).join(', ')}>".freeze
|
131
|
+
else
|
132
|
+
@intern
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
@@ -0,0 +1,260 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "set"
|
5
|
+
require "carbon/concrete/type/function"
|
6
|
+
require "carbon/concrete/type/generic"
|
7
|
+
require "carbon/concrete/type/name"
|
8
|
+
require "carbon/concrete/type/part"
|
9
|
+
require "carbon/concrete/type/parse"
|
10
|
+
|
11
|
+
module Carbon
|
12
|
+
module Concrete
|
13
|
+
# A type. This is, basically, any possible name that could resolve
|
14
|
+
# into an actual type. Modules or functions are included in the
|
15
|
+
# typing. The Type class includes a parsing module, allowing types
|
16
|
+
# to be stored as a string and then re-serialized as a Type.
|
17
|
+
#
|
18
|
+
# @note
|
19
|
+
# **This class is frozen upon initialization.** This means that any
|
20
|
+
# attempt to modify it will result in an error. In most cases, the
|
21
|
+
# attributes on this class will also be frozen, as well.
|
22
|
+
# @todo
|
23
|
+
# TODO: Add function generics.
|
24
|
+
class Type
|
25
|
+
# A cache of types. This maps unparsed strings to their parsed
|
26
|
+
# derivatives. The cache is guarenteed to be thread-safe.
|
27
|
+
#
|
28
|
+
# @api private
|
29
|
+
# @return [{::String => Type}]
|
30
|
+
def self.cache
|
31
|
+
@cache ||= Concurrent::Map.new
|
32
|
+
end
|
33
|
+
|
34
|
+
# Returns the corresponding type for the given string value. If
|
35
|
+
# a type is not cached in {.cache}, then it computes it using
|
36
|
+
# {Parse}. The cache is locked during the computation, such that
|
37
|
+
# it won't be modified while the value is being parsed.
|
38
|
+
#
|
39
|
+
# @api public
|
40
|
+
# @example
|
41
|
+
# type = Carbon::Type("Carbon::Pointer")
|
42
|
+
# type.to_s # => "Carbon::Pointer"
|
43
|
+
# type.function? # => false
|
44
|
+
# second = Carbon::Type("Carbon::Pointer")
|
45
|
+
# type.equal?(second) # => true
|
46
|
+
# @param string [::String] The type to parse.
|
47
|
+
# @return [Type]
|
48
|
+
def self.from(string)
|
49
|
+
return string if string.is_a?(Type)
|
50
|
+
cache.compute_if_absent(string) { new(Parse.new(string).value) }
|
51
|
+
end
|
52
|
+
|
53
|
+
# The name of the type. This is from the parsed result. This
|
54
|
+
# contains the part and function information.
|
55
|
+
#
|
56
|
+
# @api private
|
57
|
+
# @return [Type::Name]
|
58
|
+
attr_reader :name
|
59
|
+
|
60
|
+
# The generic information for the type. This is derived directly
|
61
|
+
# from the last part in the name and the function name (if it
|
62
|
+
# exists).
|
63
|
+
#
|
64
|
+
# @api public
|
65
|
+
# @example
|
66
|
+
# type = Carbon::Type("Result<T, E>")
|
67
|
+
# type.generics
|
68
|
+
# # => [#<Carbon::Concrete::Type::Generic T>,
|
69
|
+
# # #<Carbon::Concrete::Type::Generic E>]
|
70
|
+
# @return [<Type::Generic>]
|
71
|
+
attr_reader :generics
|
72
|
+
|
73
|
+
# Initialize the type with the given name. After initialization, this
|
74
|
+
# freezes the type, preventing modification.
|
75
|
+
#
|
76
|
+
# @api public
|
77
|
+
# @param name [Type::Name] The name.
|
78
|
+
def initialize(name)
|
79
|
+
@name = name
|
80
|
+
@generics = name.last.generics
|
81
|
+
deep_freeze!
|
82
|
+
end
|
83
|
+
|
84
|
+
# Returns whether or not this type is a function type. It does this by
|
85
|
+
# checking to see if the {Type::Name#function} attribute on the {#name}
|
86
|
+
# is not nil.
|
87
|
+
#
|
88
|
+
# @api public
|
89
|
+
# @example Not a function.
|
90
|
+
# type.to_s # => "Carbon::Pointer<T>"
|
91
|
+
# type.function? # => false
|
92
|
+
# @example A function.
|
93
|
+
# type.to_s
|
94
|
+
# # => "Carbon::Pointer<T>.add(Carbon::Pointer<T>, Carbon::Int32)"
|
95
|
+
# type.function? # => true
|
96
|
+
# @return [::Boolean] True if the type is a function, false otherwise.
|
97
|
+
def function?
|
98
|
+
!@name.function.nil?
|
99
|
+
end
|
100
|
+
|
101
|
+
# Compares this type to another type. If the other type _is_ this type,
|
102
|
+
# it returns true; otherwise, if the other value is a {Type} and the
|
103
|
+
# other type's {#to_s} is equal to this one's, it returns true;
|
104
|
+
# otherwise, it returns false.
|
105
|
+
#
|
106
|
+
# @api public
|
107
|
+
# @example Compare with self.
|
108
|
+
# second = type
|
109
|
+
# type.equal?(second) # => true
|
110
|
+
# type == second # => true
|
111
|
+
# @example Compare with a type.
|
112
|
+
# type.equal?(second) # => false
|
113
|
+
# type.to_s # => "Carbon::Pointer<T>"
|
114
|
+
# second.to_s # => "Carbon::Pointer<T>"
|
115
|
+
# type.to_s == second.to_s # => true
|
116
|
+
# type == second # => true
|
117
|
+
# @param other [Type, ::String, ::Object] The other object to compare.
|
118
|
+
# @return [::Boolean] True if the other object is similar to this type;
|
119
|
+
# false otherwise.
|
120
|
+
def ==(other)
|
121
|
+
equal?(other) || (other.is_a?(Type) && other.to_s == to_s)
|
122
|
+
end
|
123
|
+
|
124
|
+
alias_method :eql?, :==
|
125
|
+
|
126
|
+
# Creates a hash of the request. This is used mostly in the Hash class.
|
127
|
+
#
|
128
|
+
# @api private
|
129
|
+
# @return [::Numeric] The hash.
|
130
|
+
def hash
|
131
|
+
to_s.hash
|
132
|
+
end
|
133
|
+
|
134
|
+
# The interned name of a module. This is used for module lookup. This
|
135
|
+
# contains no generic information. For generic functions, all generics
|
136
|
+
# are pushed onto the defining module.
|
137
|
+
#
|
138
|
+
# @api public
|
139
|
+
# @example
|
140
|
+
# type.intern # => "Carbon::Pointer"
|
141
|
+
# @note See {Item::Base#intern} For more information about interned
|
142
|
+
# names.
|
143
|
+
# @see Type::Name#intern
|
144
|
+
# @return [::String] The interned name of the type.
|
145
|
+
def intern
|
146
|
+
@name.intern
|
147
|
+
end
|
148
|
+
|
149
|
+
# Creates a new type using this type as a base. The new type is a
|
150
|
+
# function type; this provides information for the function type.
|
151
|
+
#
|
152
|
+
# @api semipublic
|
153
|
+
# @example
|
154
|
+
# bool = Carbon::Boolean
|
155
|
+
# func = bool.call("<=>", [bool, bool])
|
156
|
+
# func.to_s # => "Carbon::Boolean.<=>(Carbon::Boolean, Carbon::Boolean)"
|
157
|
+
# @param name [::String] The name of the function that is being defined.
|
158
|
+
# @param parameters [<Type>] The parameters that the function is
|
159
|
+
# called with.
|
160
|
+
# @return [Type] The new type.
|
161
|
+
def call(name, parameters)
|
162
|
+
func = Type::Function.new(name, parameters)
|
163
|
+
name = Name.new(@name.parts, func)
|
164
|
+
Type.new(name)
|
165
|
+
end
|
166
|
+
|
167
|
+
# Replaces all of the generics in the {Type} with the mapped ones. This
|
168
|
+
# is used when generics are fully resolved.
|
169
|
+
#
|
170
|
+
# @note
|
171
|
+
# This also replaces the type itself if the type matches any of the
|
172
|
+
# keys in the generic mapping.
|
173
|
+
# @api semipublic
|
174
|
+
# @example Normal replacement.
|
175
|
+
# type # => #<Carbon::Concrete::Type Carbon::Pointer<T>>
|
176
|
+
# mapping # => {"T" => #<Carbon::Concrete::Type Carbon::Int32>}
|
177
|
+
# subbed = type.sub(mapping)
|
178
|
+
# subbed # => #<Carbon::Concrete::Type Carbon::Pointer<Carbon::Int32>>
|
179
|
+
# @example Special replacement.
|
180
|
+
# type # => #<Carbon::Concrete::Type T>
|
181
|
+
# mapping # => {"T" => #<Carbon::Concrete::Type Carbon::Int32>}
|
182
|
+
# subbed = type.sub(mapping)
|
183
|
+
# subbed # => #<Carbon::Concrete::Type Carbon::Int32>
|
184
|
+
# @param generics [{::String => Carbon::Concrete::Type}] The generics to
|
185
|
+
# replace.
|
186
|
+
# @return [Concrete::Type] The new type.
|
187
|
+
def sub(generics)
|
188
|
+
return generics[key] if generics.key?(intern)
|
189
|
+
return self if generics.none?
|
190
|
+
replace_generics(generics)
|
191
|
+
end
|
192
|
+
|
193
|
+
# Creates a string representation of the type for comparison or storage.
|
194
|
+
# The string representation has a constraint that it must be re-parsable
|
195
|
+
# by the {Type::Parse} class.
|
196
|
+
#
|
197
|
+
# @api public
|
198
|
+
# @example String representation.
|
199
|
+
# type = Carbon::Type("Carbon::Pointer<T>")
|
200
|
+
# type.to_s # => "Carbon::Pointer<T>"
|
201
|
+
# @example Re-parsing string.
|
202
|
+
# form = "Carbon::Pointer<T: Carbon::Sized + Carbon::Numeric>" \
|
203
|
+
# ".add(Carbon::Pointer<T: Carbon::Sized + Carbon::Numeric>, " \
|
204
|
+
# "Carbon::Int32)"
|
205
|
+
# type = Carbon::Type(form)
|
206
|
+
# type.to_s == form # => true
|
207
|
+
# second = Carbon::Type`(type.to_s)
|
208
|
+
# type == second # => true
|
209
|
+
# @return [::String] The string representation of the type.
|
210
|
+
def to_s
|
211
|
+
@name.to_s
|
212
|
+
end
|
213
|
+
|
214
|
+
# Creates a request based on this type.
|
215
|
+
#
|
216
|
+
# @api semipublic
|
217
|
+
# @example
|
218
|
+
# type = Carbon::Type("Carbon::Pointer<T>")
|
219
|
+
# req = type.to_request
|
220
|
+
# req.intern # => "Carbon::Pointer"
|
221
|
+
# req.generics # => [#<Carbon::Concrete::Type::Generic T>]
|
222
|
+
# @return [Request]
|
223
|
+
def to_request
|
224
|
+
Request.new(intern, generics)
|
225
|
+
end
|
226
|
+
|
227
|
+
# Removes all function information from the type. This is the complete
|
228
|
+
# opposite of {#call}. This just leaves the module that the function
|
229
|
+
# was defined on.
|
230
|
+
#
|
231
|
+
# @api semipublic
|
232
|
+
# @example
|
233
|
+
# func = Carbon::Boolean.call("test")
|
234
|
+
# func.to_s # => "Carbon::Boolean.test()"
|
235
|
+
# func.to_module.to_s # => "Carbon::Boolean"
|
236
|
+
# @return [Type]
|
237
|
+
def to_module
|
238
|
+
name = Name.new(@name.parts, nil)
|
239
|
+
Type.new(name)
|
240
|
+
end
|
241
|
+
|
242
|
+
# Pretty inspect.
|
243
|
+
#
|
244
|
+
# @api private
|
245
|
+
# @return [::String] An inspection string.
|
246
|
+
def inspect
|
247
|
+
"#<Carbon::Concrete::Type #{self}>".freeze
|
248
|
+
end
|
249
|
+
|
250
|
+
private
|
251
|
+
|
252
|
+
def replace_generics(generics)
|
253
|
+
part = Part.new(@name.parts.last.value,
|
254
|
+
@generics.map { |g| g.sub(generics) })
|
255
|
+
name = Name.new([*@name.parts[0..-2], part], @name.function)
|
256
|
+
Type.new(name)
|
257
|
+
end
|
258
|
+
end
|
259
|
+
end
|
260
|
+
end
|