module Net::IMAP::ResponseParser::ParserUtils::Generator

Constants

LOOKAHEAD
SHIFT_TOKEN

Public Instance Methods

def_char_matchers(name, char, token) click to toggle source

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

# File net-imap-0.4.4/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) click to toggle source

TODO: move coersion to the token.value method?

# File net-imap-0.4.4/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