class Ferret::Scanner

Public Class Methods

new(expr) click to toggle source
Calls superclass method
# File lib/sql-ferret.rb, line 772
def initialize expr
  raise 'type mismatch' unless expr.is_a? String
  super()
  @expr = expr
  @lex = Ferret::LEXICAL_RULESET

  @offset_ahead = 0
  @token_ahead = nil
  @offset_atail = nil
  @offset_behind = nil
  return
end

Public Instance Methods

expected!(expectation, **extra) click to toggle source
# File lib/sql-ferret.rb, line 844
def expected! expectation, **extra
  # We'll call [[peek_token]] in advance so that
  # [[@offset_ahead]] would point exactly at the next token.
  tok = peek_token
  ugh('ferret-parse-error',
      expected: expectation,
      got: (tok || '*eof*').to_s,
      input: @expr,
      offset: @offset_ahead,
      **extra)
end
expected_eof!() click to toggle source
# File lib/sql-ferret.rb, line 916
def expected_eof!
  expected! '*eof*' unless next_token_offset >= @expr.length
  return
end
get_id(expectation) click to toggle source
# File lib/sql-ferret.rb, line 887
def get_id expectation
  return (get_optional_id or expected! expectation)
end
get_optional_escaped_id(expectation) click to toggle source
# File lib/sql-ferret.rb, line 876
def get_optional_escaped_id expectation
  escaped_p = pass? :'\\'
  if escaped_p then
    return true, get_id(expectation)
  elsif id = get_optional_id then
    return false, id
  else
    return nil
  end
end
get_optional_id() { |tok| ... } click to toggle source
# File lib/sql-ferret.rb, line 866
def get_optional_id
  tok = peek_token
  if tok.is_a? String then
    _consume_token_ahead
    return block_given? ? yield(tok) : tok
  else
    return nil
  end
end
last_token_offset() click to toggle source
# File lib/sql-ferret.rb, line 906
def last_token_offset
  return @offset_behind
end
next_token_offset() click to toggle source
# File lib/sql-ferret.rb, line 910
def next_token_offset
  _skip_intertoken_space \
      unless @token_ahead
  return @offset_ahead
end
pass(etalon) click to toggle source
# File lib/sql-ferret.rb, line 901
def pass etalon
  pass? etalon or expected! etalon
  return
end
pass?(etalon) click to toggle source
# File lib/sql-ferret.rb, line 891
def pass? etalon
  tok = peek_token
  if tok == etalon then
    _consume_token_ahead
    return true
  else
    return false
  end
end
peek_token() click to toggle source
# File lib/sql-ferret.rb, line 795
def peek_token
  return @token_ahead if @token_ahead

  # Note that [[peek_token]] advances [[@offset_ahead]] to
  # skip over preceding intertoken space but no further.
  # Instead, it'll store the end offset of the peeked token
  # in [[@offset_atail]].
  _skip_intertoken_space

  # check for eof
  if @offset_ahead >= @expr.length then
    @offset_atail = @offset_ahead
    return @token_ahead = nil
  end

  # check for an identifier
  if @lex.id_starter? @expr[@offset_ahead] then
    @offset_atail = @offset_ahead
    loop do
      @offset_atail += 1
      break unless @lex.id_continuer? @expr[@offset_atail]
    end
    return @token_ahead =
        @expr[@offset_ahead ... @offset_atail]
  end

  # check for multi-char particles
  @lex.multichar.each do |etalon|
    if @expr[@offset_ahead, etalon.length] == etalon then
      @offset_atail = @offset_ahead + etalon.length
      return @token_ahead = etalon.to_sym
    end
  end

  # check for single-char particles
  if @lex.simple_particle? @expr[@offset_ahead] then
    @offset_atail = @offset_ahead + 1
    return @token_ahead = @expr[@offset_ahead].chr.to_sym
  end

  # give up
  ugh 'ferret-lexical-error',
      input: @expr,
      offset: @offset_ahead,
      lookahead: @expr[@offset_ahead, 10],
      lookbehind: @expr[
          [@offset_ahead - 10, 0].max ... @offset_ahead]
end

Private Instance Methods

_consume_token_ahead() click to toggle source
# File lib/sql-ferret.rb, line 856
def _consume_token_ahead
  raise 'assertion failed' unless @offset_atail
  @offset_behind = @offset_ahead
  @offset_ahead = @offset_atail
  @token_ahead = nil
  @offset_atail = nil
  return
end
_skip_intertoken_space() click to toggle source
# File lib/sql-ferret.rb, line 785
def _skip_intertoken_space
  loop do
    break if @offset_ahead >= @expr.length
    break unless @lex.intertoken? @expr[@offset_ahead]
    @offset_ahead += 1
  end
  return
end