All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.sourceforge.pmd.lang.velocity.ast.Vtl.jj Maven / Gradle / Ivy

There is a newer version: 7.6.0
Show newest version
/*@bgen(jjtree) Generated By:JJTree: Do not edit this line. Vtl.jj */
/*@egen*//*
 * 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.
 */

/*
 *  NOTE : please see documentation at bottom of this file. (It was placed there its tiring
 *    to always have to page past it... :)
 */
options
{
                 
                   
    IGNORE_CASE = true;

    /** for debugging purposes.  Keep false */
    DEBUG_PARSER=false;
    DEBUG_TOKEN_MANAGER=false;

}

PARSER_BEGIN(VtlParserImpl)
package net.sourceforge.pmd.lang.velocity.ast;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang3.StringUtils;

import net.sourceforge.pmd.lang.ast.impl.javacc.JavaccToken;


/**
 * This class is responsible for parsing a Velocity
 * template. This class was generated by JavaCC using
 * the JJTree extension to produce an Abstract
 * Syntax Tree (AST) of the template.
 *
 * Please look at the Parser.jjt file which is
 * what controls the generation of this class.
 *
 * @author Jason van Zyl
 * @author Geir Magnusson Jr.
 * @author Henning P. Schmiedehausen
 * @version $Id$
 * @deprecated Since 7.5.0. VtlParserImpl should have been package private because this is an implementation class
 * that should not be used directly.
 */
@Deprecated
public class VtlParserImpl/*@bgen(jjtree)*/implements VtlParserImplTreeConstants/*@egen*/
{/*@bgen(jjtree)*/
  protected static JJTVtlParserImplState jjtree = new JJTVtlParserImplState();

/*@egen*/
  private void throwParseException(String message) {
    throw new net.sourceforge.pmd.lang.ast.ParseException(message).withLocation(token);
  }
    /**
     * Check whether there is a left parenthesis with leading optional
     * whitespaces. This method is used in the semantic look ahead of
     * Directive method. This is done in code instead of as a production
     * for simplicity and efficiency.
     */
    private boolean isLeftParenthesis()
    {
        char c;
        int no = 0;
        try {
            while(true)
            {
                /**
                 * Read a character
                 */
                c = token_source.input_stream.readChar();
                no++;
                if (c == '(')
                {
                    return true;
                }
                /**
                 * if not a white space return
                 */
                else if (c != ' ' && c != '\n' && c != '\r' && c != '\t')
                {
                    return false;
                }
            }
        }
        catch(IOException e)
        {
        }
        finally
        {
            /**
             * Backup the stream to the initial state
             */
            token_source.input_stream.backup(no);
        }
        return false;
    }
}

PARSER_END(VtlParserImpl)

TOKEN_MGR_DECLS:
{
    private int fileDepth = 0;

    private int lparen = 0;
    private int rparen = 0;

    List stateStack = new ArrayList(50);

    public boolean debugPrint = false;

    private boolean inReference;
    public boolean inDirective;
    private boolean inComment;
    public  boolean inSet;

    /**
     *  pushes the current state onto the 'state stack',
     *  and maintains the parens counts
     *  public because we need it in PD & VM handling
     *
     *  @return boolean : success.  It can fail if the state machine
     *     gets messed up (do don't mess it up :)
     */
    public boolean stateStackPop()
    {
        ParserState s;
        try
        {
            s = (ParserState) stateStack.remove(stateStack.size() - 1); // stack.pop
        }
        catch(IndexOutOfBoundsException e)
        {
            // empty stack
            lparen=0;
            SwitchTo(DEFAULT);
            return false;
        }

        if( debugPrint )
            System.out.println(
                " stack pop (" + stateStack.size() + ") : lparen=" +
                    s.lparen +
                        " newstate=" + s.lexstate );

        lparen = s.lparen;
        rparen = s.rparen;

        SwitchTo(s.lexstate);

        return true;
    }

    /**
     *  pops a state off the stack, and restores paren counts
     *
     *  @return boolean : success of operation
     */
    public boolean stateStackPush()
    {
        if( debugPrint )
            System.out.println(" (" + stateStack.size() + ") pushing cur state : " +
                curLexState );

        ParserState s = new ParserState();
        s.lparen = lparen;
        s.rparen = rparen;
        s.lexstate = curLexState;

        lparen = 0;
        stateStack.add(s); // stack.push

        return true;
    }

    /**
     *  Clears all state variables, resets to
     *  start values, clears stateStack.  Call
     *  before parsing.
     */
    public void clearStateVars()
    {
        stateStack.clear();

        lparen = 0;
        rparen = 0;
        inReference = false;
        inDirective = false;
        inComment = false;
        inSet = false;

        return;
    }

    /**
     * Holds the state of the parsing process.
     */
    private static class ParserState
    {
        int lparen;
        int rparen;
        int lexstate;
    }

    /**
     *  handles the dropdown logic when encountering a RPAREN
     */
    private void RPARENHandler()
    {
        /*
         *  Ultimately, we want to drop down to the state below
         *  the one that has an open (if we hit bottom (DEFAULT),
         *  that's fine. It's just text schmoo.
         */

        boolean closed = false;

        if (inComment)
            closed = true;

        while( !closed )
        {
            /*
             * look at current state.  If we haven't seen a lparen
             * in this state then we drop a state, because this
             * lparen clearly closes our state
             */

            if( lparen > 0)
            {
                /*
                 *  if rparen + 1 == lparen, then this state is closed.
                 * Otherwise, increment and keep parsing
                 */

                 if( lparen == rparen + 1)
                 {
                       stateStackPop();
                 }
                else
                {
                    rparen++;
                }

                 closed = true;
            }
            else
            {
                /*
                 * now, drop a state
                 */

                if(!stateStackPop())
                    break;
            }
        }
    }
}

/* ------------------------------------------------------------------------
 *
 * Tokens
 *
 *  Note : we now have another state, REFMODIFIER.  This is sort of a
 *  type of REFERENCE state, simply use to use the DIRECTIVE token
 *  set when we are processing a $foo.bar() construct
 *
 * ------------------------------------------------------------------------- */


TOKEN:
{
   
   {
     stateStackPush();
     SwitchTo(REFINDEX);
   }

}


TOKEN:
{
   
   {
     stateStackPop();
   }
}



TOKEN:
{
    
|   
|   
}


TOKEN:
{
  
}


TOKEN:
{
  
}


TOKEN:
{
  
}


TOKEN :
{
    
  | 
}


TOKEN:
{
    
    {
        if (!inComment)
            lparen++;

        /*
         * If in REFERENCE and we have seen the dot, then move
         * to REFMOD2 -> Modifier()
         */

        if (curLexState == REFMODIFIER )
            SwitchTo( REFMOD2 );
    }
}

/*
 * we never will see a ')' in anything but DIRECTIVE and REFMOD2.
 * Each have their own
 */

TOKEN:
{
    /*
     *  We will eat any whitespace upto and including a newline for directives
     */
    
    {
       RPARENHandler();
    }
}



TOKEN:
{
    /*
     * in REFMOD2, we don't want to bind the whitespace and \n like we
     * do when closing a directive.
     */
    
    {
        /*
         * need to simply switch back to REFERENCE, not drop down the stack
         * because we can (infinitely) chain, ala
         * $foo.bar().blargh().woogie().doogie()
         */

        SwitchTo( REFERENCE );
    }
}

/*----------------------------------------------
 *
 *  escape "\\" handling for the built-in directives
 *
 *--------------------------------------------- */
TOKEN:
{
    /*
     *  We have to do this, because we want these to be a Text node, and
     *  whatever follows to be peer to this text in the tree.
     *
     *  We need to touch the ASTs for these, because we want an even # of \'s
     *  to render properly in front of the block
     *
     *  This is really simplistic.  I actually would prefer to find them in
     *  grammatical context, but I am neither smart nor rested, a receipe
     *  for disaster, another long night with Mr. Parser, or both.
     */

    )* "\\#" ( | ) >
}


/*
 * needed because #set is so wacky in it's desired behavior.  We want set
 * to eat any preceding whitespace so it is invisible in formatting.
 * (As it should be.)  If this works well, I am going to chuck the whole MORE:
 * token abomination.
 *
 * We added the lexical states REFERENCE, REFMODIFIER, REFMOD2 to
 * address JIRA issue VELOCITY-631. With SET_DIRECTIVE only in the
 * DEFAULT lexical state the following VTL fails "$a#set($b = 1)"
 * because the Reference token uses LOOKAHEAD(2) combined with the
 * fact that we explicity set the lex state to REFERENCE with the $
 * token, which means we would never evaulate this token during the
 * look ahead.  This general issue is disscussed here:
 *
 *  http://www.engr.mun.ca/~theo/JavaCC-FAQ/javacc-faq-ie.htm#tth_sEc3.12
 *
 */

TOKEN:
{
  
    {
        if (! inComment)
        {
            inDirective = true;

            if ( debugPrint )
                System.out.print("#set :  going to " + DIRECTIVE );

            stateStackPush();
            inSet = true;
            SwitchTo(DIRECTIVE);
        }

        /*
         *  need the LPAREN action
         */

        if (!inComment)
        {
            lparen++;

            /*
             * If in REFERENCE and we have seen the dot, then move
             * to REFMOD2 -> Modifier()
             */

            if (curLexState == REFMODIFIER )
                SwitchTo( REFMOD2 );
        }
   }
}

