Class: Ferret::Scanner

Inherits:
Object
  • Object
show all
Defined in:
lib/sql-ferret.rb

Instance Method Summary collapse

Constructor Details

#initialize(expr) ⇒ Scanner

Returns a new instance of Scanner.



772
773
774
775
776
777
778
779
780
781
782
783
# 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

Instance Method Details

#expected!(expectation, **extra) ⇒ Object



844
845
846
847
848
849
850
851
852
853
854
# 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!Object



916
917
918
919
# File 'lib/sql-ferret.rb', line 916

def expected_eof!
  expected! '*eof*' unless next_token_offset >= @expr.length
  return
end

#get_id(expectation) ⇒ Object



887
888
889
# File 'lib/sql-ferret.rb', line 887

def get_id expectation
  return (get_optional_id or expected! expectation)
end

#get_optional_escaped_id(expectation) ⇒ Object



876
877
878
879
880
881
882
883
884
885
# 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_idObject



866
867
868
869
870
871
872
873
874
# 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_offsetObject



906
907
908
# File 'lib/sql-ferret.rb', line 906

def last_token_offset
  return @offset_behind
end

#next_token_offsetObject



910
911
912
913
914
# File 'lib/sql-ferret.rb', line 910

def next_token_offset
  _skip_intertoken_space \
      unless @token_ahead
  return @offset_ahead
end

#pass(etalon) ⇒ Object



901
902
903
904
# File 'lib/sql-ferret.rb', line 901

def pass etalon
  pass? etalon or expected! etalon
  return
end

#pass?(etalon) ⇒ Boolean

Returns:

  • (Boolean)


891
892
893
894
895
896
897
898
899
# 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_tokenObject



795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
# 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