module NQL
  grammar Syntax

    rule expression
      boolean / primary
    end

    rule boolean
      left:primary space coordinator:coordinator space right:expression {
        def to_ransack
          group = {'g' => [{'m' => coordinator.to_ransack}]}

          [left, right].each do |side|
            if side.is_node?(:boolean)
              group['g'][0].merge! side.to_ransack
            else
              group['g'][0]['c'] ||= []
              group['g'][0]['c'] << side.to_ransack
            end
          end

          group
        end

        def is_node?(node_type)
          node_type.to_sym == :boolean
        end
      }
    end

    rule primary
      (space comparison space / '(' space expression space ')') {
        def to_ransack
          detect_node.to_ransack
        end

        def detect_node
          self.send %w(comparison expression).detect { |m| self.respond_to? m }
        end

        def is_node?(node_type)
          detect_node.is_node?(node_type)
        end
      }
    end

    rule coordinator
      ('|' / '&') {
        def to_ransack
          coordinators = {'|' => 'or', '&' => 'and'}
          coordinators[text_value]
        end
      }
    end

    rule comparison
      variable:alphanumeric space comparator:comparator space value:text {
        def to_ransack
          hash = {'a' => {'0' => {'name' => self.variable.text_value.gsub('.', '_')}}, 'p' => self.comparator.to_ransack, 'v' => {'0' => {'value' => self.value.text_value}}}
          hash = {'c' => [hash]} if !parent || !parent.parent || text_value == parent.parent.text_value
          hash
        end

        def is_node?(node_type)
          node_type.to_sym == :comparison
        end
      }
    end

    rule comparator
      ('=' / '!=' / '>' / '>=' / '<' / '<=' / '%')+ {
        def to_ransack
          comparators = {
            '=' => 'eq',
            '!=' => 'not_eq',
            '>' => 'gt',
            '>=' => 'gteq',
            '<' => 'lt',
            '<=' => 'lteq',
            '%' => 'cont'
          }
          comparators[text_value]
        end
      }
    end

    rule text
      (alphanumeric / utf8 / symbol)+
      (space (alphanumeric / utf8 / symbol)+)*
    end

    rule alphanumeric
      [a-zA-Z0-9_.]+
    end

    rule space
      ' '*
    end

    rule symbol
      [><=+-\/\\@#$%!?:]
    end

    rule utf8
      [\u00c1\u00c0\u00c9\u00c8\u00cd\u00cc\u00d3\u00d2\u00da\u00d9\u00dc\u00d1\u00c7\u00e1\u00e0\u00e9\u00e8\u00ed\u00ec\u00f3\u00f2\u00fa\u00f9\u00fc\u00f1\u00e7]
    end

  end
end