<*>
MORE :
{
    /*
     *   Note : DOLLARBANG is a duplicate of DOLLAR.  They must be identical.
     */

    
    {
        if (! inComment)
        {
            /*
             * if we find ourselves in REFERENCE, we need to pop down
             * to end the previous ref
             */

            if (curLexState == REFERENCE)
            {
                inReference = false;
                stateStackPop();
            }

            inReference = true;

            if ( debugPrint )
                System.out.print( "$  : going to " + REFERENCE );

            stateStackPush();
            SwitchTo(REFERENCE);
        }
    }

|   
    {
        if (! inComment)
        {
            /*
             * if we find ourselves in REFERENCE, we need to pop down
             * to end the previous ref
             */

            if (curLexState == REFERENCE)
            {
                inReference = false;
                stateStackPop();
            }

            inReference = true;

            if ( debugPrint )
                System.out.print( "$!  : going to " + REFERENCE );

            stateStackPush();
            SwitchTo(REFERENCE);
        }
    }

|   "#[["
    {
       if (!inComment)
       {
           inComment = true;
           stateStackPush();
           SwitchTo( IN_TEXTBLOCK );
       }
    }

|   <"#**" ~["#"]>
    {
    	if (!inComment)
    	{
	        input_stream.backup(1);
	        inComment = true;
	        stateStackPush();
	        SwitchTo( IN_FORMAL_COMMENT);
    	}
    }

|   "#*"
    {
    	if (!inComment)
    	{
	        inComment=true;
	        stateStackPush();
	        SwitchTo( IN_MULTI_LINE_COMMENT );
    	}
    }

|   
    {
        if (! inComment)
        {
            /*
             * We can have the situation where #if($foo)$foo#end.
             * We need to transition out of REFERENCE before going to DIRECTIVE.
             * I don't really like this, but I can't think of a legal way
             * you are going into DIRECTIVE while in REFERENCE.  -gmj
             */

            if (curLexState == REFERENCE || curLexState == REFMODIFIER )
            {
                inReference = false;
                stateStackPop();
            }

            inDirective = true;

            if ( debugPrint )
                System.out.print("# :  going to " + DIRECTIVE );

            stateStackPush();
            SwitchTo(PRE_DIRECTIVE);
        }
    }
}


// treat the single line comment case separately
// to avoid ## errors

TOKEN :
{
   
   {
        if (!inComment)
        {
            if (curLexState == REFERENCE)
            {
                inReference = false;
                stateStackPop();
            }

            inComment = true;
            stateStackPush();
            SwitchTo(IN_SINGLE_LINE_COMMENT);
        }
     }
}

TOKEN :
{
    
|   
|   
}


/* -----------------------------------------------------------------------
 *
 *   *_COMMENT Lexical tokens
 *
 *-----------------------------------------------------------------------*/

TOKEN :
{
  
  {
     inComment = false;
     stateStackPop();
  }

}


TOKEN :
{
  
  {
    inComment = false;
    stateStackPop();
  }
}


TOKEN :
{
  
  {
    inComment = false;
    stateStackPop();
  }
}


TOKEN :
{
  
  {
    inComment = false;
    stateStackPop();
  }
}


SKIP :
{
  < ~[] >
}


MORE :
{
  < ~[] >
}

/* -----------------------------------------------------------------------
 *
 *  DIRECTIVE Lexical State (some of it, anyway)
 *
 * ---------------------------------------------------------------------- */


TOKEN:
{
    
}


TOKEN :
{
//   
  < STRING_LITERAL:
      ("\""
        (   (~["\""])
          | ("\\"
              ( ["n","t","b","r","f"]
              | ["0"-"7"] ( ["0"-"7"] )?
              | ["0"-"3"] ["0"-"7"] ["0"-"7"]
              | "u" ["0"-"9", "a"-"f", "A"-"F"] ["0"-"9", "a"-"f", "A"-"F"] ["0"-"9", "a"-"f", "A"-"F"] ["0"-"9", "a"-"f", "A"-"F"]
              )
            )
          | ("\"\"")
          | ( "\\" (" ")* "\n")
        )*
        "\""
      )
    |
    ("\'"
        (   (~["\'"])
          | ("''")
          | ( "\\" (" ")* "\n")
        )*
        "\'"
      )
  >

    {
        /*
         *  - if we are in DIRECTIVE and haven't seen ( yet, then also drop out.
         *      don't forget to account for the beloved yet wierd #set
         *  - finally, if we are in REFMOD2 (remember : $foo.bar( ) then " is ok!
         */

         if( curLexState == DIRECTIVE && !inSet && lparen == 0)
            stateStackPop();
    }
}


TOKEN:
{
   
|   
}


TOKEN :
{
    
    {
        if ( debugPrint )
            System.out.println(" NEWLINE :");

        stateStackPop();

        if (inSet)
            inSet = false;

        if (inDirective)
            inDirective = false;
    }
}



TOKEN :
{
    
|   
|   
|   
|   
|   
|   
|   
|   
|   " | "gt" >
|   =" | "ge" >
|   
|   
|   
|   
    {
        inDirective = false;
        stateStackPop();
    }
|   
    {
        SwitchTo(DIRECTIVE);
    }
|   
    {
        SwitchTo(DIRECTIVE);
    }

|   
    {
        SwitchTo(DIRECTIVE);
    }

|   
     {
        inDirective = false;
        stateStackPop();
    }
}


TOKEN:
{
   <#DIGIT: [ "0"-"9" ] >

    /*
     * treat FLOATING_POINT_LITERAL and INTEGER_LITERAL differently as a range can only handle integers.
     */

    /**
     * Note -- we also define an integer as ending with a double period,
     * in order to avoid 1..3 being defined as floating point (1.) then a period, then a integer
    */
|   )+ ("..")? >
    {

        /*
         * Remove the double period if it is there
         */
        if (matchedToken.getImage().endsWith("..")) {
            input_stream.backup(2);
            matchedToken = matchedToken.replaceImage(input_stream);
        }

        /*
         * check to see if we are in set
         *    ex.  #set $foo = $foo + 3
         *  because we want to handle the \n after
         */

        if ( lparen == 0 && !inSet && curLexState != REFMOD2 && curLexState != REFINDEX)
        {
            stateStackPop();
        }
    }

|    )+ "." ()* ()?
      | ("-")? "." ()+ ()?
      | ("-")? ()+ 
    >
    {
        /*
         * check to see if we are in set
         *    ex.  #set $foo = $foo + 3
         *  because we want to handle the \n after
         */

        if ( lparen == 0 && !inSet && curLexState != REFMOD2)
        {
            stateStackPop();
    }
}
|
    <#EXPONENT: ["e","E"] (["+","-"])? (["0"-"9"])+ >

}


TOKEN:
{
    <#LETTER: [ "a"-"z", "A" - "Z" ] >
|   <#DIRECTIVE_CHAR: [ "a"-"z", "A"-"Z", "0"-"9", "_", "@" ] >
|    | ["_"] | ["@"]) ()* >
|    | ["_"]) ()* "}" >

}

/* -----------------------------------------------------------------------
 *
 *  REFERENCE Lexical States
 *
 *  This is more than a single state, because of the  structure of
 *  the VTL references.  We use three states because the set of tokens
 *  for each state can be different.
 *
 *  $foo.bar( "arg" )
 *  ^   ^   ^
 *  |   |   |
 *  ----------- >  REFERENCE : state initiated by the '$' character.  Continues
 *      |   |       until end of the reference, or the . character.
 *      |------ >  REFMODIFIER : state switched to when the  is encountered.
 *          |       note that this is a switch, not a push. See notes at bottom
 *          |       re stateStack.
 *          |-- >  REFMOD2 : state switch to when the LPAREN is encountered.
 *                  again, this is a switch, not a push.
 *
 *  During the REFERENCE or REFMODIFIER lex states we will switch to
 *  REFINDEX if a bracket is encountered '['.  for example:  $foo[1]
 *  or $foo.bar[1], $foo.bar( "arg" )[1]
 * ---------------------------------------------------------------------------- */


TOKEN :
{
    <#ALPHA_CHAR: ["a"-"z", "A"-"Z"] >
|   <#ALPHANUM_CHAR: [ "a"-"z", "A"-"Z", "0"-"9" ] >
|   <#IDENTIFIER_CHAR: [ "a"-"z", "A"-"Z", "0"-"9", "-", "_" ] >
|    | ["_"]) ()* >
|   >
    {
        /*
         * push the alpha char back into the stream so the following identifier
         * is complete
         */

        input_stream.backup(1);

        /*
         * and munge the  so we just get a . when we have normal text that
         * looks like a ref.ident
         */

        matchedToken = matchedToken.replaceImage(input_stream);

        if ( debugPrint )
            System.out.print("DOT : switching to " + REFMODIFIER);
        SwitchTo(REFMODIFIER);

    }
}



TOKEN :
{
    
|   
    {
        stateStackPop();
    }
}


