/**
* JJTree file
*  NODE_PACKAGE = "eu.dnetlib.data.collective.transformation.rulelanguage.node";
*/

options {
  STATIC=false;
  MULTI = true;
  VISITOR = true;
  JDK_VERSION = "1.6";
}

PARSER_BEGIN(FtScript) 

package eu.dnetlib.data.collective.transformation.rulelanguage.parser;
import eu.dnetlib.data.collective.transformation.rulelanguage.Rules;
public class FtScript {
}

PARSER_END(FtScript)

SKIP :
{
  " "
| "\t"
| "\n"
| "\r"
| <"//" (~["\n","\r"])* ("\n"|"\r"|"\r\n")>
| <"/*" (~["*"])* "*" (~["/"] (~["*"])* "*")* "/">
}

MORE :
{
  "//" : IN_SINGLE_LINE_COMMENT
}

< IN_SINGLE_LINE_COMMENT >
SPECIAL_TOKEN :
{
  <SINGLE_LINE_COMMENT: "\n" | "\r" | "\r\n" > : DEFAULT
}

/* RESERVED WORDS AND LITERALS */
// KEYWORDS
TOKEN : {	< IMPORT:            "import" > }
TOKEN : {	< TRANS:             "trans" > }
TOKEN : {	< IF:                "if" > }
TOKEN : {	< ELSE:              "else" > }
TOKEN : {	< END:               "end" > }
TOKEN : {   < EXTRACT:           "Extract" > }
TOKEN : {   < IDENTIFIEREXTRACT: "identifierExtract" > }
TOKEN : {	< CONVERT:           "Convert" > }
TOKEN : {	< REGEXPR:           "RegExpr" > }
TOKEN : {	< GETVALUE:	         "getValue" > }
TOKEN : {   < COPY:              "copy" > }
TOKEN : {   < DECLARE_NAMESPACE: "declare_ns" > }
TOKEN : {   < DECLARE_SCRIPT:    "declare_script" > }
TOKEN : {   < DECLARE_SUBSCRIPT: "declare_subscript" > }
TOKEN : {   < PREPROCESS:        "preprocess" > }
TOKEN : {   < SET:               "set" > }
TOKEN : {   < SKIPRECORD:        "skipRecord" > }
TOKEN : {   < SPLIT:             "split" > }
TOKEN : {   < STATIC:            "static" > }
TOKEN : {   < XPATH_SCHEME:      "xpath:" > }
TOKEN : {   < APPLY:             "apply" > }
TOKEN : {   < EMPTY:             "empty" > }
TOKEN : {   < DBLOOKUP:          "dblookup" > }
TOKEN : {   < BLACKLIST:         "blacklist" > }
TOKEN : {   < LOOKUP:            "lookup" > }
TOKEN : {   < CONCAT:            "concat" > }

// SPEC. CHARS
TOKEN : { < SEMICOLON: ";" > }
TOKEN : { < RBRACKET: "]" > }
TOKEN : { < LBRACE: "{" > }
TOKEN : { < RBRACE: "}" > }
TOKEN : { < COMMA: "," > }
TOKEN : { < RPAREN: ")" > }
TOKEN : { < QUOTE: "'" > }

TOKEN :
{

  < EQUAL:   "="      > |
  < NOTEQUAL:   "!="      > |
  < GT:    " &gt; "  | ">"    > |
  < LT:    " &lt; "  | "<"    > |
  < GTE:   " &gt;= " | ">="    > |
  < LTE:   " &lt;= " | "<="    > |
  < PLUS:   "+"      > |
  < VBAR:   "|"      > |
//  < SLASH_SLASH:  "//"      > |
  < SLASH:   "/"      > |

  < DOT_DOT:      ".."      > |
  //< DOT:     "."      > |

  < AT:     "@"      > |

  < LPAREN: "(" > |
  < LBRACKET: "[" > |
  < DOLLAR_QNAME: "$" <IDENTIFIER>     >  |
  < PERCENT_QNAME: "%" < IDENTIFIER > >

}

TOKEN :
{
  < XPATH:
     < XPATH_SCHEME > <QUOTED_STRING >
  > 
}

