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,37 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ require "carbon/concrete/item/base"
5
+ require "carbon/concrete/item/data"
6
+ require "carbon/concrete/item/function"
7
+ require "carbon/concrete/item/internal"
8
+ require "carbon/concrete/item/struct"
9
+ require "carbon/concrete/item/trait"
10
+
11
+ module Carbon
12
+ module Concrete
13
+ # Items. These are buildable concepts that have dependencies. Each item
14
+ # includes {Item::Base} in order to respond to the item API. The main
15
+ # API for items are the following set of methods:
16
+ #
17
+ # - `#intern` (`String`) - Returns an "interned" name of the item. See
18
+ # {Base#intern}.
19
+ # - `#name` (`String`) - The full name of the item. See {Base#name}.
20
+ # - `#generics` (`<Type::Generic>`) - The generics of the item.
21
+ # This is normally something like `[T]`; these most likely have no
22
+ # correspondance to an actual type. See {Base#generics}.
23
+ # - `#dependencies` (`Set<Request>`) - A set of dependencies that
24
+ # the item has. This includes the generics that the item uses.
25
+ # See {Base#dependencies}.
26
+ # - `#==`, `#eql?` (`Boolean`) - Comparison. Normally uses the `#intern`
27
+ # name for a basis of comarison. See {Base#==}.
28
+ # - `#call` - Builds the item for compilation. This is the last stage.
29
+ # This should generate something for LLVM in some way. See {Base#call}.
30
+ # - `#corrected_dependencies` (`Enumerable`) - Corrects the depdenencies of
31
+ # the Item. This makes it so that the generics of the passed request
32
+ # are matched with the generics of the dependencies, essentially
33
+ # resolving them. See {Base#corrected_dependencies}.
34
+ module Item
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,153 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ module Carbon
5
+ module Concrete
6
+ module Item
7
+ # A "base" for other items. This just has some common methods that all
8
+ # items need to share to be compatible with the index. This module is
9
+ # the bases of the build system in the {Concrete} module.
10
+ module Base
11
+ # Returns the interned name of the item. This contains no generic
12
+ # information. Interned names are mostly used to match generic
13
+ # information laden types with the items that define them; for example,
14
+ # it is meant to be used to match the type
15
+ # `Carbon::Pointer<Carbon::String>` to the module `Carbon::Pointer<T>`.
16
+ # The common parts of both is the module name that the type uses - or,
17
+ # rather, everything but the generic information. Interned names
18
+ # discard the information that is unneeded for matching the two.
19
+ #
20
+ # This methodology has the downside that a module with the same name
21
+ # as the base of a generic module cannot exist; however, allowing such
22
+ # would ultimately be confusing.
23
+ #
24
+ # @api public
25
+ # @example For a module.
26
+ # item.name # => "Carbon::Pointer<T>"
27
+ # item.intern # => "Carbon::Pointer"
28
+ # @example For a function.
29
+ # item.name
30
+ # # => "Carbon::Pointer<T>.+(Carbon::Pointer<T>, Carbon::Int32)"
31
+ # item.intern
32
+ # # => "Carbon::Pointer.+(Carbon::Pointer, Carbon::Int32)"
33
+ # @return [::String] The interned name.
34
+ attr_reader :intern
35
+
36
+ # Returns the full name of the item. This can include generic
37
+ # information.
38
+ #
39
+ # @example
40
+ # item.name # => "Carbon::Pointer<T>"
41
+ # @return [::String]
42
+ attr_reader :name
43
+
44
+ # Returns the generic information associated with this item. This is
45
+ # used internally for generic substitution later on.
46
+ #
47
+ # @api semipublic
48
+ # @example
49
+ # item.generics # => [#<Carbon::Concrcete::Type::Generic T>]
50
+ # @return [<Type::Generic>]
51
+ attr_reader :generics
52
+
53
+ # The dependencies that this item is based on. These are requests
54
+ # because we _request_ the item from the index as a dependency.
55
+ # Requests contain the module name that it builds and the generics
56
+ # it requires.
57
+ #
58
+ # @api semipublic
59
+ # @example
60
+ # item.dependencies # => Set[#<Carbon::Concrete::Request T>]
61
+ # @return [Set<Request>]
62
+ attr_reader :dependencies
63
+
64
+ # Creates a hash from a given {Concrete::Type} that can be used to
65
+ # intialize an instance of this object. This is mostly used for
66
+ # {Index#define} and shouldn't be used anywhere else.
67
+ #
68
+ # @api private
69
+ # @param type [Concrete::Type] The type.
70
+ # @return [{::Symbol => ::Object}]
71
+ def self.from(type)
72
+ { module: type }
73
+ end
74
+
75
+ # Compares this item to another object. If the other object _is_ this
76
+ # item, then it returns true; otherwise, if the other object is an
77
+ # item, and the other object's {#intern} is equal to this object's
78
+ # {#intern}, then it returns true; otherwise, it returns false.
79
+ #
80
+ # @api public
81
+ # @example
82
+ # first.intern # => "Carbon::Pointer"
83
+ # second.intern # => "Carbon::Pointer"
84
+ # first == first # => true
85
+ # first == second # => true
86
+ # second == second # => true
87
+ # second == first # => true
88
+ # @param other [Base, ::String, ::Object] The object to compare.
89
+ # @return [::Boolean] The result of comparison.
90
+ def ==(other)
91
+ equal?(other) || (other.is_a?(Base) && intern == other.intern)
92
+ end
93
+ alias_method :eql?, :==
94
+
95
+ # Creates a hash of the item. This is used mostly in the Hash
96
+ # class.
97
+ #
98
+ # @api private
99
+ # @return [Numeric]
100
+ def hash
101
+ intern.hash
102
+ end
103
+
104
+ # rubocop:disable Lint/UnusedMethodArgument
105
+
106
+ # Performs compilation for the item. This converts the item into an
107
+ # LLVM-based value or type, to be used for compiling. If
108
+ # unimplemented, it raises a `NotImplementedError`.
109
+ #
110
+ # @api private
111
+ # @param build [Concrete::Build] The build information for the item.
112
+ # @param generics [{Concrete::Type => Concrete::Type}] The generics
113
+ # to apply for the item.
114
+ # @return [void]
115
+ # @raise [NotImplementedError] If it is not implemented.
116
+ def call(build, generics)
117
+ fail NotImplementedError, "Could not build #{self.class}"
118
+ end
119
+
120
+ # Modifies the dependencies of this item so that they conform to the
121
+ # given request. This should resolve all of our dependencies so that
122
+ # they no longer hold any sort of generic class.
123
+ #
124
+ # @api private
125
+ # @param request [Request] The request.
126
+ # @yield [dep] The corrected dependencies.
127
+ # @yieldparam dep [Request] The corrected dependency.
128
+ # @return [::Enumerable] An enumerator of the corrected dependencies,
129
+ # if no block was given.
130
+ # @return [void] If a block was given.
131
+ def corrected_dependencies(request, &block)
132
+ return to_enum(:corrected_dependencies, request) unless block_given?
133
+ return dependencies.each(&block) if generics.empty?
134
+
135
+ forced_corrected_dependencies(request, &block)
136
+ end
137
+
138
+ private
139
+
140
+ def forced_corrected_dependencies(request, &block)
141
+ # Array<Type::Generic> -> Array<(Type::Generic, Numeric)> ->
142
+ # Array<(String, Type::Generic)> -> {String => Type::Generic}
143
+ mapping = generics
144
+ .each_with_index
145
+ .map { |gen, i| [gen.name.intern, request.generics[i]] }
146
+ .to_h
147
+
148
+ dependencies.map { |dep| dep.sub(mapping) }.each(&block)
149
+ end
150
+ end
151
+ end
152
+ end
153
+ end
@@ -0,0 +1,22 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ module Carbon
5
+ module Concrete
6
+ module Item
7
+ # A data definition. All data definitions include this module, which
8
+ # acts as a sort of hirearchy. It makes it easy to identify if an item
9
+ # is a data definition or a function definition.
10
+ module Data
11
+ include Base
12
+
13
+ # The traits that the data type implements. This is mostly used for
14
+ # validation and logic.
15
+ #
16
+ # @api public
17
+ # @return [<Type>]
18
+ attr_reader :implements
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,97 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ module Carbon
5
+ module Concrete
6
+ module Item
7
+ # A function definition. This contains all of the information needed to
8
+ # build a proper LLVM function. This is stored within an index and
9
+ # serialized as needed, in order to defer compilation. There are two
10
+ # main types of functions: "normal," or "extern." "Normal" functions
11
+ # have an actual definition (i.e. {Tacky::Function}), and are written
12
+ # in Ruby/Carbon. "Extern" functions do not have a definition; they
13
+ # map a Carbon function to a C/low-level function. Instead of a
14
+ # definition, they have a function name, that maps to the C/low-level
15
+ # function. This is normally specified with an `:extern` directive.
16
+ #
17
+ # @api private
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
+ class Function
23
+ include Base
24
+
25
+ # (see Item::Base.from)
26
+ def self.from(type)
27
+ {
28
+ module: type.to_module,
29
+ internal: type.name.function.name,
30
+ arguments: type.name.function.parameters,
31
+ generics: type.generics,
32
+ definition: Tacky::Function.new(type.name.function.parameters)
33
+ }
34
+ end
35
+
36
+ def initialize(data)
37
+ @module = data.fetch(:module)
38
+ @internal = data.fetch(:internal)
39
+ @parameters = data.fetch(:arguments) { data.fetch(:parameters) }
40
+ @definition = data.fetch(:definition)
41
+ @generics = data.fetch(:generics) { @module.generics }
42
+ @return = data.fetch(:return)
43
+
44
+ derive_name
45
+ derive_dependencies
46
+ deep_freeze!
47
+ end
48
+
49
+ # (see Base#call)
50
+ def call(build, generics)
51
+ value = case @definition
52
+ when Tacky::Function
53
+ build_function_intern(build, generics)
54
+ when ::String, ::Symbol
55
+ build_function_extern(build, generics)
56
+ else fail ArgumentError,
57
+ "Unknown definition #{@definition.class}"
58
+ end
59
+
60
+ build.functions[@module.sub(generics)] = value
61
+ end
62
+
63
+ private
64
+
65
+ # rubocop:disable Metrics/AbcSize
66
+ def build_function_intern(build, generics)
67
+ full = @full.sub(generics)
68
+ params = @parameters
69
+ .map { |p| build.types.fetch(p.sub(generics)).last }
70
+ ret = build.types.fetch(@return.sub(generics)).last
71
+ func = build.module.functions.add(full, params, ret)
72
+ @definition.call(func, build, generics)
73
+ build.functions[full] = func
74
+ end
75
+ # rubocop:enable Metrics/AbcSize
76
+
77
+ # @todo TODO: finish.
78
+ def build_function_extern(build, generics)
79
+ end
80
+
81
+ def derive_name
82
+ @full = @module.call(@internal, @parameters)
83
+ @intern = @full.intern
84
+ @name = @full.to_s
85
+ end
86
+
87
+ def derive_dependencies
88
+ @dependencies = Set.new
89
+ @dependencies << @return.to_request
90
+ @dependencies.merge(@parameters.map(&:to_request))
91
+ @dependencies.merge(@definition.dependencies.map(&:to_request)) if \
92
+ @definition.is_a?(Tacky::Function)
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,83 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ module Carbon
5
+ module Concrete
6
+ module Item
7
+ # An internal data type. In most cases, this is just integers and
8
+ # pointers that can't be easily serialized because of links to LLVM and
9
+ # FFI.
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 Internal
17
+ include Data
18
+
19
+ # Retreives the LLVM type information for the given integer size.
20
+ # This cannot be serialized by marshal or any other serialization
21
+ # library.
22
+ #
23
+ # @api private
24
+ # @return [Proc<Numeric, LLVM::Type>]
25
+ TYPE = proc { |size| LLVM.const_get("Int#{size}").type }
26
+
27
+ # (see Item::Base.from)
28
+ def self.from(type)
29
+ { module: type, implements: [] }
30
+ end
31
+
32
+ # Initialize the internal data type. Internal data types may not have
33
+ # generic information, and have no dependencies, but can still
34
+ # implement traits.
35
+ #
36
+ # @param data [::Hash] The options for the internal data type.
37
+ # @option data [Type] :module The module of the internal data type.
38
+ # @option data [::String, ::Symbol] :kind The kind of the internal data
39
+ # type. Valid values are `:integer`, `:pointer`, `:int_pointer`,
40
+ # `:ary_pointer`, or the string version of any of those. This
41
+ # controls the underlying LLVM type of the internal data type.
42
+ # @option data [::String, ::Numeric, #to_i] :size The size of the
43
+ # internal data type. For integers, it is the number of bits in the
44
+ # integer; for pointers, it is the number of bits of the element it
45
+ # points to.
46
+ # @option data [<Type>] :implements ([]) The types that the
47
+ # internal data type implements.
48
+ def initialize(data)
49
+ @module = data.fetch(:module)
50
+ @kind = data.fetch(:kind) { data.fetch(:type) }.to_s
51
+ @size = data.fetch(:size, 8)
52
+
53
+ @generics = @module.generics
54
+ @implements = Set.new(data.fetch(:implements, []))
55
+ @dependencies = Set.new
56
+
57
+ derive_name
58
+ deep_freeze!
59
+ end
60
+
61
+ # (see Base#call)
62
+ def call(build, generics)
63
+ value = case @kind.to_s
64
+ when "integer" then TYPE.call(@size)
65
+ when "pointer"
66
+ type = build.types.fetch(generics.fetch("T"))
67
+ type.last.pointer
68
+ else fail ArgumentError, "Unknown kind #{@kind}"
69
+ end
70
+
71
+ build.types[@module.sub(generics)] = [self, value]
72
+ end
73
+
74
+ private
75
+
76
+ def derive_name
77
+ @intern = @module.intern
78
+ @name = @module.to_s
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,65 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ require "carbon/concrete/item/struct/element"
5
+
6
+ module Carbon
7
+ module Concrete
8
+ module Item
9
+ # A struct data type. This is normally a sequence of elements that are
10
+ # stored sequentially in memory. Each element has a name, to reference
11
+ # which position, and a type.
12
+ #
13
+ # @api private
14
+ # @note
15
+ # **This class is frozen upon initialization.** This means that any
16
+ # attempt to modify it will result in an error. In most cases, the
17
+ # attributes on this class will also be frozen, as well.
18
+ class Struct
19
+ include Data
20
+
21
+ # (see Item::Base.from)
22
+ def self.from(type)
23
+ { module: type, implements: [], elements: [] }
24
+ end
25
+
26
+ # Initialize the struct with the given data.
27
+ #
28
+ # @param data [::Hash] The data to initialize with.
29
+ # @option data [Type] :module The name of the struct.
30
+ # @option data [<::String, Type>] :elements The elements of
31
+ # the struct.
32
+ # @option data [<Type>] :implements The traits that this
33
+ # data type implements.
34
+ def initialize(data)
35
+ @module = data.fetch(:module)
36
+ @generics = @module.generics
37
+ @intern = @module.intern
38
+ @name = @module.to_s
39
+
40
+ @implements = Set.new(data.fetch(:implements))
41
+ @dependencies = Set.new
42
+
43
+ derive_elements(data.fetch(:elements))
44
+ derive_dependencies
45
+ deep_freeze!
46
+ end
47
+
48
+ # (see Base#call)
49
+ def call(build, generics)
50
+ super # TODO: fixme.
51
+ end
52
+
53
+ private
54
+
55
+ def derive_elements(elements)
56
+ @elements = elements.map { |e| Element.new(*e) }
57
+ end
58
+
59
+ def derive_dependencies
60
+ @dependencies.merge(@elements.map { |e| e.type.to_request })
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end