SPECIAL_TOKEN :
{
    
    {
        /*
         * push every terminator character back into the stream
         */

        input_stream.backup(1);

        inReference = false;

        if ( debugPrint )
            System.out.print("REF_TERM :");

        stateStackPop();
    }
}


SPECIAL_TOKEN :
{
    
    {
        if ( debugPrint )
            System.out.print("DIRECTIVE_TERM :");

        input_stream.backup(1);
        inDirective = false;
        stateStackPop();
    }
}

/**
 * This method is what starts the whole parsing
 * process. After the parsing is complete and
 * the template has been turned into an AST,
 * this method returns the root of AST which
 * can subsequently be traversed by a visitor
 * which implements the ParserVisitor interface
 * which is generated automatically by JavaCC
 */
ASTTemplate Template() : {/*@bgen(jjtree) Template */
  ASTTemplate jjtn000 = new ASTTemplate(JJTTEMPLATE);
  boolean jjtc000 = true;
  jjtree.openNodeScope(jjtn000);
/*@egen*/}
{/*@bgen(jjtree) Template */
   try {
/*@egen*/
   ( Statement() )* /*@bgen(jjtree)*/
   {
     jjtree.closeNodeScope(jjtn000, true);
     jjtc000 = false;
   }
/*@egen*/
   { return jjtn000; }/*@bgen(jjtree)*/
   } catch (Throwable jjte000) {
     if (jjtc000) {
       jjtree.clearNodeScope(jjtn000);
       jjtc000 = false;
     } else {
       jjtree.popNode();
     }
     if (jjte000 instanceof RuntimeException) {
       throw (RuntimeException)jjte000;
     }
     if (jjte000 instanceof net.sourceforge.pmd.lang.ast.ParseException) {
       throw (net.sourceforge.pmd.lang.ast.ParseException)jjte000;
     }
     throw (Error)jjte000;
   } finally {
     if (jjtc000) {
       jjtree.closeNodeScope(jjtn000, true);
     }
   }
/*@egen*/
}

/**
 * These are the types of statements that
 * are acceptable in Velocity templates.
 */
void Statement()       : {}
{
    IfStatement()
|   ForeachStatement()
|   LOOKAHEAD(2) Reference()
|   Comment()
|   Textblock()
|   SetDirective()
|   EscapedDirective()
|   Escape()
|   Directive()
|   Text()
}

/**
 *  used to separate the notion of a valid directive that has been
 *  escaped, versus something that looks like a directive and
 *  is just schmoo.  This is important to do as a separate production
 *  that creates a node, because we want this, in either case, to stop
 *  the further parsing of the Directive() tree.
 */
void EscapedDirective() : {/*@bgen(jjtree) EscapedDirective */
  ASTEscapedDirective jjtn000 = new ASTEscapedDirective(JJTESCAPEDDIRECTIVE);
  boolean jjtc000 = true;
  jjtree.openNodeScope(jjtn000);
/*@egen*/}
{/*@bgen(jjtree) EscapedDirective */
    try {
/*@egen*/
    /*@bgen(jjtree)*/
    } finally {
      if (jjtc000) {
        jjtree.closeNodeScope(jjtn000, true);
      }
    }
/*@egen*/
}

/**
 *  Used to catch and process escape sequences in grammatical constructs
 *  as escapes outside of VTL are just characters.  Right now we have both
 *  this and the EscapeDirective() construction because in the EscapeDirective()
 *  case, we want to suck in the #<directive> and here we don't.  We just want
 *  the escapes to render correctly
 */
void Escape() :
{/*@bgen(jjtree) Escape */
  ASTEscape jjtn000 = new ASTEscape(JJTESCAPE);
  boolean jjtc000 = true;
  jjtree.openNodeScope(jjtn000);
/*@egen*/ int count = 0; }
{/*@bgen(jjtree) Escape */
   try {
/*@egen*/
   ( LOOKAHEAD(2)   { count++; } )+/*@bgen(jjtree)*/
    {
      jjtree.closeNodeScope(jjtn000, true);
      jjtc000 = false;
    }
/*@egen*/
    {
        jjtn000.setValue(StringUtils.repeat("\\", count));
    }/*@bgen(jjtree)*/
   } finally {
     if (jjtc000) {
       jjtree.closeNodeScope(jjtn000, true);
     }
   }
/*@egen*/
}

void Comment() : {/*@bgen(jjtree) Comment */
  ASTComment jjtn000 = new ASTComment(JJTCOMMENT);
  boolean jjtc000 = true;
  jjtree.openNodeScope(jjtn000);
/*@egen*/}
{/*@bgen(jjtree) Comment */
        try {
/*@egen*/
	 (  ) ?
|   
|   /*@bgen(jjtree)*/
        } finally {
          if (jjtc000) {
            jjtree.closeNodeScope(jjtn000, true);
          }
        }
/*@egen*/
}

void Textblock() : {/*@bgen(jjtree) Textblock */
  ASTTextblock jjtn000 = new ASTTextblock(JJTTEXTBLOCK);
  boolean jjtc000 = true;
  jjtree.openNodeScope(jjtn000);
/*@egen*/}
{/*@bgen(jjtree) Textblock */
   try {
/*@egen*/
   /*@bgen(jjtree)*/
   } finally {
     if (jjtc000) {
       jjtree.closeNodeScope(jjtn000, true);
     }
   }
/*@egen*/
}

void FloatingPointLiteral() : {/*@bgen(jjtree) FloatingPointLiteral */
  ASTFloatingPointLiteral jjtn000 = new ASTFloatingPointLiteral(JJTFLOATINGPOINTLITERAL);
  boolean jjtc000 = true;
  jjtree.openNodeScope(jjtn000);
/*@egen*/}
{/*@bgen(jjtree) FloatingPointLiteral */
    try {
/*@egen*/
    /*@bgen(jjtree)*/
    } finally {
      if (jjtc000) {
        jjtree.closeNodeScope(jjtn000, true);
      }
    }
/*@egen*/
}

void IntegerLiteral() : {/*@bgen(jjtree) IntegerLiteral */
  ASTIntegerLiteral jjtn000 = new ASTIntegerLiteral(JJTINTEGERLITERAL);
  boolean jjtc000 = true;
  jjtree.openNodeScope(jjtn000);
/*@egen*/}
{/*@bgen(jjtree) IntegerLiteral */
     try {
/*@egen*/
     /*@bgen(jjtree)*/
     } finally {
       if (jjtc000) {
         jjtree.closeNodeScope(jjtn000, true);
       }
     }
/*@egen*/
}

void StringLiteral() : {/*@bgen(jjtree) StringLiteral */
  ASTStringLiteral jjtn000 = new ASTStringLiteral(JJTSTRINGLITERAL);
  boolean jjtc000 = true;
  jjtree.openNodeScope(jjtn000);
/*@egen*/}
{/*@bgen(jjtree) StringLiteral */
    try {
/*@egen*/
    /*@bgen(jjtree)*/
    } finally {
      if (jjtc000) {
        jjtree.closeNodeScope(jjtn000, true);
      }
    }
/*@egen*/
}

/**
 * This method corresponds to variable
 * references in Velocity templates.
 * The following are examples of variable
 * references that may be found in a
 * template:
 *
 * $foo
 * $bar
 *
 */
void Identifier() : {/*@bgen(jjtree) Identifier */
  ASTIdentifier jjtn000 = new ASTIdentifier(JJTIDENTIFIER);
  boolean jjtc000 = true;
  jjtree.openNodeScope(jjtn000);
/*@egen*/}
{/*@bgen(jjtree) Identifier */
    try {
/*@egen*/
    /*@bgen(jjtree)*/
    } finally {
      if (jjtc000) {
        jjtree.closeNodeScope(jjtn000, true);
      }
    }
/*@egen*/
}

void Word() : {/*@bgen(jjtree) Word */
  ASTWord jjtn000 = new ASTWord(JJTWORD);
  boolean jjtc000 = true;
  jjtree.openNodeScope(jjtn000);
/*@egen*/}
{/*@bgen(jjtree) Word */
    try {
/*@egen*/
    /*@bgen(jjtree)*/
    } finally {
      if (jjtc000) {
        jjtree.closeNodeScope(jjtn000, true);
      }
    }
/*@egen*/
}

/**
 *   Supports the arguments for the Pluggable Directives
 */
void DirectiveArg()       : {}
{
    Reference()
|   Word()
|   StringLiteral()
|   IntegerLiteral()
    /*
     * Need to put this before the floating point expansion
     */
|   LOOKAHEAD(   [] ( Reference() | IntegerLiteral())     []  ) IntegerRange()
|   FloatingPointLiteral()
|   Map()
|   ObjectArray()
|   True()
|   False()
}


/**
 *   Supports the Pluggable Directives
 *     #foo( arg+ )
 */
