class Safrano::Filter::Parser

Parser for $filter input

Attributes

cursor[R]
error[R]

Public Class Methods

new(input) click to toggle source
# File lib/odata/filter/parse.rb, line 17
def initialize(input)
  @tree = RootTree.new
  @cursor = @tree
  @input = input
  @stack = []
  @binop_stack = []
end

Public Instance Methods

build() click to toggle source
# File lib/odata/filter/parse.rb, line 70
def build
  each_typed_token(@input) do |tok, typ|
    case typ
    when :FuncTree
      with_accepted(tok, typ) { grow_at_cursor(FuncTree.new(tok)) }

    when :Delimiter
      case tok
      when '('
        with_accepted(tok, typ) do
          grow_at_cursor(IdentityFuncTree.new) unless @cursor.is_a? FuncTree
          unless @error
            openarg = ArgTree.new('(')
            @stack << openarg
            grow_at_cursor(openarg)
          end
        end

      when ')'
        break invalid_closing_delimiter_error(tok, typ) unless (@cursor = @stack.pop)

        with_accepted(tok, typ) do
          @cursor.update_state(tok, typ)
          cursor_at_parent
        end
      end

    when :Separator
      break invalid_separator_error(tok, typ) unless (@cursor = @stack.last)

      with_accepted(tok, typ) { @cursor.update_state(tok, typ) }

    when :UnopTree
      unoptr = UnopTree.new(tok)
      if (prev = @binop_stack.last)
        # handling of lower precedence binding vs the other
        # ones(le,gt,eq...)
        unless prev.precedence < unoptr.precedence
          @cursor = @binop_stack.pop
          @binop_stack << unoptr
        end
      else
        @binop_stack << unoptr
      end
      grow_at_cursor(unoptr)

    when :BinopBool
      with_accepted(tok, typ) do
        binoptr = BinopBool.new(tok)
        if (prev = @binop_stack.last)
          # handling of lower precedence binding vs the other
          # ones(le,gt,eq...)
          unless prev.precedence < binoptr.precedence
            @cursor = @binop_stack.pop
            @binop_stack << binoptr
          end
        else
          @binop_stack << binoptr
        end
        insert_before_cursor(binoptr)
      end

    when :BinopArithm
      with_accepted(tok, typ) do
        binoptr = BinopArithm.new(tok)
        if (prev = @binop_stack.last)
          # handling of lower precedence binding vs the other
          # ones(le,gt,eq...)
          unless prev.precedence < binoptr.precedence
            @cursor = @binop_stack.pop
            @binop_stack << binoptr
          end
        else
          @binop_stack << binoptr
        end
        insert_before_cursor(binoptr)
      end

    when :Literal
      with_accepted(tok, typ) do
        @cursor.update_state(tok, typ)
        grow_at_cursor(Literal.new(tok))
      end

    when :NullLiteral
      with_accepted(tok, typ) do
        @cursor.update_state(tok, typ)
        grow_at_cursor(NullLiteral.new(tok))
      end

    when :Qualit
      with_accepted(tok, typ) do
        @cursor.update_state(tok, typ)
        grow_at_cursor(Qualit.new(tok))
      end

    when :QString
      with_accepted(tok, typ) do
        @cursor.update_state(tok, typ)
        grow_at_cursor(QString.new(tok))
      end

    when :FPNumber
      with_accepted(tok, typ) do
        @cursor.update_state(tok, typ)
        grow_at_cursor(FPNumber.new(tok))
      end

    when :unmatchedQuote
      break unmatched_quote_error(tok, typ)

    when :space
      with_accepted(tok, typ) do
        @cursor.update_state(tok, typ)
      end
    else
      server_error
    end
    break(@error) if @error
  end
  (@error = @tree.check_types) unless @error
  @error ? @error : Contract.valid(@tree)
end
cursor_at_parent() click to toggle source
# File lib/odata/filter/parse.rb, line 36
def cursor_at_parent
  @cursor = @cursor.parent
end
detach_cursor() click to toggle source

detach cursor from parent and move cursor to the parent return the detached subtree

# File lib/odata/filter/parse.rb, line 42
def detach_cursor
  left = @cursor
  cursor_at_parent
  @cursor.detach(left)
end
grow_at_cursor(child) click to toggle source
# File lib/odata/filter/parse.rb, line 29
def grow_at_cursor(child)
  return server_error if @cursor.nil?

  @cursor.attach(child).tap_error { |err| return (@error = err) }
  @cursor = child
end
insert_before_cursor(node) click to toggle source
# File lib/odata/filter/parse.rb, line 48
def insert_before_cursor(node)
  left = detach_cursor
  grow_at_cursor(node)
  @cursor.attach(left).tap_error { |err| return (@error = err) }
end
invalid_closing_delimiter_error(tok, typ) click to toggle source
# File lib/odata/filter/parse.rb, line 62
def invalid_closing_delimiter_error(tok, typ)
  @error = ErrorUnmatchedClose.new(tok, typ, @cursor)
end
invalid_separator_error(tok, typ) click to toggle source
# File lib/odata/filter/parse.rb, line 54
def invalid_separator_error(tok, typ)
  @error = ErrorInvalidSeparator.new(tok, typ, @cursor)
end
server_error() click to toggle source
# File lib/odata/filter/parse.rb, line 25
def server_error
  (@error = ::Safrano::ServerError)
end
unmatched_quote_error(tok, typ) click to toggle source
# File lib/odata/filter/parse.rb, line 58
def unmatched_quote_error(tok, typ)
  @error = UnmatchedQuoteError.new(tok, typ, @cursor)
end
with_accepted(tok, typ) { || ... } click to toggle source
# File lib/odata/filter/parse.rb, line 66
def with_accepted(tok, typ)
  (err = @cursor.accept?(tok, typ)) ? (@error = err) : yield
end