class YARD::Tags::TypesExplainer::Parser

@private

Constants

TOKENS

Public Class Methods

new(string) click to toggle source
# File lib/yard/tags/types_explainer.rb, line 173
def initialize(string)
  @scanner = StringScanner.new(string)
end
parse(string) click to toggle source
# File lib/yard/tags/types_explainer.rb, line 169
def self.parse(string)
  new(string).parse
end

Public Instance Methods

parse(until_tokens: [:parse_end]) click to toggle source

@return [Array(Boolean, Array<Type>)] - finished, types

# File lib/yard/tags/types_explainer.rb, line 178
def parse(until_tokens: [:parse_end])
  current_parsed_types = []
  type = nil
  name = nil
  finished = false
  parse_with_handlers do |token_type, token|
    case token_type
    when *until_tokens
      raise SyntaxError, "expecting name, got '#{token}'" if name.nil?
      type = create_type(name) unless type
      current_parsed_types << type
      finished = true
    when :type_name
      raise SyntaxError, "expecting END, got name '#{token}'" if name
      name = token
    when :type_next
      raise SyntaxError, "expecting name, got '#{token}' at #{@scanner.pos}" if name.nil?
      type = create_type(name) unless type
      current_parsed_types << type
      name = nil
      type = nil
    when :fixed_collection_start, :collection_start
      name ||= "Array"
      klass = token_type == :collection_start ? CollectionType : FixedCollectionType
      type = klass.new(name, parse(until_tokens: [:fixed_collection_end, :collection_end, :parse_end]))
    when :hash_collection_start
      name ||= "Hash"
      type = parse_hash_collection(name)
    end

    [finished, current_parsed_types]
  end
end

Private Instance Methods

create_type(name) click to toggle source
# File lib/yard/tags/types_explainer.rb, line 264
def create_type(name)
  if name[0, 1] == ":" || (name[0, 1] =~ /['"]/ && name[-1, 1] =~ /['"]/)
    LiteralType.new(name)
  elsif name[0, 1] == "#"
    DuckType.new(name)
  else
    Type.new(name)
  end
end
parse_hash_collection(name) click to toggle source
# File lib/yard/tags/types_explainer.rb, line 233
def parse_hash_collection(name)
  key_value_pairs = []
  current_keys = []
  finished = false

  parse_with_handlers do |token_type, token|
    case token_type
    when :type_name
      current_keys << create_type(token)
    when :type_next
      # Comma - continue collecting keys unless we just processed a value
      # In that case, start a new key group
    when :hash_collection_value
      # => - current keys map to the next value(s)
      raise SyntaxError, "no keys before =>" if current_keys.empty?
      values = parse(until_tokens: [:hash_collection_value_end, :parse_end])
      key_value_pairs << [current_keys, values]
      current_keys = []
    when :hash_collection_end, :parse_end
      # End of hash
      finished = true
    when :whitespace
      # Ignore whitespace
    end

    [finished, HashCollectionType.new(name, key_value_pairs)]
  end
end
parse_with_handlers() { |token_type, token| ... } click to toggle source

@return [Array<Type>]

# File lib/yard/tags/types_explainer.rb, line 215
def parse_with_handlers
  loop do
    found = false
    TOKENS.each do |token_type, match|
      # TODO: cleanup this code.
      # rubocop:disable Lint/AssignmentInCondition
      next unless (match.nil? && @scanner.eos?) || (match && token = @scanner.scan(match))
      found = true
      # @type [Array<Type>]
      finished, types = yield(token_type, token)
      return types if finished
      break
    end
    raise SyntaxError, "invalid character at #{@scanner.peek(1)}" unless found
  end
  nil
end