VtlNode Directive() :
{/*@bgen(jjtree) Directive */
    ASTDirective jjtn000 = new ASTDirective(JJTDIRECTIVE);
    boolean jjtc000 = true;
    jjtree.openNodeScope(jjtn000);
/*@egen*/
    JavaccToken t = null;
    int argPos = 0;
    boolean isVM = false;
    boolean doItNow = false;
}
{/*@bgen(jjtree) Directive */
    try {
/*@egen*/

    /*
     * note that if we were escaped, that is now handled by
     * EscapedDirective()
     */
    ((t = ) | (t = ))
    {
        String directiveName;
        if (t.kind == VtlTokenKinds.BRACKETED_WORD)
        {
            directiveName = t.getImage().substring(2, t.getImage().length() - 1);
        }
        else
        {
            directiveName = t.getImage().substring(1);
        }

        /*
         *  Velocimacro support : if the directive is macro directive
         *   then set the flag so after the block parsing, we add the VM
         *   right then. (So available if used w/in the current template )
         */

        if (directiveName.equals("macro"))
        {
             doItNow = true;
        }

        /*
         * set the directive name from here.  No reason for the thing to know
         * about parser tokens
         */
        jjtn000.setDirectiveName(directiveName);

        /*
         *  now, switch us out of PRE_DIRECTIVE
         */
        token_source.SwitchTo(DIRECTIVE);

        argPos = 0;
    }


     /**
      * Look for the pattern [WHITESPACE] 
      */
    (LOOKAHEAD( { isLeftParenthesis() } )
    /*
     *  if this is indeed a token, match the #foo ( arg ) pattern
     */
    []  ( LOOKAHEAD(2) [] [ []]

            DirectiveArg()
            {
                if (jjtree.peekNode() instanceof ASTWord)
                {
                    if (doItNow && argPos == 0)
                    {
                        /* if #macro and it's the 0th arg, ok */
                    }
                    else if (!jjtn000.isDirective())
                    {
                        // not a real directive, but maybe a Velocimacro
                        throwParseException("Invalid arg #"
                        + argPos + " in VM " + t.getImage());
                    }
                    /* if #foreach and it's the 2nd arg, ok */
                    else if (jjtn000.isDirective() && (!"foreach".equals(jjtn000.getDirectiveName()) || argPos != 1))
                    {
                        throwParseException("Invalid arg #"
                        + argPos + " in directive " + t.getImage());
                    }
                    else
                    {
                        /* either schmoo or a late-defined macro,
                         * VelocimacroProxy will have to check for latter. */
                    }
                }
                else
                {
                    if (doItNow && argPos == 0)
                    {
                        /* if a VM and it's the 0th arg, not ok */

                        throwParseException("Invalid first arg"
                        + " in #macro() directive - must be a"
                        + " word token (no ' or double quote surrounding)");
                    }
                }

                argPos++;
            }

    )* [] 
    {

        if (jjtn000.isLine())
        {
            return jjtn000;
        }
    }
    |
    {
	if (doItNow)  // doItNow is true if the directive is "macro"
	{
            // VELOCITY-667 We get here if we have a "#macro" construct
	    // without parenthesis which is a parse error
            throwParseException("A macro declaration requires at least a name argument");
	}

        /**
         * Not a directive
         */
        token_source.stateStackPop();
        token_source.inDirective = false;
        return jjtn000;
    }
    )/*@bgen(jjtree) Block */
    {
      ASTBlock jjtn001 = new ASTBlock(JJTBLOCK);
      boolean jjtc001 = true;
      jjtree.openNodeScope(jjtn001);
    }
    try {
/*@egen*/
    /*
     *  and the following block if the PD needs it
     */

    ( Statement() )*/*@bgen(jjtree)*/
    } catch (Throwable jjte001) {
      if (jjtc001) {
        jjtree.clearNodeScope(jjtn001);
        jjtc001 = false;
      } else {
        jjtree.popNode();
      }
      if (jjte001 instanceof RuntimeException) {
        throw (RuntimeException)jjte001;
      }
      if (jjte001 instanceof net.sourceforge.pmd.lang.ast.ParseException) {
        throw (net.sourceforge.pmd.lang.ast.ParseException)jjte001;
      }
      throw (Error)jjte001;
    } finally {
      if (jjtc001) {
        jjtree.closeNodeScope(jjtn001, true);
      }
    }
/*@egen*/       
    /*@bgen(jjtree)*/
    {
      jjtree.closeNodeScope(jjtn000, true);
      jjtc000 = false;
    }
/*@egen*/
    { return jjtn000; }/*@bgen(jjtree)*/
    } catch (Throwable jjte000) {
      if (jjtc000) {
        jjtree.clearNodeScope(jjtn000);
        jjtc000 = false;
      } else {
        jjtree.popNode();
      }
      if (jjte000 instanceof RuntimeException) {
        throw (RuntimeException)jjte000;
      }
      if (jjte000 instanceof net.sourceforge.pmd.lang.ast.ParseException) {
        throw (net.sourceforge.pmd.lang.ast.ParseException)jjte000;
      }
      throw (Error)jjte000;
    } finally {
      if (jjtc000) {
        jjtree.closeNodeScope(jjtn000, true);
      }
    }
/*@egen*/
}

/**
 * for creating a map in a #set
 *
 *  #set($foo = {$foo : $bar, $blargh : $thingy})
 */
void Map() : {/*@bgen(jjtree) Map */
  ASTMap jjtn000 = new ASTMap(JJTMAP);
  boolean jjtc000 = true;
  jjtree.openNodeScope(jjtn000);
/*@egen*/}
{/*@bgen(jjtree) Map */
    try {
/*@egen*/
    
    (
      LOOKAHEAD(2) Parameter()  Parameter() ( Parameter()  Parameter() )*
      |
      [  ]
     )

     /** note: need both tokens as they are generated in different states **/
     (  |  )/*@bgen(jjtree)*/
    } catch (Throwable jjte000) {
      if (jjtc000) {
        jjtree.clearNodeScope(jjtn000);
        jjtc000 = false;
      } else {
        jjtree.popNode();
      }
      if (jjte000 instanceof RuntimeException) {
        throw (RuntimeException)jjte000;
      }
      if (jjte000 instanceof net.sourceforge.pmd.lang.ast.ParseException) {
        throw (net.sourceforge.pmd.lang.ast.ParseException)jjte000;
      }
      throw (Error)jjte000;
    } finally {
      if (jjtc000) {
        jjtree.closeNodeScope(jjtn000, true);
      }
    }
/*@egen*/
}

void ObjectArray() : {/*@bgen(jjtree) ObjectArray */
  ASTObjectArray jjtn000 = new ASTObjectArray(JJTOBJECTARRAY);
  boolean jjtc000 = true;
  jjtree.openNodeScope(jjtn000);
/*@egen*/}
{/*@bgen(jjtree) ObjectArray */
    try {
/*@egen*/
     [ Parameter() (  Parameter() )* ] /*@bgen(jjtree)*/
    } catch (Throwable jjte000) {
      if (jjtc000) {
        jjtree.clearNodeScope(jjtn000);
        jjtc000 = false;
      } else {
        jjtree.popNode();
      }
      if (jjte000 instanceof RuntimeException) {
        throw (RuntimeException)jjte000;
      }
      if (jjte000 instanceof net.sourceforge.pmd.lang.ast.ParseException) {
        throw (net.sourceforge.pmd.lang.ast.ParseException)jjte000;
      }
      throw (Error)jjte000;
    } finally {
      if (jjtc000) {
        jjtree.closeNodeScope(jjtn000, true);
      }
    }
/*@egen*/
}


/**
 *  supports the [n..m] vector generator for use in
 *  the #foreach() to generate measured ranges w/o
 *  needing explicit support from the app/servlet
 */
void IntegerRange() : {/*@bgen(jjtree) IntegerRange */
  ASTIntegerRange jjtn000 = new ASTIntegerRange(JJTINTEGERRANGE);
  boolean jjtc000 = true;
  jjtree.openNodeScope(jjtn000);
/*@egen*/}
{/*@bgen(jjtree) IntegerRange */
    try {
/*@egen*/
     []
    ( Reference() | IntegerLiteral())
    []  []
    (Reference() | IntegerLiteral())
    [] /*@bgen(jjtree)*/
    } catch (Throwable jjte000) {
      if (jjtc000) {
        jjtree.clearNodeScope(jjtn000);
        jjtc000 = false;
      } else {
        jjtree.popNode();
      }
      if (jjte000 instanceof RuntimeException) {
        throw (RuntimeException)jjte000;
      }
      if (jjte000 instanceof net.sourceforge.pmd.lang.ast.ParseException) {
        throw (net.sourceforge.pmd.lang.ast.ParseException)jjte000;
      }
      throw (Error)jjte000;
    } finally {
      if (jjtc000) {
        jjtree.closeNodeScope(jjtn000, true);
      }
    }
/*@egen*/
}


/**
 * A Simplified parameter more suitable for an index position: $foo[$index]
 */
void IndexParameter()      : {}
{
    []
    (
        StringLiteral()
        | IntegerLiteral()
        | True()
        | False()
        | Reference()
        )
    [ ]
}


/**
 * This method has yet to be fully implemented
 * but will allow arbitrarily nested method
 * calls
 */
void Parameter()      : {}
{
    []
    (
        StringLiteral()
        | IntegerLiteral()
        | LOOKAHEAD(   []    ( Reference() | IntegerLiteral())     []  ) IntegerRange()
        | Map()
        | ObjectArray()
        | True()
        | False()
        | Reference()
        | FloatingPointLiteral()
        )
    [ ]
}

