/*
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
options
{
  STATIC = false;
  UNICODE_INPUT = true;
}

PARSER_BEGIN(FilterParser)
package org.apache.sling.resource.filter.impl.script;

import java.util.ArrayList;
import java.util.List;
import org.apache.sling.resource.filter.impl.node.*;

public final class FilterParser
{
}

PARSER_END(FilterParser)

SKIP :
{
  " "
| "\t"
}

TOKEN :
{
  < #PLUS: "+" >
| < #MINUS: "-" >
| < #DIGIT: [ "0"-"9" ] >
| < #EXP: ["e","E"] ( < PLUS > | < MINUS > )? >
| < #OFFSET: ["+","-"]["0"-"2"] <DIGIT> ":" ["0"-"5"] <DIGIT> >
| < #YYYYMMDD: <INTEGER> <INTEGER> <INTEGER> <INTEGER> <MINUS> ["0"-"1"] <INTEGER> <MINUS> ["0"-"3"] <DIGIT> >
| < #TIME: ["0"-"2"] <DIGIT> ":" ["0"-"5"] <DIGIT> ( ":" ["0"-"5"] <DIGIT> ("." <DIGIT>  <DIGIT>  <DIGIT>)? )? >
| < OFFSETDATETIME: <YYYYMMDD> "T" <TIME> <OFFSET> >
| < DATETIME: <YYYYMMDD> "T" <TIME> >
| < DATE: <YYYYMMDD> >
| < NUMBER:  <INTEGER> | <INTEGER> <FRACTIONAL_DIGITS> | <INTEGER> <EXPONENT> | <INTEGER> <FRACTIONAL_DIGITS> <EXPONENT> >
| < INTEGER: (<MINUS>)? ( <DIGITS> ) >
| < FRACTIONAL_DIGITS: "." <DIGITS> >
| < EXPONENT: <EXP> <DIGITS> >
| < DIGITS: ( <DIGIT> )+ >
}

TOKEN :
{
  < STRING : < SQUOTE > | < DQUOTE > >{matchedToken.image = image.substring(1, lengthOfMatch - 1);}
| < #SQUOTE :
    (
      "'"
      ( "\\" ~[ ] | ~[ "'", "\\" ] )*
      "'"
    ) >
| < #DQUOTE :
    (
      "\""
      ( "\\" ~[ ] | ~[ "\"", "\\" ] )*
      "\""
    ) >
}

TOKEN :
{
  < AND :
    (
      "&&"
    | "and"
    ) >
| < OR :
    (
      "||"
    | "or"
    ) >
| < NULL : "null" >
| < LPAREN : "(" >
| < RPAREN : ")" >
| < COMMA : "," >
| < BOOLEAN: "true" | "false" >
| < EQUAL : "==" | "is" >
| < NOT_EQUAL : "!=" | "is not" >
| < GREATER_THAN : ">" | "greater than" >
| < GREATER_THAN_OR_EQUAL : ">=" >
| < LESS_THAN : "<" | "less than" >
| < LESS_THAN_OR_EQUAL : "<=" >
| < LIKE : "~=" | "like" >
| < LIKE_NOT : "like not" | "not like" >
| < CONTAINS : "contains" >
| < CONTAINS_NOT : "contains not" >
| < CONTAINS_ANY : "contains any" >
| < CONTAINS_NOT_ANY : "contains not any" >
| < IN : "in" >
| < NOT_IN : "not in" >
| < DYNAMIC_ARG : "$" >
| < FUNCTION_NAME : (~[ "\"", "'", "$", "(", ")", ",", "=", "<", ">", " ", "[", "]","+","-",".","0"-"9" ])+ >
| < PROPERTY: "[" ( "\\" ~[ ] | ~[ "]", "\\" ] )* "]" >{matchedToken.image = image.substring(1, lengthOfMatch - 1);}
}

<*> TOKEN : { <UNKNOWN: ~[]> }

Node parse() :
{
  final Node node;
}
{
  node = or() < EOF >
  {
    return node;
  }
}

Node or() :
{
  final List < Node > nodes = new ArrayList < Node > (3);
  Node node;
}
{
  node = and()
  {
    nodes.add(node);
  }
  (
    < OR > node = and()
    {
      nodes.add(node);
    }
  )*
  {
    return nodes.size() != 1 ? new Node(FilterParserConstants.OR, nodes) : nodes.get(0);
  }
}

Node and() :
{
  final List < Node > nodes = new ArrayList < Node > (3);
  Node node;
}
{
  node = constraint()
  {
    nodes.add(node);
  }
  (
    < AND > node = constraint()
    {
      nodes.add(node);
    }
  )*
  {
    return nodes.size() != 1 ? new Node(FilterParserConstants.AND, nodes) : nodes.get(0);
  }
}

Node constraint() :
{
  final Node node;
}
{
  (
    node = group()
  | node = comparison()
  )
  {
    return node;
  }
}

Node group() :
{
  final Node node;
}
{
  < LPAREN > node = or() < RPAREN >
  {
    return node;
  }
}

Node comparison() :
{
  Node leftValue;
  Token op;
  Node rightValue;
}
{
  leftValue = argument()
  op = comparisonValue()
  rightValue = argument()
  {
    return new Node(op.kind, op.image, leftValue, rightValue);
  }
}

Token comparisonValue() :
{
}
{
  (
     < EQUAL >
  |  < NOT_EQUAL >
  |  < GREATER_THAN >
  |  < GREATER_THAN_OR_EQUAL >
  |  < LESS_THAN >
  |  < LESS_THAN_OR_EQUAL >
  |  < LIKE >
  |  < LIKE_NOT >
  |  < CONTAINS >
  |  < CONTAINS_NOT >
  |  < CONTAINS_ANY >
  |  < CONTAINS_NOT_ANY >
  |  < IN >
  |  < NOT_IN >
  )
  {
    return token;
  }
}


List < Node > Arguments() :
{
  Object value = new ArrayList();
}
{
  
  < LPAREN > [ value = commaSepArguments() ] < RPAREN >
  {
    return (List) value;
  }
}

List < Node > commaSepArguments() :
{
  final List < Node > list = new ArrayList < Node > (3);
  Node arg;
}
{
  arg = argument()
  {
    list.add(arg);
  }
  (
    < COMMA > 
    arg = argument()
    {
      list.add(arg);
    }
  )*
  {
    return list;
  }
}

Node argument() :
{
  Node selector = null;
}
{
  (
    selector = literal()
  | selector = property()
  | selector = dynamicArg()
  | selector = function()

  )
  {
    return selector;
  }
}

Node function() :
{
  String functionName = null;
  List < Node > children = null;
}
{
  < FUNCTION_NAME >
  {
    functionName = token.image;
  }
  < LPAREN > [ children = commaSepArguments() ] < RPAREN >
  {
    return new Node(FilterParserConstants.FUNCTION_NAME, functionName, children);
  }
}

Node dynamicArg() :
{
  String functionName = null;
}
{
  < DYNAMIC_ARG >< FUNCTION_NAME >
  {
    functionName = token.image;
    return new Node(FilterParserConstants.DYNAMIC_ARG, functionName);
  }
}

Node literal() :
{
}
{
  (
    < STRING >
  | < NUMBER >
  | < NULL >
  | < BOOLEAN >
  | < DATE >
  | < DATETIME >
  | < OFFSETDATETIME >
  )
  {
    return new Node(token.kind, token.image);
  }
}

Node property() :
{
}
{
  < PROPERTY > 
  {
    return new Node(token.kind, token.image);
  }
}