TOKEN :
{
  < JOBCONST:
     < JOBCONST_PREFIX > <LETTER_OR_DIGIT> (<LETTER_OR_DIGIT>)* >
|  < #JOBCONST_PREFIX: "$job." >
}

TOKEN:
{
  < QUOTED_STRING: "\""
  (~["\""]
  )+ "\"" >
}

TOKEN:
{
  < SINGLE_QUOTE: "'"
  (~["'"]
  )+ "'" >
}

TOKEN : /* STRING LITERALS*/
{
  < CHARACTER_LITERAL:
      "'"
      (   (~["'","\\","\n","\r"])
        | ("\\"
            ( ["n","t","b","r","f","\\","'","\""]
            | ["0"-"7"] ( ["0"-"7"] )?
            | ["0"-"3"] ["0"-"7"] ["0"-"7"]
            )
          )
      )
      "'"
  >
| 
  < STRING_LITERAL:
    "\""
    ( (~["\"", "\\", "\n", "\r"])
      | ("\\"
           ( ["n", "t", "b", "r", "f", "\\", "'", "\""]
           | ["0"-"7"] ( ["0"-"7"] )?
           | ["0"-"3"] ["0"-"7"] ["0"-"7"]
           )
        )
    )*
    "\""
  >
}


TOKEN :
{
  < URI:
    < IDENTIFIER > "://" <IDENTIFIER >
    ( "/" < IDENTIFIER > )*  ( "/" )?
  >
}



TOKEN : /* IDENTIFIERS */
{
  < IDENTIFIER:
   ( < AT >|<LETTER_OR_DIGIT>) (<LETTER_OR_DIGIT>|<MINUS>|< DOT >|< COLON >|< AT >)* >
|  < #LETTER_OR_DIGIT: ["_","a"-"z","A"-"Z","0"-"9"] >
|  < #MINUS: "-" >
|  < #DOT: "." >
|  < #COLON: ":" >
//|  < #AT: "@" >
}



ASTStart Start() :{}
{	
  (script())
  { return jjtThis; }
}

/**
 * id = value
 */
void assign(Rules r) #MyAssign : {String value = ""; Token t;}
{
	                                                  {jjtThis.setRule(r);}
         (t = inputField()                            {jjtThis.setFieldExpression(t.image);}        
         |value = quotedString()                      {jjtThis.setAttribute(value);}
         )
}

void attrib_list() #void : {}
{
	<LBRACKET>
	  (attribute())*
	<RBRACKET>
}


void attribute() #MyAttribute : {String value; Token t=null;}
{
	(value = identifier() { jjtThis.setAttributeValue(value);}
	|t = inputField()
	{ value = t.image;
	  jjtThis.setAttributeInputField(value);
	}
	)
	[<COMMA>]
	
}

/**
 *  a conditional Rule, which contains the condition, the Rule on which the condition holds and the alternative rule
 */
void conditionalStmt() #MyCondition : {Rules r1 = new Rules(); Rules r2 = new Rules(); Token cond; Token apply;}
{
  [< APPLY > apply = inputField()
  {
    jjtThis.setApplyExpression(apply.image);
  } ]
   < IF > cond = inputField() { jjtThis.setConditionalExpression(cond.image); jjtThis.setPrimaryRule(r1); jjtThis.setSecondaryRule(r2); }
    rule(r1)
  < ELSE >
    rule(r2)
}

void empty(Rules r) #MyEmpty : {}
{
                                             {jjtThis.setRule(r);}
        < EMPTY >                            {jjtThis.setEmpty(true);}        
}

String identifier() #void : {Token t;}
{
  t = <IDENTIFIER> {return t.image;}
}

void importDeclaration() #MyImport :
{String scriptName;}
{
  <IMPORT> <LPAREN> scriptName = identifier() <RPAREN> ";" { jjtThis.setScriptName(scriptName); }
}

Token anyExpression() #void : { Token t; }
{
  t = < IDENTIFIER >
  {
    return t;
  }
}

Token inputField() #void :{ Token t; }
{
  t =  < XPATH >
  {
    return t;
  }
  | t = < JOBCONST >
  {
    return t;
  }
  | t = < DOLLAR_QNAME >
  {
    return t;
  }
}


/*
 * becomes obsolete
 */
String key() #void : {String key;}
{
   key = identifier()                     
   <EQUAL>
   {return key;}
}