/**
 * This method has yet to be fully implemented
 * but will allow arbitrarily nested method
 * calls
 */
void Method() : {/*@bgen(jjtree) Method */
  ASTMethod jjtn000 = new ASTMethod(JJTMETHOD);
  boolean jjtc000 = true;
  jjtree.openNodeScope(jjtn000);
/*@egen*/}
{/*@bgen(jjtree) Method */
   try {
/*@egen*/
   Identifier()  [ Parameter() (  Parameter() )* ] /*@bgen(jjtree)*/
   } catch (Throwable jjte000) {
     if (jjtc000) {
       jjtree.clearNodeScope(jjtn000);
       jjtc000 = false;
     } else {
       jjtree.popNode();
     }
     if (jjte000 instanceof RuntimeException) {
       throw (RuntimeException)jjte000;
     }
     if (jjte000 instanceof net.sourceforge.pmd.lang.ast.ParseException) {
       throw (net.sourceforge.pmd.lang.ast.ParseException)jjte000;
     }
     throw (Error)jjte000;
   } finally {
     if (jjtc000) {
       jjtree.closeNodeScope(jjtn000, true);
     }
   }
/*@egen*/
}


void Index() : {/*@bgen(jjtree) Index */
  ASTIndex jjtn000 = new ASTIndex(JJTINDEX);
  boolean jjtc000 = true;
  jjtree.openNodeScope(jjtn000);
/*@egen*/}
{/*@bgen(jjtree) Index */
   try {
/*@egen*/
    IndexParameter() /*@bgen(jjtree)*/
   } catch (Throwable jjte000) {
     if (jjtc000) {
       jjtree.clearNodeScope(jjtn000);
       jjtc000 = false;
     } else {
       jjtree.popNode();
     }
     if (jjte000 instanceof RuntimeException) {
       throw (RuntimeException)jjte000;
     }
     if (jjte000 instanceof net.sourceforge.pmd.lang.ast.ParseException) {
       throw (net.sourceforge.pmd.lang.ast.ParseException)jjte000;
     }
     throw (Error)jjte000;
   } finally {
     if (jjtc000) {
       jjtree.closeNodeScope(jjtn000, true);
     }
   }
/*@egen*/
}

void Reference() : {/*@bgen(jjtree) Reference */
  ASTReference jjtn000 = new ASTReference(JJTREFERENCE);
  boolean jjtc000 = true;
  jjtree.openNodeScope(jjtn000);
/*@egen*/}
{/*@bgen(jjtree) Reference */
      try {
/*@egen*/
    /*
     *  A reference is either ${} or  $
     */

      (
        (Index())*
         (LOOKAHEAD(2)  (LOOKAHEAD(3) Method() | Identifier() ) (Index())* )*
      )
      |
      (
         
          (Index())*
         (LOOKAHEAD(2)  (LOOKAHEAD(3) Method() | Identifier() ) (Index())* )*
         
      )/*@bgen(jjtree)*/
      } catch (Throwable jjte000) {
        if (jjtc000) {
          jjtree.clearNodeScope(jjtn000);
          jjtc000 = false;
        } else {
          jjtree.popNode();
        }
        if (jjte000 instanceof RuntimeException) {
          throw (RuntimeException)jjte000;
        }
        if (jjte000 instanceof net.sourceforge.pmd.lang.ast.ParseException) {
          throw (net.sourceforge.pmd.lang.ast.ParseException)jjte000;
        }
        throw (Error)jjte000;
      } finally {
        if (jjtc000) {
          jjtree.closeNodeScope(jjtn000, true);
        }
      }
/*@egen*/
}

void True() : {/*@bgen(jjtree) True */
  ASTTrue jjtn000 = new ASTTrue(JJTTRUE);
  boolean jjtc000 = true;
  jjtree.openNodeScope(jjtn000);
/*@egen*/}
{/*@bgen(jjtree) True */
    try {
/*@egen*/
    /*@bgen(jjtree)*/
    } finally {
      if (jjtc000) {
        jjtree.closeNodeScope(jjtn000, true);
      }
    }
/*@egen*/
}

void False() : {/*@bgen(jjtree) False */
  ASTFalse jjtn000 = new ASTFalse(JJTFALSE);
  boolean jjtc000 = true;
  jjtree.openNodeScope(jjtn000);
/*@egen*/}
{/*@bgen(jjtree) False */
    try {
/*@egen*/
    /*@bgen(jjtree)*/
    } finally {
      if (jjtc000) {
        jjtree.closeNodeScope(jjtn000, true);
      }
    }
/*@egen*/
}


/**
 * This is somewhat of a kludge, the problem is that the parser picks
 * up on '$[' , or '$![' as being a Reference, and does not dismiss it even though
 * there is no  between $ and [,  This has something to do
 * with the LOOKAHEAD in Reference, but I never found a way to resolve
 * it in a more fashionable way..
 */

TOKEN :
{
  
}


/**
 * This method is responsible for allowing
 * all non-grammar text to pass through
 * unscathed.
 */
void Text() : {/*@bgen(jjtree) Text */
  ASTText jjtn000 = new ASTText(JJTTEXT);
  boolean jjtc000 = true;
  jjtree.openNodeScope(jjtn000);
/*@egen*/}
{/*@bgen(jjtree) Text */
    try {
/*@egen*/
    
|   
|   
|   
|   
|   
|   
|   
|   
|   
|   /*@bgen(jjtree)*/
    } finally {
      if (jjtc000) {
        jjtree.closeNodeScope(jjtn000, true);
      }
    }
/*@egen*/
}

/* -----------------------------------------------------------------------
 *
 *  Defined Directive Syntax
 *
 * ----------------------------------------------------------------------*/

void ForeachStatement() : {/*@bgen(jjtree) ForeachStatement */
  ASTForeachStatement jjtn000 = new ASTForeachStatement(JJTFOREACHSTATEMENT);
  boolean jjtc000 = true;
  jjtree.openNodeScope(jjtn000);
/*@egen*/}
{/*@bgen(jjtree) ForeachStatement */
    try {
/*@egen*/
     []  [] Reference() []  [] PrimaryExpression() [] /*@bgen(jjtree) Block */
    {
      ASTBlock jjtn001 = new ASTBlock(JJTBLOCK);
      boolean jjtc001 = true;
      jjtree.openNodeScope(jjtn001);
    }
    try {
/*@egen*/
    ( Statement() )*/*@bgen(jjtree)*/
    } catch (Throwable jjte001) {
      if (jjtc001) {
        jjtree.clearNodeScope(jjtn001);
        jjtc001 = false;
      } else {
        jjtree.popNode();
      }
      if (jjte001 instanceof RuntimeException) {
        throw (RuntimeException)jjte001;
      }
      if (jjte001 instanceof net.sourceforge.pmd.lang.ast.ParseException) {
        throw (net.sourceforge.pmd.lang.ast.ParseException)jjte001;
      }
      throw (Error)jjte001;
    } finally {
      if (jjtc001) {
        jjtree.closeNodeScope(jjtn001, true);
      }
    }
/*@egen*/       
    /*@bgen(jjtree)*/
    } catch (Throwable jjte000) {
      if (jjtc000) {
        jjtree.clearNodeScope(jjtn000);
        jjtc000 = false;
      } else {
        jjtree.popNode();
      }
      if (jjte000 instanceof RuntimeException) {
        throw (RuntimeException)jjte000;
      }
      if (jjte000 instanceof net.sourceforge.pmd.lang.ast.ParseException) {
        throw (net.sourceforge.pmd.lang.ast.ParseException)jjte000;
      }
      throw (Error)jjte000;
    } finally {
      if (jjtc000) {
        jjtree.closeNodeScope(jjtn000, true);
      }
    }
/*@egen*/
}

void IfStatement() : {/*@bgen(jjtree) IfStatement */
  ASTIfStatement jjtn000 = new ASTIfStatement(JJTIFSTATEMENT);
  boolean jjtc000 = true;
  jjtree.openNodeScope(jjtn000);
/*@egen*/}
{/*@bgen(jjtree) IfStatement */
    try {
/*@egen*/
     []  Expression() /*@bgen(jjtree) Block */
    {
      ASTBlock jjtn001 = new ASTBlock(JJTBLOCK);
      boolean jjtc001 = true;
      jjtree.openNodeScope(jjtn001);
    }
    try {
/*@egen*/
    ( Statement() )*/*@bgen(jjtree)*/
    } catch (Throwable jjte001) {
      if (jjtc001) {
        jjtree.clearNodeScope(jjtn001);
        jjtc001 = false;
      } else {
        jjtree.popNode();
      }
      if (jjte001 instanceof RuntimeException) {
        throw (RuntimeException)jjte001;
      }
      if (jjte001 instanceof net.sourceforge.pmd.lang.ast.ParseException) {
        throw (net.sourceforge.pmd.lang.ast.ParseException)jjte001;
      }
      throw (Error)jjte001;
    } finally {
      if (jjtc001) {
        jjtree.closeNodeScope(jjtn001, true);
      }
    }
/*@egen*/       
    [ LOOKAHEAD(1) ( ElseIfStatement() )+ ]
    [ LOOKAHEAD(1) ElseStatement() ]
    /*@bgen(jjtree)*/
    } catch (Throwable jjte000) {
      if (jjtc000) {
        jjtree.clearNodeScope(jjtn000);
        jjtc000 = false;
      } else {
        jjtree.popNode();
      }
      if (jjte000 instanceof RuntimeException) {
        throw (RuntimeException)jjte000;
      }
      if (jjte000 instanceof net.sourceforge.pmd.lang.ast.ParseException) {
        throw (net.sourceforge.pmd.lang.ast.ParseException)jjte000;
      }
      throw (Error)jjte000;
    } finally {
      if (jjtc000) {
        jjtree.closeNodeScope(jjtn000, true);
      }
    }
/*@egen*/
}

