/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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.
 *
 * $Header:$
 */
options {
  JAVA_UNICODE_ESCAPE = false;
  UNICODE_INPUT = true;
  STATIC = false;
  DEBUG_PARSER=false;
}

PARSER_BEGIN(NetUIELParser)

package org.apache.beehive.netui.script.el.parser;

import org.apache.beehive.netui.script.el.ExpressionTerm;
import org.apache.beehive.netui.script.el.LiteralTerm;
import org.apache.beehive.netui.script.el.ParsedExpression;
import org.apache.beehive.netui.script.el.Term;
import org.apache.beehive.netui.script.el.tokens.*;

public class NetUIELParser
{
    public static void main(String[] args)
        throws Exception
    {
        NetUIELParser parser = new NetUIELParser(System.in);
        parser.parse();
    }
}

PARSER_END(NetUIELParser)

<DEFAULT> TOKEN:
{
< NON_EXPRESSION_TEXT: (~["{", "\\"])+ | "\\{" | "\\" >
|
< START_EXPRESSION: "{" > : IN_EXPRESSION
|
< ESCAPED_START_EXPRESSION: "\\\\{" > : IN_EXPRESSION
}

<IN_EXPRESSION> TOKEN: 
{
< END_EXPRESSION: "}" > : DEFAULT
|
  /* String Literal -- This will accept a Java String literal that is converted internally into an EcmaScript compliant literal
     See: http://www.ecma-international.org/publications/files/ecma-st/Ecma-262.pdf -- Annex A, StringLiteral production
   */
< STRING_LITERAL: 
  ("\"" ((~["\"", "\\", "\n", "\r"])|<ECMA_ESCAPE_SEQUENCE>)* "\"") |
  ("'"  ((~["'",  "\\", "\n", "\r"])|<ECMA_ESCAPE_SEQUENCE>)* "'") 
  >
| <#ECMA_ESCAPE_SEQUENCE:
  "\\" | 
  (
  ["n", "t", "b", "r", "f", "\\", "'", "\""] |
  ["0"-"7"] (["0"-"7"])? |
  ["0"-"3"] ["0"-"7"] ["0"-"7"] |
  ["x","X"] <HIT> <HIT> |
  ["u","U"] <HIT> <HIT> <HIT> <HIT>
  )
  >
| <#HIT: ["0"-"9","a"-"f","A"-"F"] >
|
/* Identifiers */
< IDENTIFIER: (<LETTER>|<IMPL_OBJ_START>) (<LETTER>|<DIGIT>)* >
| < #IMPL_OBJ_START: "#" >
| < #LETTER:
      [
       "\u0024",
       "\u0041"-"\u005a",
       "\u005f",
       "\u0061"-"\u007a",
       "\u00c0"-"\u00d6",
       "\u00d8"-"\u00f6",
       "\u00f8"-"\u00ff",
       "\u0100"-"\u1fff",
       "\u3040"-"\u318f",
       "\u3300"-"\u337f",
       "\u3400"-"\u3d2d",
       "\u4e00"-"\u9fff",
       "\uf900"-"\ufaff"
      ]
  >
|
  < #DIGIT:
      [
       "\u0030"-"\u0039",
       "\u0660"-"\u0669",
       "\u06f0"-"\u06f9",
       "\u0966"-"\u096f",
       "\u09e6"-"\u09ef",
       "\u0a66"-"\u0a6f",
       "\u0ae6"-"\u0aef",
       "\u0b66"-"\u0b6f",
       "\u0be7"-"\u0bef",
       "\u0c66"-"\u0c6f",
       "\u0ce6"-"\u0cef",
       "\u0d66"-"\u0d6f",
       "\u0e50"-"\u0e59",
       "\u0ed0"-"\u0ed9",
       "\u1040"-"\u1049"
      ]
  >
| < INTEGER: ["0"-"9"] (["0"-"9"])* >
| <DOT: ".">
| <DQUOTE: "\"">
| <SQUOTE: "'">
| <LBRACKET: "[">
| <RBRACKET: "]">
}

// 3.
ParsedExpression parse() :
{
Token t = null;
ParsedExpression pe = new ParsedExpression();
Term term = null;
}
{
    (
     (term = parseLiteralTerm() {pe.addTerm(term);}) | 
     (<START_EXPRESSION> term = parseExpression() <END_EXPRESSION> {pe.addTerm(term);}) |
     (<ESCAPED_START_EXPRESSION> term = parseExpression() <END_EXPRESSION> {pe.addTerm(new LiteralTerm("\\")); pe.addTerm(term);}) 
    )* <EOF>
{
return pe;
}
}

LiteralTerm parseLiteralTerm() :
{
Token t = null;
LiteralTerm ls = null;
}
{
  (t = <NON_EXPRESSION_TEXT> {ls = new LiteralTerm(t.image); return ls;})
}


ExpressionTerm parseExpression() :
{
ExpressionTerm expr = new ExpressionTerm();
ExpressionToken eTok = null;
}
{

(
eTok = Context() 
{
expr.addToken(eTok);
}
(
  (<DOT> eTok = ExprIdentifier() | LOOKAHEAD(2) eTok = MapKey() | eTok = ArrayIndex())
  {
    {
      expr.addToken(eTok);
    }
  }

)*
)
{
expr.seal();
return expr;
}
}

ExpressionToken Context() :
{
Token t = null;
ExpressionToken eTok = null;
}
{
(t = <IDENTIFIER>)
{
//System.out.println("** Parser found context: " + t.image);
eTok = new ContextToken(t.image);
return eTok;
}
}

ExpressionToken ExprIdentifier() :
{
Token t = null;
ExpressionToken eTok = null;
}
{
(t = <IDENTIFIER>)
{
//System.out.println("** Parser found identifier: " + t.image);
eTok = new IdentifierToken(t.image);
return eTok;
}
}

// handle text inside of map braces as ["..."] or ['...']
ExpressionToken MapKey() :
{
Token t = null;
ExpressionToken eTok = null;
}
{
(
<LBRACKET> (t=<STRING_LITERAL>) <RBRACKET>
)
{
eTok = new MapKeyToken(t.image);
return eTok;
}
}

ExpressionToken ArrayIndex() :
{
Token t = null;
ExpressionToken eTok = null;
}
{
(<LBRACKET> (t = <INTEGER>) <RBRACKET>)
{
//System.out.println("** Parser found array index: " + t.image);
eTok = new ArrayIndexToken(t.image);
return eTok;
}
}
