carbon-core 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +13 -0
  3. data/.rspec +2 -0
  4. data/.rubocop.yml +38 -0
  5. data/.travis.yml +4 -0
  6. data/.yardopts +1 -0
  7. data/CODE_OF_CONDUCT.md +49 -0
  8. data/Gemfile +11 -0
  9. data/LICENSE.txt +21 -0
  10. data/README.md +41 -0
  11. data/Rakefile +14 -0
  12. data/carbon.gemspec +30 -0
  13. data/lib/carbon.rb +54 -0
  14. data/lib/carbon/concrete.rb +43 -0
  15. data/lib/carbon/concrete/build.rb +63 -0
  16. data/lib/carbon/concrete/index.rb +324 -0
  17. data/lib/carbon/concrete/item.rb +37 -0
  18. data/lib/carbon/concrete/item/base.rb +153 -0
  19. data/lib/carbon/concrete/item/data.rb +22 -0
  20. data/lib/carbon/concrete/item/function.rb +97 -0
  21. data/lib/carbon/concrete/item/internal.rb +83 -0
  22. data/lib/carbon/concrete/item/struct.rb +65 -0
  23. data/lib/carbon/concrete/item/struct/element.rb +42 -0
  24. data/lib/carbon/concrete/item/trait.rb +72 -0
  25. data/lib/carbon/concrete/item/trait/expectation.rb +55 -0
  26. data/lib/carbon/concrete/request.rb +137 -0
  27. data/lib/carbon/concrete/type.rb +260 -0
  28. data/lib/carbon/concrete/type/function.rb +91 -0
  29. data/lib/carbon/concrete/type/generic.rb +118 -0
  30. data/lib/carbon/concrete/type/name.rb +147 -0
  31. data/lib/carbon/concrete/type/parse.rb +172 -0
  32. data/lib/carbon/concrete/type/part.rb +100 -0
  33. data/lib/carbon/core.rb +61 -0
  34. data/lib/carbon/core/int.rb +87 -0
  35. data/lib/carbon/core/integer.rb +109 -0
  36. data/lib/carbon/core/integer/cast.rb +83 -0
  37. data/lib/carbon/core/integer/math.rb +198 -0
  38. data/lib/carbon/core/integer/misc.rb +145 -0
  39. data/lib/carbon/core/integer/pole.rb +133 -0
  40. data/lib/carbon/core/integer/ship.rb +71 -0
  41. data/lib/carbon/core/integer/sign.rb +52 -0
  42. data/lib/carbon/core/integer/type.rb +42 -0
  43. data/lib/carbon/core/integer/zero.rb +52 -0
  44. data/lib/carbon/core/pointer.rb +54 -0
  45. data/lib/carbon/core/pointer/access.rb +123 -0
  46. data/lib/carbon/core/pointer/cast.rb +55 -0
  47. data/lib/carbon/core/pointer/math.rb +187 -0
  48. data/lib/carbon/core/pointer/memory.rb +85 -0
  49. data/lib/carbon/core/pointer/type.rb +23 -0
  50. data/lib/carbon/tacky.rb +21 -0
  51. data/lib/carbon/tacky/block.rb +96 -0
  52. data/lib/carbon/tacky/builder.rb +310 -0
  53. data/lib/carbon/tacky/context.rb +66 -0
  54. data/lib/carbon/tacky/function.rb +137 -0
  55. data/lib/carbon/tacky/instruction.rb +170 -0
  56. data/lib/carbon/tacky/parameter.rb +23 -0
  57. data/lib/carbon/tacky/reference.rb +23 -0
  58. data/lib/carbon/tacky/value.rb +40 -0
  59. data/lib/carbon/version.rb +9 -0
  60. metadata +186 -0
@@ -0,0 +1,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