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,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