class RuboCop::AST::NodePattern::LexerRex

def action

def action
  yield
end

def location

def location
  [
    (filename || "<input>"),
  ].compact.join(":")
end

def matches

def matches
  m = (1..9).map { |i| ss[i] }
  m.pop until m[-1] or m.empty?
  m
end

def next_token

def next_token
  token = nil
  until ss.eos? or token do
    token =
      case state
      when nil then
        case
        when ss.skip(/\s+/) then
          # do nothing
        when ss.skip(/:(#{SYMBOL_NAME})/o) then
          action { emit :tSYMBOL, &:to_sym }
        when ss.skip(/"(.+?)"/) then
          action { emit :tSTRING }
        when ss.skip(/[-+]?\d+\.\d+/) then
          action { emit :tNUMBER, &:to_f }
        when ss.skip(/[-+]?\d+/) then
          action { emit :tNUMBER, &:to_i }
        when ss.skip(/#{Regexp.union(
                  %w"( ) { | } [ ] < > $ ! ^ ` ... + * ? ,"
                )}/o) then
          action { emit ss.matched, &:to_sym }
        when ss.skip(/#{REGEXP}/o) then
          action { emit_regexp }
        when ss.skip(/%?(#{CONST_NAME})/o) then
          action { emit :tPARAM_CONST }
        when ss.skip(/%([a-z_]+)/) then
          action { emit :tPARAM_NAMED }
        when ss.skip(/%(\d*)/) then
          action { emit(:tPARAM_NUMBER) { |s| s.empty? ? 1 : s.to_i } } # Map `%` to `%1`
        when ss.skip(/_(#{IDENTIFIER})/o) then
          action { emit :tUNIFY }
        when ss.skip(/_/o) then
          action { emit :tWILDCARD }
        when ss.skip(/\#(#{CALL})/o) then
          action { @state = :ARG; emit :tFUNCTION_CALL, &:to_sym }
        when ss.skip(/#{IDENTIFIER}\?/o) then
          action { @state = :ARG; emit :tPREDICATE, &:to_sym }
        when ss.skip(/#{NODE_TYPE}/o) then
          action { emit :tNODE_TYPE, &:to_sym }
        when ss.skip(/\#.*/) then
          action { emit_comment }
        else
          text = ss.string[ss.pos .. -1]
          raise ScanError, "can not match (#{state.inspect}) at #{location}: '#{text}'"
        end
      when :ARG then
        case
        when ss.skip(/\(/) then
          action { @state = nil; emit :tARG_LIST }
        when ss.skip(//) then
          action { @state = nil }
        else
          text = ss.string[ss.pos .. -1]
          raise ScanError, "can not match (#{state.inspect}) at #{location}: '#{text}'"
        end
      else
        raise ScanError, "undefined state at #{location}: '#{state}'"
      end # token = case state
    next unless token # allow functions to trigger redo w/ nil
  end # while
  raise LexerError, "bad lexical result at #{location}: #{token.inspect}" unless
    token.nil? || (Array === token && token.size >= 2)
  # auto-switch state
  self.state = token.last if token && token.first == :state
  token
end # def next_token

def parse str

def parse str
  self.ss     = scanner_class.new str
  self.state  ||= nil
  do_parse
end

def parse_file path

def parse_file path
  self.filename = path
  open path do |f|
    parse f.read
  end
end

def scanner_class

def scanner_class
  StringScanner
end unless instance_methods(false).map(&:to_s).include?("scanner_class")