# encoding: utf-8 # frozen_string_literal: true module Carbon module Concrete module Item # An internal data type. In most cases, this is just integers and # pointers that can't be easily serialized because of links to LLVM and # FFI. # # @api private # @note # **This class is frozen upon initialization.** This means that any # attempt to modify it will result in an error. In most cases, the # attributes on this class will also be frozen, as well. class Internal include Data # Retreives the LLVM type information for the given integer size. # This cannot be serialized by marshal or any other serialization # library. # # @api private # @return [Proc] TYPE = proc { |size| LLVM.const_get("Int#{size}").type } # (see Item::Base.from) def self.from(type) { type: type, implements: [] } end # Initialize the internal data type. Internal data types may not have # generic information, and have no dependencies, but can still # implement traits. # # @param data [::Hash] The options for the internal data type. # @option data [Type] :type The module of the internal data type. # @option data [::String, ::Symbol] :kind The kind of the internal data # type. Valid values are `:integer`, `:pointer`, `:void`, or the # string version of any of those. This controls the underlying LLVM # type of the internal data type. # @option data [::String, ::Numeric, #to_i] :size The size of the # internal data type. For integers, it is the number of bits in the # integer; for pointers, it is the number of bits of the element it # points to. # @option data [] :implements ([]) The types that the # internal data type implements. def initialize(data) @type = data.fetch(:type) @kind = data.fetch(:kind).to_s @size = data.fetch(:size, 8) @extern = data[:extern] @generics = @type.generics @implements = Set.new(data.fetch(:implements, [])) @dependencies = Set.new(@generics.map(&:name)) @name = @module.to_s deep_freeze! end # (see Base#call) def call(build, generics) full = @type.sub(generics) value = case @kind.to_s when "integer" then TYPE.call(@size) when "void" then ::LLVM::Type.void when "opaque" ::LLVM::Type.struct([], false, @extern || full.to_s) when "pointer" type = build.fetch(generics.fetch(Carbon::Type("T"))) type.last.pointer else fail ArgumentError, "Unknown kind #{@kind}" end build.items[@type.sub(generics)] = [self, value] end end end end end