123456789_123456789_123456789_123456789_123456789_

Module: Net::IMAP::ResponseParser::ParserUtils::Generator

Do not use. This module is for internal use only.
Relationships & Source Files
Extension / Inclusion / Inheritance Descendants
Extended In:
Defined in: lib/net/imap/response_parser/parser_utils.rb

Constant Summary

Instance Method Summary

Instance Method Details

#def_char_matchers(name, char, token)

we can skip lexer for single character matches, as a shortcut

[ GitHub ]

  
# File 'lib/net/imap/response_parser/parser_utils.rb', line 17

def def_char_matchers(name, char, token)
  byte = char.ord
  match_name = name.match(/\A[A-Z]/) ? "#{name}!" : name
  char = char.dump
  class_eval <<~RUBY, __FILE__, __LINE__ + 1
    # frozen_string_literal: true

    # force use of #next_token; no string peeking
    def lookahead_#{name}?
      #{LOOKAHEAD}&.symbol == #{token}
    end

    # use token or string peek
    def peek_#{name}?
      @token ? @token.symbol == #{token} : @str.getbyte(@pos) == #{byte}
    end

    # like accept(token_symbols); returns token or nil
    def #{name}?
      if @token&.symbol == #{token}
        #{SHIFT_TOKEN}
        #{char}
      elsif !@token && @str.getbyte(@pos) == #{byte}
        @pos += 1
        #{char}
      end
    end

    # like match(token_symbols); returns token or raises parse_error
    def #{match_name}
      if @token&.symbol == #{token}
        #{SHIFT_TOKEN}
        #{char}
      elsif !@token && @str.getbyte(@pos) == #{byte}
        @pos += 1
        #{char}
      else
        parse_error("unexpected %s (expected %p)",
                    @token&.symbol || @str[@pos].inspect, #{char})
      end
    end
  RUBY
end

#def_token_matchers(name, *token_symbols, coerce: nil, send: nil)

TODO: move coersion to the token.value method?

[ GitHub ]

  
# File 'lib/net/imap/response_parser/parser_utils.rb', line 62

def def_token_matchers(name, *token_symbols, coerce: nil, send: nil)
  match_name = name.match(/\A[A-Z]/) ? "#{name}!" : name

  if token_symbols.size == 1
    token   = token_symbols.first
    matcher = "token&.symbol == %p" % [token]
    desc    = token
  else
    matcher = "%p.include? token&.symbol" % [token_symbols]
    desc    = token_symbols.join(" or ")
  end

  value = "(token.value)"
  value = coerce.to_s + value   if coerce
  value = [value, send].join(".") if send

  raise_parse_error = <<~RUBY
    parse_error("unexpected %s (expected #{desc})", token&.symbol)
  RUBY

  class_eval <<~RUBY, __FILE__, __LINE__ + 1
    # frozen_string_literal: true

    # lookahead version of match, returning the value
    def lookahead_#{name}!
      token = #{LOOKAHEAD}
      if #{matcher}
        #{value}
      else
        #{raise_parse_error}
      end
    end

    def #{name}?
      token = #{LOOKAHEAD}
      if #{matcher}
        #{SHIFT_TOKEN}
        #{value}
      end
    end

    def #{match_name}
      token = #{LOOKAHEAD}
      if #{matcher}
        #{SHIFT_TOKEN}
        #{value}
      else
        #{raise_parse_error}
      end
    end
  RUBY
end