void ElseStatement() : {/*@bgen(jjtree) ElseStatement */
  ASTElseStatement jjtn000 = new ASTElseStatement(JJTELSESTATEMENT);
  boolean jjtc000 = true;
  jjtree.openNodeScope(jjtn000);
/*@egen*/}
{/*@bgen(jjtree) ElseStatement */
   try {
/*@egen*/
   /*@bgen(jjtree) Block */
    {
      ASTBlock jjtn001 = new ASTBlock(JJTBLOCK);
      boolean jjtc001 = true;
      jjtree.openNodeScope(jjtn001);
    }
    try {
/*@egen*/
    ( Statement() )*/*@bgen(jjtree)*/
    } catch (Throwable jjte001) {
      if (jjtc001) {
        jjtree.clearNodeScope(jjtn001);
        jjtc001 = false;
      } else {
        jjtree.popNode();
      }
      if (jjte001 instanceof RuntimeException) {
        throw (RuntimeException)jjte001;
      }
      if (jjte001 instanceof net.sourceforge.pmd.lang.ast.ParseException) {
        throw (net.sourceforge.pmd.lang.ast.ParseException)jjte001;
      }
      throw (Error)jjte001;
    } finally {
      if (jjtc001) {
        jjtree.closeNodeScope(jjtn001, true);
      }
    }
/*@egen*/       /*@bgen(jjtree)*/
   } catch (Throwable jjte000) {
     if (jjtc000) {
       jjtree.clearNodeScope(jjtn000);
       jjtc000 = false;
     } else {
       jjtree.popNode();
     }
     if (jjte000 instanceof RuntimeException) {
       throw (RuntimeException)jjte000;
     }
     if (jjte000 instanceof net.sourceforge.pmd.lang.ast.ParseException) {
       throw (net.sourceforge.pmd.lang.ast.ParseException)jjte000;
     }
     throw (Error)jjte000;
   } finally {
     if (jjtc000) {
       jjtree.closeNodeScope(jjtn000, true);
     }
   }
/*@egen*/
}

void ElseIfStatement() : {/*@bgen(jjtree) ElseIfStatement */
  ASTElseIfStatement jjtn000 = new ASTElseIfStatement(JJTELSEIFSTATEMENT);
  boolean jjtc000 = true;
  jjtree.openNodeScope(jjtn000);
/*@egen*/}
{/*@bgen(jjtree) ElseIfStatement */
    try {
/*@egen*/
     []
     Expression() /*@bgen(jjtree) Block */
    {
      ASTBlock jjtn001 = new ASTBlock(JJTBLOCK);
      boolean jjtc001 = true;
      jjtree.openNodeScope(jjtn001);
    }
    try {
/*@egen*/
    ( Statement() )*/*@bgen(jjtree)*/
    } catch (Throwable jjte001) {
      if (jjtc001) {
        jjtree.clearNodeScope(jjtn001);
        jjtc001 = false;
      } else {
        jjtree.popNode();
      }
      if (jjte001 instanceof RuntimeException) {
        throw (RuntimeException)jjte001;
      }
      if (jjte001 instanceof net.sourceforge.pmd.lang.ast.ParseException) {
        throw (net.sourceforge.pmd.lang.ast.ParseException)jjte001;
      }
      throw (Error)jjte001;
    } finally {
      if (jjtc001) {
        jjtree.closeNodeScope(jjtn001, true);
      }
    }
/*@egen*/       /*@bgen(jjtree)*/
    } catch (Throwable jjte000) {
      if (jjtc000) {
        jjtree.clearNodeScope(jjtn000);
        jjtc000 = false;
      } else {
        jjtree.popNode();
      }
      if (jjte000 instanceof RuntimeException) {
        throw (RuntimeException)jjte000;
      }
      if (jjte000 instanceof net.sourceforge.pmd.lang.ast.ParseException) {
        throw (net.sourceforge.pmd.lang.ast.ParseException)jjte000;
      }
      throw (Error)jjte000;
    } finally {
      if (jjtc000) {
        jjtree.closeNodeScope(jjtn000, true);
      }
    }
/*@egen*/
}

/**
 *  Currently support both types of set :
 *   #set( expr )
 *   #set expr
 */
void SetDirective() : {/*@bgen(jjtree) SetDirective */
  ASTSetDirective jjtn000 = new ASTSetDirective(JJTSETDIRECTIVE);
  boolean jjtc000 = true;
  jjtree.openNodeScope(jjtn000);
/*@egen*/}
{/*@bgen(jjtree) SetDirective */
    try {
/*@egen*/
    ([] Reference() []   Expression() 
    {
        /*
         * ensure that inSet is false.  Leads to some amusing bugs...
         */

        token_source.inSet = false;
    }
    [] )/*@bgen(jjtree)*/
    } catch (Throwable jjte000) {
      if (jjtc000) {
        jjtree.clearNodeScope(jjtn000);
        jjtc000 = false;
      } else {
        jjtree.popNode();
      }
      if (jjte000 instanceof RuntimeException) {
        throw (RuntimeException)jjte000;
      }
      if (jjte000 instanceof net.sourceforge.pmd.lang.ast.ParseException) {
        throw (net.sourceforge.pmd.lang.ast.ParseException)jjte000;
      }
      throw (Error)jjte000;
    } finally {
      if (jjtc000) {
        jjtree.closeNodeScope(jjtn000, true);
      }
    }
/*@egen*/
}

/* -----------------------------------------------------------------------
 *
 *  Expression Syntax
 *
 * ----------------------------------------------------------------------*/

void Expression() : {/*@bgen(jjtree) Expression */
  ASTExpression jjtn000 = new ASTExpression(JJTEXPRESSION);
  boolean jjtc000 = true;
  jjtree.openNodeScope(jjtn000);
/*@egen*/}
{/*@bgen(jjtree) Expression */
try {
/*@egen*/
//    LOOKAHEAD( PrimaryExpression()   ) Assignment()
//|
ConditionalOrExpression()/*@bgen(jjtree)*/
} catch (Throwable jjte000) {
  if (jjtc000) {
    jjtree.clearNodeScope(jjtn000);
    jjtc000 = false;
  } else {
    jjtree.popNode();
  }
  if (jjte000 instanceof RuntimeException) {
    throw (RuntimeException)jjte000;
  }
  if (jjte000 instanceof net.sourceforge.pmd.lang.ast.ParseException) {
    throw (net.sourceforge.pmd.lang.ast.ParseException)jjte000;
  }
  throw (Error)jjte000;
} finally {
  if (jjtc000) {
    jjtree.closeNodeScope(jjtn000, true);
  }
}
/*@egen*/
}

void Assignment()                : {/*@bgen(jjtree) #Assignment( 2) */
  ASTAssignment jjtn000 = new ASTAssignment(JJTASSIGNMENT);
  boolean jjtc000 = true;
  jjtree.openNodeScope(jjtn000);
/*@egen*/}
{/*@bgen(jjtree) #Assignment( 2) */
    try {
/*@egen*/
    PrimaryExpression()   Expression()/*@bgen(jjtree)*/
    } catch (Throwable jjte000) {
      if (jjtc000) {
        jjtree.clearNodeScope(jjtn000);
        jjtc000 = false;
      } else {
        jjtree.popNode();
      }
      if (jjte000 instanceof RuntimeException) {
        throw (RuntimeException)jjte000;
      }
      if (jjte000 instanceof net.sourceforge.pmd.lang.ast.ParseException) {
        throw (net.sourceforge.pmd.lang.ast.ParseException)jjte000;
      }
      throw (Error)jjte000;
    } finally {
      if (jjtc000) {
        jjtree.closeNodeScope(jjtn000,  2);
      }
    }
/*@egen*/
}

void ConditionalOrExpression()       : {}
{
  ConditionalAndExpression()
  (  /*@bgen(jjtree) #OrNode( 2) */
                   {
                     ASTOrNode jjtn001 = new ASTOrNode(JJTORNODE);
                     boolean jjtc001 = true;
                     jjtree.openNodeScope(jjtn001);
                   }
                   try {
/*@egen*/  ConditionalAndExpression()/*@bgen(jjtree)*/
                   } catch (Throwable jjte001) {
                     if (jjtc001) {
                       jjtree.clearNodeScope(jjtn001);
                       jjtc001 = false;
                     } else {
                       jjtree.popNode();
                     }
                     if (jjte001 instanceof RuntimeException) {
                       throw (RuntimeException)jjte001;
                     }
                     if (jjte001 instanceof net.sourceforge.pmd.lang.ast.ParseException) {
                       throw (net.sourceforge.pmd.lang.ast.ParseException)jjte001;
                     }
                     throw (Error)jjte001;
                   } finally {
                     if (jjtc001) {
                       jjtree.closeNodeScope(jjtn001,  2);
                     }
                   }
/*@egen*/            )*
}