void literal() #void :
{}
{
  < CHARACTER_LITERAL > | < STRING_LITERAL >
}

void nsDeclaration() #MyNs :
{String nsPrefix; String nsUri;}
{
	< DECLARE_NAMESPACE > nsPrefix = identifier() < EQUAL > nsUri = quotedString() < SEMICOLON >
	{
	  jjtThis.setNsDeclaration(nsPrefix, nsUri);
	}
}

void preprocess() #MyPreprocess :{String preprocessId;}
{
  (
    < PREPROCESS >
   preprocessId = identifier() < EQUAL >
   < DBLOOKUP >
    < LPAREN >                     { String sqlExpr; }
      sqlExpr = quotedString()
    < RPAREN >                     { jjtThis.preprocess(preprocessId, "dblookup", sqlExpr); }
  < SEMICOLON >
  ) |
 (
   < BLACKLIST >
   < LPAREN > { String blacklistDataSourceId; }
      blacklistDataSourceId = quotedString()
   < RPAREN >
   { jjtThis.preprocess("blacklist", blacklistDataSourceId); }
   < SEMICOLON >
 )
}

void set(Rules r) #MySet : {Token expr; String value = "";}
{
  {    jjtThis.setRule(r);  }

  < SET >
        < LPAREN >
        (
          
        expr = inputField()        { jjtThis.setValueExpression(expr.image); }
      | value = quotedString()     { jjtThis.setAttribute(value); }
        )
        (
          < COMMA >
		     {
		       r = new Rules();
		     }
		     rule(r)
		     {
			   jjtThis.addAttributeRule(r);  
			 }
          
        )*
        < RPAREN >
}

void skip(Rules r) #MySkip :{}
{
  { jjtThis.setRule(r);  }
	< SKIPRECORD >	                {jjtThis.skipRecord();}
	   < LPAREN >
	   < RPAREN >  
}

void copy(Rules r) #MyCopy : {}
{
  {    jjtThis.setRule(r);  }
  	   < COPY >
	      < LPAREN >         	        { String templateMatchExpression; String applyTemplateSelectExpression; String copySelectExpression; }
	       templateMatchExpression = quotedString()
	       < COMMA >
	       applyTemplateSelectExpression = quotedString()
	       <  COMMA >
	       copySelectExpression = quotedString()
	      < RPAREN >	                { jjtThis.copy(templateMatchExpression, applyTemplateSelectExpression, copySelectExpression); }

}

void op(Rules r) #MyOp : {String functionName = ""; Token expr; Token expr2; Token vocab; String defaultPattern = ""; String function = ""; String elementName = ""; String regExpr; Token feature;}
{
	                                    {jjtThis.setRule(r);}
	( (<GETVALUE> 
	 <LPAREN>
	   functionName = identifier() <COMMA> attrib_list()
	 <RPAREN>                           {jjtThis.getValue(functionName);}
	 )	 
	| (<CONVERT> 
	  <LPAREN>
	    expr = inputField()
	    <COMMA>
	    vocab = <IDENTIFIER>
	    (
	      <COMMA>
	      defaultPattern = quotedString()
	      <COMMA>
	      function = quotedString()
	    )*
	  <RPAREN>                          {jjtThis.convert(expr.image, vocab.image, defaultPattern, function);} 
	  )
	| (< EXTRACT >
	   < LPAREN >
	    feature = < IDENTIFIER >
	   < RPAREN >                       {jjtThis.extract(feature.image); }
	  )
	| (<REGEXPR>
		<LPAREN>
		expr = inputField()
		<COMMA>
		expr2 = inputField()
		<COMMA>
		regExpr = quotedString()
		<RPAREN>                        {jjtThis.regExpr(expr.image, expr2.image, regExpr);}
	  )
	| (<SPLIT>
	    < LPAREN >
	     expr = inputField()
	     < COMMA >
	     elementName = quotedString()
	     < COMMA >
	     regExpr = quotedString()
        < RPAREN >                      {jjtThis.split(expr.image, elementName, regExpr);}
	  )
	| ( < LOOKUP >                    	{ String propertyKey; }
         < LPAREN >                     
           expr = inputField()
           < COMMA >
           propertyKey = quotedString()
         < RPAREN >                     { jjtThis.lookup(expr.image, propertyKey); }
	  )
	| ( < IDENTIFIEREXTRACT >       	{ String xpathExprJsonString; Token xpathExprInputSource; }
	      < LPAREN > 
            // "{//abc, //def }" ?json list of xpath-expr
            // xpath-expr of input source
            // regExpr          
	        xpathExprJsonString = singleQuotedString()
	        < COMMA >
	        xpathExprInputSource = inputField()
	        < COMMA >
	        regExpr = singleQuotedString()            
	      < RPAREN >	                { jjtThis.identifierExtract(xpathExprJsonString, xpathExprInputSource.image, regExpr); }
	  )
	| ( < CONCAT >                    	{ jjtThis.concat();	}
	      < LPAREN >	                { String v; Token t; }
			( v = quotedString() { jjtThis.addConcat(v); }  | t = < DOLLAR_QNAME >			{ jjtThis.addConcat(t.image); }
			)
			(
			  < COMMA >
              (
                v = quotedString() { jjtThis.addConcat(v); } | t = < DOLLAR_QNAME >			{ jjtThis.addConcat(t.image); }
              )
			)*
	      < RPAREN >
	  )
	)
}

