class Fluent::FilterWhere::Parser
  prechigh
    left OR
    left AND
    right NOT
  preclow

  token EQ  /* = */
  token NEQ /* <> != */
  token GT  /* >  */ 
  token GE  /* >= */
  token LT  /* <  */
  token LE  /* <= */
  
  token START_WITH
  token END_WITH
  token INCLUDE
  token REGEXP
  token IS
  token NOT
  
  token AND
  token OR
  
  token NULL
  token BOOLEAN
  token STRING
  token NUMBER
  token IDENTIFIER

  options no_result_var
rule

  input: # empty string
   | exp { val[0] }
   ;
  
  exp: IDENTIFIER EQ BOOLEAN      { BooleanOpExp.new(val[0], val[2], :EQ) }
   | IDENTIFIER NEQ BOOLEAN       { BooleanOpExp.new(val[0], val[2], :NEQ) }
   | BOOLEAN EQ  IDENTIFIER       { BooleanOpExp.new(val[0], val[2], :EQ) }
   | BOOLEAN NEQ IDENTIFIER       { BooleanOpExp.new(val[0], val[2], :NEQ) }
   | IDENTIFIER EQ  NUMBER        { NumberOpExp.new(val[0], val[2], :EQ) }
   | IDENTIFIER NEQ NUMBER        { NumberOpExp.new(val[0], val[2], :NEQ) }
   | IDENTIFIER GT  NUMBER        { NumberOpExp.new(val[0], val[2], :GT) }
   | IDENTIFIER GE  NUMBER        { NumberOpExp.new(val[0], val[2], :GE) }
   | IDENTIFIER LT  NUMBER        { NumberOpExp.new(val[0], val[2], :LT) }
   | IDENTIFIER LE  NUMBER        { NumberOpExp.new(val[0], val[2], :LE) }
   | NUMBER EQ  IDENTIFIER        { NumberOpExp.new(val[0], val[2], :EQ) }
   | NUMBER NEQ IDENTIFIER        { NumberOpExp.new(val[0], val[2], :NEQ) }
   | NUMBER GT  IDENTIFIER        { NumberOpExp.new(val[0], val[2], :GT) }
   | NUMBER GE  IDENTIFIER        { NumberOpExp.new(val[0], val[2], :GE) }
   | NUMBER LT  IDENTIFIER        { NumberOpExp.new(val[0], val[2], :LT) }
   | NUMBER LE  IDENTIFIER        { NumberOpExp.new(val[0], val[2], :LE) }
   | IDENTIFIER EQ         STRING { StringOpExp.new(val[0], val[2], :EQ) }
   | IDENTIFIER NEQ        STRING { StringOpExp.new(val[0], val[2], :NEQ) }
   | IDENTIFIER START_WITH STRING { StringOpExp.new(val[0], val[2], :START_WITH) }
   | IDENTIFIER END_WITH   STRING { StringOpExp.new(val[0], val[2], :END_WITH) }
   | IDENTIFIER INCLUDE    STRING { StringOpExp.new(val[0], val[2], :INCLUDE) }
   | STRING EQ         IDENTIFIER { StringOpExp.new(val[0], val[2], :EQ) }
   | STRING NEQ        IDENTIFIER { StringOpExp.new(val[0], val[2], :NEQ) }
   | STRING START_WITH IDENTIFIER { StringOpExp.new(val[0], val[2], :START_WITH) }
   | STRING END_WITH   IDENTIFIER { StringOpExp.new(val[0], val[2], :END_WITH) }
   | STRING INCLUDE    IDENTIFIER { StringOpExp.new(val[0], val[2], :INCLUDE) }
   | IDENTIFIER REGEXP STRING     { RegexpOpExp.new(val[0], val[2], :REGEXP) }
   | IDENTIFIER IS NULL           { NullOpExp.new(val[0], :EQ) }
   | IDENTIFIER IS NOT NULL       { NullOpExp.new(val[0], :NEQ) }
   | exp OR exp                   { LogicalOpExp.new(val[0], val[2], :OR) }
   | exp AND exp                  { LogicalOpExp.new(val[0], val[2], :AND) }
   | NOT exp                      { NegateOpExp.new(val[1]) }
   | '(' exp ')'                  { val[1] }
   ;
end

---- header ----
#
# generated by racc
#
module Fluent; module FilterWhere; end; end
require_relative 'parser.rex'
require_relative 'parser/literal'
require_relative 'parser/exp'

---- inner ----

---- footer ----