Sha256: 5b09b3525f1c1aa3087bc03e45915ef38345fdcbd3f44e9df4a4ce15b08b8e7a

Contents?: true

Size: 1.87 KB

Versions: 2

Compression:

Stored size: 1.87 KB

Contents

require 'parslet'

module ParsingNesting
  class Grammar < Parslet::Parser
    root :query

    # query is actually a list of expressions.
    rule :query do
      (spacing? >> (expression | paren_unit) >> spacing?).repeat
    end

    rule :paren_list do
      (str('(') >> query >> str(')')).as(:list)
    end

    rule :paren_unit do
      (str('(') >> spacing? >> expression >> spacing? >> str(')')) |
        paren_list
    end

    # Note well: It was tricky to parse the thing we want where you can
    # have a flat list with boolean operators, but where 'OR' takes precedence.
    # eg "A AND B OR C AND C" or "A OR B AND C OR D". Tricky to parse at all,
    # tricky to make precedence work. Important things that seem to make it work:
    # and_list comes BEFORE or_list in :expression.
    # and_list's operand can be an or_list, but NOT vice versa
    # There are others, it was an iterative process with testing.
    rule :expression do
      (and_list | or_list | unary_expression)
    end

    rule :and_list do
      ((or_list | unary_expression | paren_unit) >>
        (spacing >> str("AND") >> spacing >> (or_list | unary_expression | paren_unit)).repeat(1)).as(:and_list)
    end

    rule :or_list do
      ((unary_expression | paren_unit) >>
      (spacing >> str("OR") >> spacing >> (unary_expression | paren_unit)).repeat(1)).as(:or_list)
    end

    rule :unary_expression do
      (str('+') >> (phrase | token)).as(:mandatory) |
      (str('-') >> (phrase | token)).as(:excluded) |
      (str('NOT') >> spacing? >> (unary_expression | paren_unit)).as(:not_expression) |
      (phrase | token)
    end

    rule :token do
      match['^ ")('].repeat(1).as(:token)
    end
    rule :phrase do
      match('"') >> match['^"'].repeat(1).as(:phrase) >> match('"')
    end

    rule :spacing do
      match[' '].repeat(1)
    end
    rule :spacing? do
      spacing.maybe
    end
  end
end

Version data entries

2 entries across 2 versions & 1 rubygems

Version Path
blacklight_advanced_search-8.0.0.alpha2 lib/parsing_nesting/grammar.rb
blacklight_advanced_search-8.0.0.alpha1 lib/parsing_nesting/grammar.rb