String leftExprOutputField() #void :{ String leftExpr; }
{
  leftExpr = identifier() < EQUAL > { return leftExpr; }
}

String leftExprVar() #void :{ String leftExpr; }
{
  leftExpr = variable() <  EQUAL >  { return leftExpr; }
}

String leftExprTemplate() #void :{ String leftExpr; }
{
  leftExpr = template() < EQUAL >  { return leftExpr;  }
}

String singleQuotedString() #void : { Token t;}
{
  t =
    < SINGLE_QUOTE >
    { return t.image; }
}

String quotedString() #void : {Token t;}
{
  t =
    < QUOTED_STRING >
     {return t.image;}
}

void rule(Rules r) #void : { String ruleDecl; String leftExpr;}
{
	[  ruleDecl = ruleDecl() { r.setRuleDeclaration(ruleDecl);	} ]
	 (
	   leftExpr = leftExprOutputField()
	   {
	     String[] fieldArray = leftExpr.split("@");
	     r.setTargetField(fieldArray[0]);
	     if (fieldArray.length > 1)
	     {
	       r.setAttribute(fieldArray[1]);
	     }
	   }
	 | leftExpr = leftExprVar()	 {	r.setVariable(leftExpr); }
	 | leftExpr = leftExprTemplate()	 { r.setTemplate(leftExpr);	 }
	 )
     (
 	   LOOKAHEAD(2)
       
       assign(r)
     | op(r)
     | set(r)
     | copy(r)
     | empty(r)
     | skip(r)
     ) < SEMICOLON >  
}

String ruleDecl() #void : {Token t;}
{
  (
    t = < STATIC >  
  )
  { return t.image;
  }
}

void script() #void :{}
{
	   scriptDeclaration()
	  [ importDeclaration() ]
	  (
	     nsDeclaration()
	   )*
	   (
	     preprocess()
	   )*
	  ( stmt() | conditionalStmt() )*
	  ( <END> <EOF> )
}

void scriptDeclaration() #MyScript :
{String scriptName; ASTMyScript.SCRIPTTYPE scriptType;}
{

  	(
  	  < DECLARE_SCRIPT >
  	  {
  	    jjtThis.setScriptType(ASTMyScript.SCRIPTTYPE.MAINSCRIPT);
  	  }
  	  | < DECLARE_SUBSCRIPT >
  	  {
  	    jjtThis.setScriptType(ASTMyScript.SCRIPTTYPE.SUBSCRIPT);  	    
  	  }
  	) scriptName = quotedString() < SEMICOLON >
  	{
  	  jjtThis.setScript(scriptName);
  	}
}

void stmt() #void :{Rules r = new Rules();}
{
  rule(r)
}

String string() #void : {Token t;}
{
	t = <STRING_LITERAL> {return t.image.substring(1, t.image.length()-1);}
}

String variable() #void : { Token t; }
{
  t = < DOLLAR_QNAME >  { return t.image;  }
}

String template() #void : { Token t; }
{
  t = < PERCENT_QNAME >  { return t.image;  }
}