void ConditionalAndExpression()       : {}
{
  EqualityExpression()
  ( /*@bgen(jjtree) #AndNode( 2) */
                  {
                    ASTAndNode jjtn001 = new ASTAndNode(JJTANDNODE);
                    boolean jjtc001 = true;
                    jjtree.openNodeScope(jjtn001);
                  }
                  try {
/*@egen*/ EqualityExpression()/*@bgen(jjtree)*/
                  } catch (Throwable jjte001) {
                    if (jjtc001) {
                      jjtree.clearNodeScope(jjtn001);
                      jjtc001 = false;
                    } else {
                      jjtree.popNode();
                    }
                    if (jjte001 instanceof RuntimeException) {
                      throw (RuntimeException)jjte001;
                    }
                    if (jjte001 instanceof net.sourceforge.pmd.lang.ast.ParseException) {
                      throw (net.sourceforge.pmd.lang.ast.ParseException)jjte001;
                    }
                    throw (Error)jjte001;
                  } finally {
                    if (jjtc001) {
                      jjtree.closeNodeScope(jjtn001,  2);
                    }
                  }
/*@egen*/             )*
}

void EqualityExpression()       : {}
{
    RelationalExpression()
    (
       /*@bgen(jjtree) #EQNode( 2) */
                        {
                          ASTEQNode jjtn001 = new ASTEQNode(JJTEQNODE);
                          boolean jjtc001 = true;
                          jjtree.openNodeScope(jjtn001);
                        }
                        try {
/*@egen*/ RelationalExpression()/*@bgen(jjtree)*/
                        } catch (Throwable jjte001) {
                          if (jjtc001) {
                            jjtree.clearNodeScope(jjtn001);
                            jjtc001 = false;
                          } else {
                            jjtree.popNode();
                          }
                          if (jjte001 instanceof RuntimeException) {
                            throw (RuntimeException)jjte001;
                          }
                          if (jjte001 instanceof net.sourceforge.pmd.lang.ast.ParseException) {
                            throw (net.sourceforge.pmd.lang.ast.ParseException)jjte001;
                          }
                          throw (Error)jjte001;
                        } finally {
                          if (jjtc001) {
                            jjtree.closeNodeScope(jjtn001,  2);
                          }
                        }
/*@egen*/               
     | /*@bgen(jjtree) #NENode( 2) */
                            {
                              ASTNENode jjtn002 = new ASTNENode(JJTNENODE);
                              boolean jjtc002 = true;
                              jjtree.openNodeScope(jjtn002);
                            }
                            try {
/*@egen*/ RelationalExpression()/*@bgen(jjtree)*/
                            } catch (Throwable jjte002) {
                              if (jjtc002) {
                                jjtree.clearNodeScope(jjtn002);
                                jjtc002 = false;
                              } else {
                                jjtree.popNode();
                              }
                              if (jjte002 instanceof RuntimeException) {
                                throw (RuntimeException)jjte002;
                              }
                              if (jjte002 instanceof net.sourceforge.pmd.lang.ast.ParseException) {
                                throw (net.sourceforge.pmd.lang.ast.ParseException)jjte002;
                              }
                              throw (Error)jjte002;
                            } finally {
                              if (jjtc002) {
                                jjtree.closeNodeScope(jjtn002,  2);
                              }
                            }
/*@egen*/           
    )*
}

void RelationalExpression()       : {}
{
    AdditiveExpression()
    (
        /*@bgen(jjtree) #LTNode( 2) */
                      {
                        ASTLTNode jjtn001 = new ASTLTNode(JJTLTNODE);
                        boolean jjtc001 = true;
                        jjtree.openNodeScope(jjtn001);
                      }
                      try {
/*@egen*/  AdditiveExpression()/*@bgen(jjtree)*/
                      } catch (Throwable jjte001) {
                        if (jjtc001) {
                          jjtree.clearNodeScope(jjtn001);
                          jjtc001 = false;
                        } else {
                          jjtree.popNode();
                        }
                        if (jjte001 instanceof RuntimeException) {
                          throw (RuntimeException)jjte001;
                        }
                        if (jjte001 instanceof net.sourceforge.pmd.lang.ast.ParseException) {
                          throw (net.sourceforge.pmd.lang.ast.ParseException)jjte001;
                        }
                        throw (Error)jjte001;
                      } finally {
                        if (jjtc001) {
                          jjtree.closeNodeScope(jjtn001,  2);
                        }
                      }
/*@egen*/           
      | /*@bgen(jjtree) #GTNode( 2) */
                      {
                        ASTGTNode jjtn002 = new ASTGTNode(JJTGTNODE);
                        boolean jjtc002 = true;
                        jjtree.openNodeScope(jjtn002);
                      }
                      try {
/*@egen*/  AdditiveExpression()/*@bgen(jjtree)*/
                      } catch (Throwable jjte002) {
                        if (jjtc002) {
                          jjtree.clearNodeScope(jjtn002);
                          jjtc002 = false;
                        } else {
                          jjtree.popNode();
                        }
                        if (jjte002 instanceof RuntimeException) {
                          throw (RuntimeException)jjte002;
                        }
                        if (jjte002 instanceof net.sourceforge.pmd.lang.ast.ParseException) {
                          throw (net.sourceforge.pmd.lang.ast.ParseException)jjte002;
                        }
                        throw (Error)jjte002;
                      } finally {
                        if (jjtc002) {
                          jjtree.closeNodeScope(jjtn002,  2);
                        }
                      }
/*@egen*/           
      | /*@bgen(jjtree) #LENode( 2) */
                      {
                        ASTLENode jjtn003 = new ASTLENode(JJTLENODE);
                        boolean jjtc003 = true;
                        jjtree.openNodeScope(jjtn003);
                      }
                      try {
/*@egen*/  AdditiveExpression()/*@bgen(jjtree)*/
                      } catch (Throwable jjte003) {
                        if (jjtc003) {
                          jjtree.clearNodeScope(jjtn003);
                          jjtc003 = false;
                        } else {
                          jjtree.popNode();
                        }
                        if (jjte003 instanceof RuntimeException) {
                          throw (RuntimeException)jjte003;
                        }
                        if (jjte003 instanceof net.sourceforge.pmd.lang.ast.ParseException) {
                          throw (net.sourceforge.pmd.lang.ast.ParseException)jjte003;
                        }
                        throw (Error)jjte003;
                      } finally {
                        if (jjtc003) {
                          jjtree.closeNodeScope(jjtn003,  2);
                        }
                      }
/*@egen*/           
      | /*@bgen(jjtree) #GENode( 2) */
                      {
                        ASTGENode jjtn004 = new ASTGENode(JJTGENODE);
                        boolean jjtc004 = true;
                        jjtree.openNodeScope(jjtn004);
                      }
                      try {
/*@egen*/  AdditiveExpression()/*@bgen(jjtree)*/
                      } catch (Throwable jjte004) {
                        if (jjtc004) {
                          jjtree.clearNodeScope(jjtn004);
                          jjtc004 = false;
                        } else {
                          jjtree.popNode();
                        }
                        if (jjte004 instanceof RuntimeException) {
                          throw (RuntimeException)jjte004;
                        }
                        if (jjte004 instanceof net.sourceforge.pmd.lang.ast.ParseException) {
                          throw (net.sourceforge.pmd.lang.ast.ParseException)jjte004;
                        }
                        throw (Error)jjte004;
                      } finally {
                        if (jjtc004) {
                          jjtree.closeNodeScope(jjtn004,  2);
                        }
                      }
/*@egen*/           
    )*
}

void AdditiveExpression()       : {}
{
    MultiplicativeExpression()
    (
        /*@bgen(jjtree) #AddNode( 2) */
                {
                  ASTAddNode jjtn001 = new ASTAddNode(JJTADDNODE);
                  boolean jjtc001 = true;
                  jjtree.openNodeScope(jjtn001);
                }
                try {
/*@egen*/  MultiplicativeExpression()/*@bgen(jjtree)*/
                } catch (Throwable jjte001) {
                  if (jjtc001) {
                    jjtree.clearNodeScope(jjtn001);
                    jjtc001 = false;
                  } else {
                    jjtree.popNode();
                  }
                  if (jjte001 instanceof RuntimeException) {
                    throw (RuntimeException)jjte001;
                  }
                  if (jjte001 instanceof net.sourceforge.pmd.lang.ast.ParseException) {
                    throw (net.sourceforge.pmd.lang.ast.ParseException)jjte001;
                  }
                  throw (Error)jjte001;
                } finally {
                  if (jjtc001) {
                    jjtree.closeNodeScope(jjtn001,  2);
                  }
                }
/*@egen*/            
      | /*@bgen(jjtree) #SubtractNode( 2) */
                {
                  ASTSubtractNode jjtn002 = new ASTSubtractNode(JJTSUBTRACTNODE);
                  boolean jjtc002 = true;
                  jjtree.openNodeScope(jjtn002);
                }
                try {
/*@egen*/ MultiplicativeExpression()/*@bgen(jjtree)*/
                } catch (Throwable jjte002) {
                  if (jjtc002) {
                    jjtree.clearNodeScope(jjtn002);
                    jjtc002 = false;
                  } else {
                    jjtree.popNode();
                  }
                  if (jjte002 instanceof RuntimeException) {
                    throw (RuntimeException)jjte002;
                  }
                  if (jjte002 instanceof net.sourceforge.pmd.lang.ast.ParseException) {
                    throw (net.sourceforge.pmd.lang.ast.ParseException)jjte002;
                  }
                  throw (Error)jjte002;
                } finally {
                  if (jjtc002) {
                    jjtree.closeNodeScope(jjtn002,  2);
                  }
                }
/*@egen*/                 
    )*
}

