# encoding: utf-8 # frozen_string_literal: true module Carbon module Compiler class Metanostic # A diagnostic. This is an actual diagnostic, spawned off of a metanostic # and an issue in compiling a file. This contains information about the # related metanostic, the location of the diagnostic, an associated # message, and the mode the diagnostic is considered. class Diagnostic TEMPLATESTR = File.read(File.expand_path("../template.erb", __FILE__)) .gsub(/\r\n|\r|\n/, "\n") TEMPLATE = ERB.new(TEMPLATESTR, nil, ">") include Comparable # The associated metanostic. This contains information about # information the name and the allowed modes of this diagnostic. # # @return [Metanostic] attr_reader :metanostic # The associated location. If the location is not given, it defaults # to {Location.default}. # # @return [Location] attr_reader :location # The message for the diagnostic. If none is given, it defaults to the # metanostic's message. # # @return [String] attr_reader :message # The mode for the diagnostic. This changes how the diagnostic is # treated. # # @return [Integer] attr_reader :mode # Initializes the diagnostic, and then freezes it. # # @param data [{Symbol => Object}] Origin date for the diagnostic. # @option data [Metanostic] :meta The associated metanostic. # See {#metanostic}. # @option data [Location] :location The location. See {#location}. # @option data [Integer] :mode The mode. See {#mode}. # @option data [String?] :message The message. See {#message}. # @raise [KeyError] If one of the above options was not present. def initialize(data) @metanostic = data.fetch(:meta) @location = data.fetch(:location) @mode = data.fetch(:mode) @list = data.fetch(:list) @stack = data.fetch(:stack) { caller[3..8] } @message = data[:message] || @metanostic.message to_a freeze end # Outputs this diagnostic to the given IO. If the mode is # {Mode::IGNORE}, and {Carbon.verbose} is less than `1`, then the # diagnostic is not output. # # @param io [#<<] # @return [void] def output(io) return if mode == Mode::IGNORE && Carbon.verbose < 1 io << TEMPLATE.result(binding) << "\n" end # Compares this instance with another instance. It does so by comparing # the array representations of both; therefore, this makes no sense # other than equality. # # @param other [Diagnostic] The diagnostic to compare. # @return [Numeric] def <=>(other) fail ArgumentError, "Expected Diagnostic" unless \ other.is_a?(Diagnostic) to_a <=> other.to_a end # Returns a numeric representation of this class for use of hashing. # # @return [Numeric] def hash to_a.hash end # An array representation of this class. This is frozen and cached. # # @return [(Class, Metanostic, Location, Integer, String)] def to_a @array ||= [self.class, @metanostic, @location, @mode, @message].freeze end private def distance @location.column.end - @location.column.begin end def lines (@location.line.begin - 1)..(@location.line.end - 1) end def file @list.files[@location.file] end end end end end