carbon-core 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +13 -0
  3. data/.rspec +2 -0
  4. data/.rubocop.yml +38 -0
  5. data/.travis.yml +4 -0
  6. data/.yardopts +1 -0
  7. data/CODE_OF_CONDUCT.md +49 -0
  8. data/Gemfile +11 -0
  9. data/LICENSE.txt +21 -0
  10. data/README.md +41 -0
  11. data/Rakefile +14 -0
  12. data/carbon.gemspec +30 -0
  13. data/lib/carbon.rb +54 -0
  14. data/lib/carbon/concrete.rb +43 -0
  15. data/lib/carbon/concrete/build.rb +63 -0
  16. data/lib/carbon/concrete/index.rb +324 -0
  17. data/lib/carbon/concrete/item.rb +37 -0
  18. data/lib/carbon/concrete/item/base.rb +153 -0
  19. data/lib/carbon/concrete/item/data.rb +22 -0
  20. data/lib/carbon/concrete/item/function.rb +97 -0
  21. data/lib/carbon/concrete/item/internal.rb +83 -0
  22. data/lib/carbon/concrete/item/struct.rb +65 -0
  23. data/lib/carbon/concrete/item/struct/element.rb +42 -0
  24. data/lib/carbon/concrete/item/trait.rb +72 -0
  25. data/lib/carbon/concrete/item/trait/expectation.rb +55 -0
  26. data/lib/carbon/concrete/request.rb +137 -0
  27. data/lib/carbon/concrete/type.rb +260 -0
  28. data/lib/carbon/concrete/type/function.rb +91 -0
  29. data/lib/carbon/concrete/type/generic.rb +118 -0
  30. data/lib/carbon/concrete/type/name.rb +147 -0
  31. data/lib/carbon/concrete/type/parse.rb +172 -0
  32. data/lib/carbon/concrete/type/part.rb +100 -0
  33. data/lib/carbon/core.rb +61 -0
  34. data/lib/carbon/core/int.rb +87 -0
  35. data/lib/carbon/core/integer.rb +109 -0
  36. data/lib/carbon/core/integer/cast.rb +83 -0
  37. data/lib/carbon/core/integer/math.rb +198 -0
  38. data/lib/carbon/core/integer/misc.rb +145 -0
  39. data/lib/carbon/core/integer/pole.rb +133 -0
  40. data/lib/carbon/core/integer/ship.rb +71 -0
  41. data/lib/carbon/core/integer/sign.rb +52 -0
  42. data/lib/carbon/core/integer/type.rb +42 -0
  43. data/lib/carbon/core/integer/zero.rb +52 -0
  44. data/lib/carbon/core/pointer.rb +54 -0
  45. data/lib/carbon/core/pointer/access.rb +123 -0
  46. data/lib/carbon/core/pointer/cast.rb +55 -0
  47. data/lib/carbon/core/pointer/math.rb +187 -0
  48. data/lib/carbon/core/pointer/memory.rb +85 -0
  49. data/lib/carbon/core/pointer/type.rb +23 -0
  50. data/lib/carbon/tacky.rb +21 -0
  51. data/lib/carbon/tacky/block.rb +96 -0
  52. data/lib/carbon/tacky/builder.rb +310 -0
  53. data/lib/carbon/tacky/context.rb +66 -0
  54. data/lib/carbon/tacky/function.rb +137 -0
  55. data/lib/carbon/tacky/instruction.rb +170 -0
  56. data/lib/carbon/tacky/parameter.rb +23 -0
  57. data/lib/carbon/tacky/reference.rb +23 -0
  58. data/lib/carbon/tacky/value.rb +40 -0
  59. data/lib/carbon/version.rb +9 -0
  60. metadata +186 -0
@@ -0,0 +1,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