void MultiplicativeExpression()       : {}
{
    UnaryExpression()
    (
            /*@bgen(jjtree) #MulNode( 2) */
                        {
                          ASTMulNode jjtn001 = new ASTMulNode(JJTMULNODE);
                          boolean jjtc001 = true;
                          jjtree.openNodeScope(jjtn001);
                        }
                        try {
/*@egen*/  UnaryExpression()/*@bgen(jjtree)*/
                        } catch (Throwable jjte001) {
                          if (jjtc001) {
                            jjtree.clearNodeScope(jjtn001);
                            jjtc001 = false;
                          } else {
                            jjtree.popNode();
                          }
                          if (jjte001 instanceof RuntimeException) {
                            throw (RuntimeException)jjte001;
                          }
                          if (jjte001 instanceof net.sourceforge.pmd.lang.ast.ParseException) {
                            throw (net.sourceforge.pmd.lang.ast.ParseException)jjte001;
                          }
                          throw (Error)jjte001;
                        } finally {
                          if (jjtc001) {
                            jjtree.closeNodeScope(jjtn001,  2);
                          }
                        }
/*@egen*/            
          | /*@bgen(jjtree) #DivNode( 2) */
                      {
                        ASTDivNode jjtn002 = new ASTDivNode(JJTDIVNODE);
                        boolean jjtc002 = true;
                        jjtree.openNodeScope(jjtn002);
                      }
                      try {
/*@egen*/  UnaryExpression()/*@bgen(jjtree)*/
                      } catch (Throwable jjte002) {
                        if (jjtc002) {
                          jjtree.clearNodeScope(jjtn002);
                          jjtc002 = false;
                        } else {
                          jjtree.popNode();
                        }
                        if (jjte002 instanceof RuntimeException) {
                          throw (RuntimeException)jjte002;
                        }
                        if (jjte002 instanceof net.sourceforge.pmd.lang.ast.ParseException) {
                          throw (net.sourceforge.pmd.lang.ast.ParseException)jjte002;
                        }
                        throw (Error)jjte002;
                      } finally {
                        if (jjtc002) {
                          jjtree.closeNodeScope(jjtn002,  2);
                        }
                      }
/*@egen*/            
          | /*@bgen(jjtree) #ModNode( 2) */
                       {
                         ASTModNode jjtn003 = new ASTModNode(JJTMODNODE);
                         boolean jjtc003 = true;
                         jjtree.openNodeScope(jjtn003);
                       }
                       try {
/*@egen*/  UnaryExpression()/*@bgen(jjtree)*/
                       } catch (Throwable jjte003) {
                         if (jjtc003) {
                           jjtree.clearNodeScope(jjtn003);
                           jjtc003 = false;
                         } else {
                           jjtree.popNode();
                         }
                         if (jjte003 instanceof RuntimeException) {
                           throw (RuntimeException)jjte003;
                         }
                         if (jjte003 instanceof net.sourceforge.pmd.lang.ast.ParseException) {
                           throw (net.sourceforge.pmd.lang.ast.ParseException)jjte003;
                         }
                         throw (Error)jjte003;
                       } finally {
                         if (jjtc003) {
                           jjtree.closeNodeScope(jjtn003,  2);
                         }
                       }
/*@egen*/            
    )*
}

void UnaryExpression()       : {}
{
     LOOKAHEAD(2)  []  /*@bgen(jjtree) #NotNode( 1) */
                                                  {
                                                    ASTNotNode jjtn001 = new ASTNotNode(JJTNOTNODE);
                                                    boolean jjtc001 = true;
                                                    jjtree.openNodeScope(jjtn001);
                                                  }
                                                  try {
/*@egen*/  UnaryExpression()/*@bgen(jjtree)*/
                                                  } catch (Throwable jjte001) {
                                                    if (jjtc001) {
                                                      jjtree.clearNodeScope(jjtn001);
                                                      jjtc001 = false;
                                                    } else {
                                                      jjtree.popNode();
                                                    }
                                                    if (jjte001 instanceof RuntimeException) {
                                                      throw (RuntimeException)jjte001;
                                                    }
                                                    if (jjte001 instanceof net.sourceforge.pmd.lang.ast.ParseException) {
                                                      throw (net.sourceforge.pmd.lang.ast.ParseException)jjte001;
                                                    }
                                                    throw (Error)jjte001;
                                                  } finally {
                                                    if (jjtc001) {
                                                      jjtree.closeNodeScope(jjtn001,  1);
                                                    }
                                                  }
/*@egen*/            
|   PrimaryExpression()
}

void PrimaryExpression()       : {}
{
    []
    (
     StringLiteral()
    | Reference()
    | IntegerLiteral()
    | LOOKAHEAD(   []    ( Reference() | IntegerLiteral())     []  ) IntegerRange()
    | FloatingPointLiteral()
    | Map()
    | ObjectArray()
    | True()
    | False()
    |   Expression()  
     )
    []
}


/* ======================================================================

   Notes
   -----

    template == the input stream for this parser, contains 'VTL'
    mixed in with 'schmoo'

    VTL == Velocity Template Language : the references, directives, etc

    schmoo == the non-VTL component of a template

    reference == VTL entity that represents data within the context. ex. $foo

    directive == VTL entity that denotes 'action' (#set, #foreach, #if )

    defined directive (DD) == VTL directive entity that is expressed
    explicitly w/in this grammar

    pluggable directive (PD) == VTL directive entity that is defined outside of the
    grammar.  PD's allow VTL to be easily expandable w/o parser modification.

    The problem with parsing VTL is that an input stream consists generally of
    little bits of VTL mixed in with 'other stuff, referred to as 'schmoo'.
    Unlike other languages, like C or Java, where the parser can punt whenever
    it encounters input that doesn't conform to the grammar, the VTL parser can't do
    that. It must simply output the schmoo and keep going.

    There are a few things that we do here :
     - define a set of parser states (DEFAULT, DIRECTIVE, REFERENCE, etc)
     - define for each parser state a set of tokens for each state
     - define the VTL grammar, expressed (mostly) in the productions such as Text(),
     SetStatement(), etc.

    It is clear that this expression of the VTL grammar (the contents
    of this .jjt file) is maturing and evolving as we learn more about
    how to parse VTL ( and as I learn about parsing...), so in the event
    this documentation is in disagreement w/ the source, the source
    takes precedence. :)

    Parser States
    -------------
    DEFAULT :  This is the base or starting state, and strangely enough, the
    default state.

    PRE_DIRECTIVE : State immediately following '#' before we figure out which
    defined or pluggable directive (or neither) we are working with.

    DIRECTIVE : This state is triggered by the a match of a DD or a PD.

    REFERENCE : Triggered by '$'. Analagous to PRE_DIRECTIVE.

    REFMODIFIER : Triggered by . when in REFERENCE.

    REFMOD2 : Triggered by ( when in REFMODIFIER

    (cont)

    Escape Sequences
    ----------------
    The escape processing in VTL is very simple.  The '\' character acts
    only as an escape when :

        1) On or more touch a VTL element.

    A VTL element is either :

        1) It preceeds a reference that is in the context.

        2) It preceeds a defined directive (#set, #if, #end, etc) or a valid
        pluggable directive, such as #foreach

    In all other cases the '\' is just another piece of text.  The purpose of this
    is to allow the non-VTL parts of a template (the 'schmoo') to not have to be
    altered for processing by Velocity.

    So if in the context $foo and $bar were defined and $woogie was not

        \$foo  \$bar \$woogie

    would output

        $foo  $bar  \$woogie

    Further, you can stack them and they affect left to right, just like convention
    escape characters in other languages.

        \$foo = $foo
        \\$foo = \
        \\\$foo = \$foo


    What You Expect
    ---------------
    The recent versions of the parser are trying to support precise output to
    support general template use. The directives do not render trailing
    whitespace and newlines if followed by a newline.  They will render
    preceding whitespace. The only exception is #set, which also eats
    preceding whitespace.

    So, with a template :

        ------
        #set $foo="foo"
        #if($foo)
        \$foo = $foo
        #end
        ------

    it will render precisely :

        ------
        $foo = foo
        ------

*/





© 2015 - 2024 Weber Informatics LLC | Privacy Policy