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

org.drools.compiler.semantics.java.parser.Java.g Maven / Gradle / Ivy

The newest version!
/**
 * 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.
 */

/** A Java 1.5 grammar for ANTLR v3 derived from the spec
 *
 *  This is a very close representation of the spec; the changes
 *  are comestic (remove left recursion) and also fixes (the spec
 *  isn't exactly perfect).  I have run this on the 1.4.2 source
 *  and some nasty looking enums from 1.5, but have not really
 *  tested for 1.5 compatibility.
 *
 *  I built this with: java -Xmx100M org.antlr.Tool java.g 
 *  and got two errors that are ok (for now):
 *  java.g:691:9: Decision can match input such as
 *    "'0'..'9'{'E', 'e'}{'+', '-'}'0'..'9'{'D', 'F', 'd', 'f'}"
 *    using multiple alternatives: 3, 4
 *  As a result, alternative(s) 4 were disabled for that input
 *  java.g:734:35: Decision can match input such as "{'$', 'A'..'Z',
 *    '_', 'a'..'z', '\u00C0'..'\u00D6', '\u00D8'..'\u00F6',
 *    '\u00F8'..'\u1FFF', '\u3040'..'\u318F', '\u3300'..'\u337F',
 *    '\u3400'..'\u3D2D', '\u4E00'..'\u9FFF', '\uF900'..'\uFAFF'}"
 *    using multiple alternatives: 1, 2
 *  As a result, alternative(s) 2 were disabled for that input
 *
 *  You can turn enum on/off as a keyword :)
 *
 *  Version 1.0 -- initial release July 5, 2006 (requires 3.0b2 or higher)
 *
 *  Primary author: Terence Parr, July 2006
 *
 *  Version 1.0.1 -- corrections by Koen Vanderkimpen & Marko van Dooren,
 *      October 25, 2006;
 *      fixed normalInterfaceDeclaration: now uses typeParameters instead
 *          of typeParameter (according to JLS, 3rd edition)
 *      fixed castExpression: no longer allows expression next to type
 *          (according to semantics in JLS, in contrast with syntax in JLS)
 *
 *  Version 1.0.2 -- Terence Parr, Nov 27, 2006
 *      java spec I built this from had some bizarre for-loop control.
 *          Looked weird and so I looked elsewhere...Yep, it's messed up.
 *          simplified.
 *
 *  Version 1.0.3 -- Chris Hogue, Feb 26, 2007
 *      Factored out an annotationName rule and used it in the annotation rule.
 *          Not sure why, but typeName wasn't recognizing references to inner
 *       	`1111111   annotations (e.g. @InterfaceName.InnerAnnotation())
 *      Factored out the elementValue section of an annotation reference.  Created 
 *          elementValuePair and elementValuePairs rules, then used them in the 
 *          annotation rule.  Allows it to recognize annotation references with 
 *          multiple, comma separated attributes.
 *      Updated elementValueArrayInitializer so that it allows multiple elements.
 *          (It was only allowing 0 or 1 element).
 *      Updated localVariableDeclaration to allow annotations.  Interestingly the JLS
 *          doesn't appear to indicate this is legal, but it does work as of at least
 *          JDK 1.5.0_06.
 *      Moved the Identifier portion of annotationTypeElementRest to annotationMethodRest.
 *          Because annotationConstantRest already references variableDeclarator which 
 *          has the Identifier portion in it, the parser would fail on constants in 
 *          annotation definitions because it expected two identifiers.  
 *      Added optional trailing ';' to the alternatives in annotationTypeElementRest.
 *          Wouldn't handle an inner interface that has a trailing ';'.
 *      Swapped the expression and type rule reference order in castExpression to 
 *          make it check for genericized casts first.  It was failing to recognize a
 *          statement like  "Class TYPE = (Class)...;" because it was seeing
 *          'Class'.
 *      Changed createdName to use typeArguments instead of nonWildcardTypeArguments.
 *          Again, JLS doesn't seem to allow this, but java.lang.Class has an example of
 *          of this construct.
 *      Changed the 'this' alternative in primary to allow 'identifierSuffix' rather than
 *          just 'arguments'.  The case it couldn't handle was a call to an explicit
 *          generic method invocation (e.g. this.doSomething()).  Using identifierSuffix
 *          may be overly aggressive--perhaps should create a more constrained thisSuffix rule?
 * 		
 *  Version 1.0.4 -- Hiroaki Nakamura, May 3, 2007
 *
 *	Fixed formalParameterDecls, localVariableDeclaration, forInit,
 *	and forVarControl to use variableModifier* not 'final'? (annotation)?
 */
grammar Java;
options {k=2; backtrack=true; memoize=true;}

scope VarDecl {
    org.drools.compiler.rule.builder.dialect.java.parser.JavaLocalDeclarationDescr descr;
}
 
@parser::header {
    package org.drools.compiler.rule.builder.dialect.java.parser;
    import java.util.Iterator;
    import java.util.Queue;
    import java.util.LinkedList;
    import java.util.Stack;
    import java.util.Set;
    import java.util.HashSet;
    import java.util.Collections;

    import org.drools.compiler.rule.builder.dialect.java.parser.JavaLocalDeclarationDescr;
    import org.drools.compiler.rule.builder.dialect.java.parser.JavaRootBlockDescr;
    import org.drools.compiler.rule.builder.dialect.java.parser.JavaContainerBlockDescr;
    import org.drools.compiler.rule.builder.dialect.java.parser.JavaBlockDescr;
    
}

@parser::members {
    private Set identifiers = new HashSet();
    public Set getIdentifiers() { return identifiers; }

    private Stack> localDeclarationsStack = new Stack>(); 
    { localDeclarationsStack.push( new ArrayList() ); }
    private int localVariableLevel = 0;

    public static final CommonToken IGNORE_TOKEN = new CommonToken(null,0,99,0,0);
    private List errors = new ArrayList();
    
        private JavaRootBlockDescr rootBlockDescr = new JavaRootBlockDescr();
        private LinkedList blocks;
        private Set assignedVariables;

        public void addBlockDescr(JavaBlockDescr blockDescr) {
            if ( this.blocks == null ) {
                this.blocks = new LinkedList();
                this.blocks.add( this.rootBlockDescr );
            }
            blocks.getLast().addJavaBlockDescr( blockDescr );
        }

        public void addAssignment(String variable) {
            if ( this.assignedVariables == null ) {
                this.assignedVariables = new HashSet();
            }
            this.assignedVariables.add( variable );
        }

            public void pushContainerBlockDescr(JavaContainerBlockDescr blockDescr, boolean addToParent) {
                if ( addToParent ) {
                    addBlockDescr(blockDescr);
                }
                blocks.add( blockDescr );
            }      
            
            public void popContainerBlockDescr() {
                blocks.removeLast( );
            }          
        
        public JavaRootBlockDescr getRootBlockDescr() { return rootBlockDescr; }

        public Set getAssignedVariables() { return assignedVariables != null ? assignedVariables : Collections.emptySet(); }

    private String source = "unknown";

    public void setSource(String source) {
        this.source = source;
    }

    public String getSource() {
        return this.source;
    }

    public void reportError(RecognitionException ex) {
            // if we've already reported an error and have not matched a token
                // yet successfully, don't report any errors.
                if ( state.errorRecovery ) {
                        //System.err.print("[SPURIOUS] ");
                        return;
                }
                state.errorRecovery = true;

        errors.add( ex );
    }

         /** return the raw RecognitionException errors */
         public List getErrors() {
             return errors;
         }

         /** Return a list of pretty strings summarising the errors */
         public List getErrorMessages() {
             List messages = new ArrayList();
         for ( Iterator errorIter = errors.iterator() ; errorIter.hasNext() ; ) {
                      messages.add( createErrorMessage( (RecognitionException) errorIter.next() ) );
                  }
                  return messages;
         }

         /** return true if any parser errors were accumulated */
         public boolean hasErrors() {
          return ! errors.isEmpty();
         }

         /** This will take a RecognitionException, and create a sensible error message out of it */
         public String createErrorMessage(RecognitionException e)
        {
        StringBuilder message = new StringBuilder();
                message.append( source + ":"+e.line+":"+e.charPositionInLine+" ");
                if ( e instanceof MismatchedTokenException ) {
                        MismatchedTokenException mte = (MismatchedTokenException)e;
                        message.append("mismatched token: "+
                                                           e.token+
                                                           "; expecting type "+
                                                           tokenNames[mte.expecting]);
                }
                else if ( e instanceof MismatchedTreeNodeException ) {
                        MismatchedTreeNodeException mtne = (MismatchedTreeNodeException)e;
                        message.append("mismatched tree node: "+
                                                           mtne.node+
                                                           "; expecting type "+
                                                           tokenNames[mtne.expecting]);
                }
                else if ( e instanceof NoViableAltException ) {
                        NoViableAltException nvae = (NoViableAltException)e;
            message.append( "Unexpected token '" + e.token.getText() + "'" );
                        /*
                        message.append("decision=<<"+nvae.grammarDecisionDescription+">>"+
                                                           " state "+nvae.stateNumber+
                                                           " (decision="+nvae.decisionNumber+
                                                           ") no viable alt; token="+
                                                           e.token);
                                                           */
                }
                else if ( e instanceof EarlyExitException ) {
                        EarlyExitException eee = (EarlyExitException)e;
                        message.append("required (...)+ loop (decision="+
                                                           eee.decisionNumber+
                                                           ") did not match anything; token="+
                                                           e.token);
                }
                else if ( e instanceof MismatchedSetException ) {
                        MismatchedSetException mse = (MismatchedSetException)e;
                        message.append("mismatched token '"+
                                                           e.token+
                                                           "' expecting set "+mse.expecting);
                }
                else if ( e instanceof MismatchedNotSetException ) {
                        MismatchedNotSetException mse = (MismatchedNotSetException)e;
                        message.append("mismatched token '"+
                                                           e.token+
                                                           "' expecting set "+mse.expecting);
                }
                else if ( e instanceof FailedPredicateException ) {
                        FailedPredicateException fpe = (FailedPredicateException)e;
                        message.append("rule "+fpe.ruleName+" failed predicate: {"+
                                                           fpe.predicateText+"}?");
        }
                   return message.toString();
        }   
        
        public void increaseLevel() {
            this.localVariableLevel++;
            localDeclarationsStack.push( new ArrayList() );
        }
        
        public void decreaseLevel() {
            this.localVariableLevel--;
            localDeclarationsStack.pop();
        }
        
        public void addLocalDeclaration( JavaLocalDeclarationDescr decl ) {
            localDeclarationsStack.peek().add(decl);
        }

        public List getLocalDeclarations() { 
            if( localDeclarationsStack.size() > 1 ) {
                List decls = new ArrayList();
                for( List local : localDeclarationsStack ) {
                    decls.addAll( local );
                }
                return decls;
            }
            // the stack should never be empty, so it is safe to do a peek() here
            return new ArrayList( localDeclarationsStack.peek() ); 
        }
} 

@lexer::header {
    package org.drools.compiler.rule.builder.dialect.java.parser;
}

@lexer::members {
    public static final CommonToken IGNORE_TOKEN = new CommonToken(null,0,99,0,0);
    protected boolean enumIsKeyword = true;
}
 

// starting point for parsing a java file
compilationUnit
    :	annotations?
        packageDeclaration?
        importDeclaration*
        typeDeclaration*
    ;

packageDeclaration
    :	'package' qualifiedName ';'
    ;

importDeclaration
    :	'import' 'static'? Identifier ('.' Identifier)* ('.' '*')? ';'
    ;

typeDeclaration
    :	classOrInterfaceDeclaration
    |   ';'
    ;

classOrInterfaceDeclaration
    :	modifier* (classDeclaration | interfaceDeclaration)
    ;

classDeclaration
    :	normalClassDeclaration
    |   enumDeclaration
    ;

normalClassDeclaration
    :	'class' Identifier (typeParameters)?
        ('extends' type)?
        ('implements' typeList)?
        classBody
    ;

typeParameters
    :	'<' typeParameter (',' typeParameter)* '>'
    ;

typeParameter
    :	Identifier ('extends' bound)?
    ;

bound
    :	type ('&' type)*
    ;

enumDeclaration
    :	ENUM Identifier ('implements' typeList)? enumBody
    ;

enumBody
    :	'{' enumConstants? ','? enumBodyDeclarations? '}'
    ;

enumConstants
    :	enumConstant (',' enumConstant)*
    ;

enumConstant
    :	annotations? Identifier (arguments)? (classBody)?
    ;

enumBodyDeclarations
    :	';' (classBodyDeclaration)*
    ;

interfaceDeclaration
    :	normalInterfaceDeclaration
        | annotationTypeDeclaration
    ;

normalInterfaceDeclaration
    :	'interface' Identifier typeParameters? ('extends' typeList)? interfaceBody
    ;

typeList
    :	type (',' type)*
    ;

classBody
    :	'{' classBodyDeclaration* '}'
    ;

interfaceBody
    :	'{' interfaceBodyDeclaration* '}'
    ;

classBodyDeclaration
    :	';'
    |	'static'? block
    |	modifier* memberDecl
    ;

memberDecl
    :	genericMethodOrConstructorDecl
    |	methodDeclaration
    |	fieldDeclaration
    |	'void' Identifier voidMethodDeclaratorRest
    |	Identifier constructorDeclaratorRest
    |	interfaceDeclaration
    |	classDeclaration
    ;

genericMethodOrConstructorDecl
    :	typeParameters genericMethodOrConstructorRest
    ;

genericMethodOrConstructorRest
    :	(type | 'void') Identifier methodDeclaratorRest
    |	Identifier constructorDeclaratorRest
    ;

methodDeclaration
scope VarDecl;
    :	type Identifier methodDeclaratorRest
    ;

fieldDeclaration
    :	type variableDeclarators ';'
    ;

interfaceBodyDeclaration
    :	modifier* interfaceMemberDecl
    |   ';'
    ;

interfaceMemberDecl
    :	interfaceMethodOrFieldDecl
    |   interfaceGenericMethodDecl
    |   'void' Identifier voidInterfaceMethodDeclaratorRest
    |   interfaceDeclaration
    |   classDeclaration
    ;

interfaceMethodOrFieldDecl
    :	type Identifier interfaceMethodOrFieldRest
    ;

interfaceMethodOrFieldRest
    :	constantDeclaratorsRest ';'
    |	interfaceMethodDeclaratorRest
    ;

methodDeclaratorRest
    :	formalParameters ('[' ']')*
        ('throws' qualifiedNameList)?
        (   methodBody
        |   ';'
        )
    ;

voidMethodDeclaratorRest
    :	formalParameters ('throws' qualifiedNameList)?
        (   methodBody
        |   ';'
        )
    ;

interfaceMethodDeclaratorRest
    :	formalParameters ('[' ']')* ('throws' qualifiedNameList)? ';'
    ;

interfaceGenericMethodDecl
    :	typeParameters (type | 'void') Identifier
        interfaceMethodDeclaratorRest
    ;

voidInterfaceMethodDeclaratorRest
    :	formalParameters ('throws' qualifiedNameList)? ';'
    ;

constructorDeclaratorRest
    :	formalParameters ('throws' qualifiedNameList)? methodBody
    ;

constantDeclarator
    :	Identifier constantDeclaratorRest
    ;

variableDeclarators
    :	variableDeclarator (',' variableDeclarator)*
    ;

variableDeclarator
    scope {
        JavaLocalDeclarationDescr.IdentifierDescr ident;
    }
    @init {
        $variableDeclarator::ident = new JavaLocalDeclarationDescr.IdentifierDescr();
    }
    @after {
            if( $VarDecl::descr != null ) {
                $VarDecl::descr.addIdentifier( $variableDeclarator::ident );
            }
    }
    :	id=Identifier rest=variableDeclaratorRest
        {
            $variableDeclarator::ident.setIdentifier( $id.text );
            $variableDeclarator::ident.setStart( ((CommonToken)$id).getStartIndex() - 1 );
            if( $rest.stop != null ) {
                   $variableDeclarator::ident.setEnd( ((CommonToken)$rest.stop).getStopIndex() );
            }
        }
    ;

variableDeclaratorRest
    :	('[' ']')+ ('=' variableInitializer)?
    |	'=' variableInitializer
    |
    ;

constantDeclaratorsRest
    :   constantDeclaratorRest (',' constantDeclarator)*
    ;

constantDeclaratorRest
    :	('[' ']')* '=' variableInitializer
    ;

variableDeclaratorId
    :	Identifier ('[' ']')*
    ;

variableInitializer
    :	arrayInitializer
    |   expression
    ;

arrayInitializer
    :	'{' (variableInitializer (',' variableInitializer)* (',')? )? '}'
    ;

modifier
    :   annotation
    |   'public'
    |   'protected'
    |   'private'
    |   'static'
    |   'abstract'
    |   'final'
    |   'native'
    |   'synchronized'
    |   'transient'
    |   'volatile'
    |   'strictfp'
    ;

packageOrTypeName
    :	Identifier ('.' Identifier)*
    ;

enumConstantName
    :   Identifier
    ;

typeName
    :   Identifier
    |   packageOrTypeName '.' Identifier
    ;

type
    :	Identifier (typeArguments)? ('.' Identifier (typeArguments)? )* ('[' ']')*
    |	primitiveType ('[' ']')*
    ;

primitiveType
    :   'boolean'
    |	'char'
    |	'byte'
    |	'short'
    |	'int'
    |	'long'
    |	'float'
    |	'double'
    ;

variableModifier
    :	'final'
    |   annotation
    ;

typeArguments
    :	'<' typeArgument (',' typeArgument)* '>'
    ;

typeArgument
    :	type
    |	'?' (('extends' | 'super') type)?
    ;

qualifiedNameList
    :	qualifiedName (',' qualifiedName)*
    ;

formalParameters
    :	'(' formalParameterDecls? ')'
    ;

formalParameterDecls
    :	variableModifier* type formalParameterDeclsRest?
    ;

formalParameterDeclsRest
    :	variableDeclaratorId (',' formalParameterDecls)?
    |   '...' variableDeclaratorId
    ;

methodBody
    :	block
    ;

qualifiedName
    :	Identifier ('.' Identifier)*
    ;

literal	
    :   integerLiteral
    |   FloatingPointLiteral
    |   CharacterLiteral
    |   StringLiteral
    |   booleanLiteral
    |   'null'
    ;

integerLiteral
    :   HexLiteral
    |   OctalLiteral
    |   DecimalLiteral
    ;

booleanLiteral
    :   'true'
    |   'false'
    ;

// ANNOTATIONS

annotations
    :	annotation+
    ;

annotation
    :	'@' annotationName ('(' elementValuePairs? ')')?
    ;

annotationName
    : Identifier ('.' Identifier)*
    ;

elementValuePairs
    : elementValuePair (',' elementValuePair)*
    ;

elementValuePair
    : (Identifier '=')? elementValue
    ;

elementValue
    :	conditionalExpression
    |   annotation
    |   elementValueArrayInitializer
    ;

elementValueArrayInitializer
    :	'{' (elementValue (',' elementValue )*)? '}'
    ;

annotationTypeDeclaration
    :	'@' 'interface' Identifier annotationTypeBody
    ;

annotationTypeBody
    :	'{' (annotationTypeElementDeclarations)? '}'
    ;

annotationTypeElementDeclarations
    :	(annotationTypeElementDeclaration) (annotationTypeElementDeclaration)*
    ;

annotationTypeElementDeclaration
    :	(modifier)* annotationTypeElementRest
    ;

annotationTypeElementRest
    :	type annotationMethodOrConstantRest ';'
    |   classDeclaration ';'?
    |   interfaceDeclaration ';'?
    |   enumDeclaration ';'?
    |   annotationTypeDeclaration ';'?
    ;

annotationMethodOrConstantRest
    :	annotationMethodRest
    |   annotationConstantRest
    ;

annotationMethodRest
     :	Identifier '(' ')' (defaultValue)?
     ;

annotationConstantRest
scope VarDecl;
     :	variableDeclarators
     ;

defaultValue
     :	'default' elementValue
     ;

// STATEMENTS / BLOCKS

block
        @init {
            increaseLevel();
        }
        @after {
            if( localVariableLevel <= 1 ) {
                // this is the top level block, so set the top level declarations
                rootBlockDescr.setInScopeLocalVars( getLocalDeclarations() );
            }
            decreaseLevel();
        }
    :	'{' blockStatement* '}'
    ;

blockStatement
    :	localVariableDeclaration
    |	classOrInterfaceDeclaration
        |	statement
    ;

localVariableDeclaration
scope VarDecl;
        @init {
            $VarDecl::descr = new JavaLocalDeclarationDescr();
        }
        @after {
            addLocalDeclaration( $VarDecl::descr );
        }
    :
    ( variableModifier
        {
            $VarDecl::descr.updateStart( ((CommonToken)$variableModifier.start).getStartIndex() - 1 );
            $VarDecl::descr.addModifier( $variableModifier.text );
        }
    )*
    type
        {
            $VarDecl::descr.updateStart( ((CommonToken)$type.start).getStartIndex() - 1 );
            $VarDecl::descr.setType( $type.text );
            $VarDecl::descr.setEnd( ((CommonToken)$type.stop).getStopIndex() );
        }
    variableDeclarators ';'
    ;

statement
    : block
    | 'assert' expression (':' expression)? ';'
    | ifStatement
    | forStatement //'for' '(' forControl ')' statement
    | whileStatement//'while' parExpression statement
    | 'do' statement 'while' parExpression ';'
    
    | tryStatement
      
    | 'switch' parExpression '{' switchBlockStatementGroups '}'
    | 'synchronized' parExpression block
    | 'return' expression? ';'
    |  throwStatement
    | 'break' Identifier? ';'
    | 'continue' Identifier? ';'
    // adding support to drools modify block
    | modifyStatement | updateStatement | retractStatement | deleteStatement | insertStatement
    | ';'
    | statementExpression ';'
    | Identifier ':' statement
    ;
    

throwStatement
    @init {
        JavaThrowBlockDescr d = null;
    }
    : s='throw'
    expression
    c = ';'
        {
        d = new JavaThrowBlockDescr( );
        d.setStart( ((CommonToken)$s).getStartIndex() );
        d.setTextStart( ((CommonToken)$expression.start).getStartIndex() );        
        this.addBlockDescr( d );
        d.setEnd( ((CommonToken)$c).getStopIndex() ); 
        }
    ;
    
ifStatement
    @init {
         JavaIfBlockDescr id = null;
         JavaElseBlockDescr ed = null;         
    }
    :     
    //    | 'if' parExpression statement (options {k=1;}:'else' statement)?
    s='if' parExpression
    {
        increaseLevel();
        id = new JavaIfBlockDescr();
        id.setStart( ((CommonToken)$s).getStartIndex() );  pushContainerBlockDescr(id, true); 
    }    
    x=statement 
    {
        decreaseLevel();
        id.setTextStart(((CommonToken)$x.start).getStartIndex() );
        id.setEnd(((CommonToken)$x.stop).getStopIndex() ); popContainerBlockDescr(); 
    }
    
    (
     y='else'  ('if' parExpression )?
    {
        increaseLevel();
        ed = new JavaElseBlockDescr();
        ed.setStart( ((CommonToken)$y).getStartIndex() );  pushContainerBlockDescr(ed, true); 
    }             
     z=statement
    {
        decreaseLevel();
        ed.setTextStart(((CommonToken)$z.start).getStartIndex() );
        ed.setEnd(((CommonToken)$z.stop).getStopIndex() ); popContainerBlockDescr();               
    })*       
    ;      
       
forStatement
options {k=3;}
scope VarDecl;
    @init {
         JavaForBlockDescr fd = null;
         increaseLevel();
         $VarDecl::descr = new JavaLocalDeclarationDescr();
    }
    @after {
         addLocalDeclaration( $VarDecl::descr );
         decreaseLevel();
    }
    : 
    x='for' y='('
    {   fd = new JavaForBlockDescr( ); 
        fd.setStart( ((CommonToken)$x).getStartIndex() ); pushContainerBlockDescr(fd, true);    
        fd.setStartParen( ((CommonToken)$y).getStartIndex() );            
    }      
    (    
        ( ( variableModifier
            {
                $VarDecl::descr.updateStart( ((CommonToken)$variableModifier.start).getStartIndex() - 1 );
                $VarDecl::descr.addModifier( $variableModifier.text );
            }
          )*
          type
          {
            $VarDecl::descr.updateStart( ((CommonToken)$type.start).getStartIndex() - 1 );
            $VarDecl::descr.setType( $type.text );
            $VarDecl::descr.setEnd( ((CommonToken)$type.stop).getStopIndex() );
          }
          id=Identifier 
          {
            JavaLocalDeclarationDescr.IdentifierDescr ident = new JavaLocalDeclarationDescr.IdentifierDescr();
            ident.setIdentifier( $id.text );
            ident.setStart( ((CommonToken)$id).getStartIndex() - 1 );
            ident.setEnd( ((CommonToken)$id).getStopIndex() );
            $VarDecl::descr.addIdentifier( ident );
          }
          z=':' expression
          {
             fd.setInitEnd( ((CommonToken)$z).getStartIndex() );        
          })
        |  
        (forInit? z=';' expression? ';' forUpdate?        
         {
             fd.setInitEnd( ((CommonToken)$z).getStartIndex() );        
          })

    
      )    
     ')' bs=statement
    {                
        fd.setTextStart(((CommonToken)$bs.start).getStartIndex() );
        fd.setEnd(((CommonToken)$bs.stop).getStopIndex() ); popContainerBlockDescr();     
    }
    ;       

whileStatement
    @init {
         JavaWhileBlockDescr wd = null;         
    }
    :         
    // 'while' parExpression statement    
    s='while' parExpression 
    {   wd = new JavaWhileBlockDescr( ); wd.setStart( ((CommonToken)$s).getStartIndex() ); pushContainerBlockDescr(wd, true);    
    } 
    bs= statement
    {                
        wd.setTextStart(((CommonToken)$bs.start).getStartIndex() );
        wd.setEnd(((CommonToken)$bs.stop).getStopIndex() ); popContainerBlockDescr();     
    }    
    ;  
    
tryStatement
    @init {
         JavaTryBlockDescr td = null;
         JavaCatchBlockDescr cd = null;
         JavaFinalBlockDescr fd = null;
         
    }
    :     
    s='try' 
    {   increaseLevel();
        td = new JavaTryBlockDescr( ); td.setStart( ((CommonToken)$s).getStartIndex() ); pushContainerBlockDescr(td, true);    
    } bs='{' blockStatement*
    {
                
        td.setTextStart( ((CommonToken)$bs).getStartIndex() );        

    } c='}' {td.setEnd( ((CommonToken)$c).getStopIndex() ); decreaseLevel(); popContainerBlockDescr();    }
    
 
    (s='catch' '(' formalParameter ')' 
     {  increaseLevel();
        cd = new JavaCatchBlockDescr( $formalParameter.text );
        cd.setClauseStart( ((CommonToken)$formalParameter.start).getStartIndex() ); 
        cd.setStart( ((CommonToken)$s).getStartIndex() );  pushContainerBlockDescr(cd, false);
     } bs='{' blockStatement*
     { 
        cd.setTextStart( ((CommonToken)$bs).getStartIndex() );
        td.addCatch( cd );        
     }  c='}' {cd.setEnd( ((CommonToken)$c).getStopIndex() ); decreaseLevel(); popContainerBlockDescr(); } )* 
     
     
     
     (s='finally' 
     {  increaseLevel();
        fd = new JavaFinalBlockDescr( ); fd.setStart( ((CommonToken)$s).getStartIndex() ); pushContainerBlockDescr(fd, false);
     } bs='{' blockStatement*
      {
        fd.setTextStart( ((CommonToken)$bs).getStartIndex() );        
        td.setFinally( fd );         
      }  c='}' {fd.setEnd( ((CommonToken)$c).getStopIndex() ); decreaseLevel(); popContainerBlockDescr(); } )?     
    ;    

modifyStatement
    @init {
        JavaModifyBlockDescr d = null;
    }
    : s='modify' parExpression
    {
        d = new JavaModifyBlockDescr( $parExpression.text );
        d.setStart( ((CommonToken)$s).getStartIndex() );
        d.setInScopeLocalVars( getLocalDeclarations() );
        this.addBlockDescr( d );

    }
    '{' ( e = expression { d.getExpressions().add( $e.text ); }
           (',' e=expression { d.getExpressions().add( $e.text ); } )*
        )?
    c='}'
        {
            d.setEnd( ((CommonToken)$c).getStopIndex() ); 
        }
    ;

updateStatement
    : s='update' '('
    expression
    c = ')'
        {
        JavaStatementBlockDescr d = new JavaStatementBlockDescr( $expression.text, JavaBlockDescr.BlockType.UPDATE );
        d.setStart( ((CommonToken)$s).getStartIndex() );
        this.addBlockDescr( d );
        d.setEnd( ((CommonToken)$c).getStopIndex() ); 
        }
    ;
    
retractStatement
    : s='retract' '('
    expression
    c = ')'
        {	
        JavaStatementBlockDescr d = new JavaStatementBlockDescr( $expression.text, JavaBlockDescr.BlockType.DELETE );
        d.setStart( ((CommonToken)$s).getStartIndex() );
        this.addBlockDescr( d );
        d.setEnd( ((CommonToken)$c).getStopIndex() );
    }
    ;

deleteStatement
    : s='delete' '('
    expression
    c = ')'
        {
        JavaStatementBlockDescr d = new JavaStatementBlockDescr( $expression.text, JavaBlockDescr.BlockType.DELETE );
        d.setStart( ((CommonToken)$s).getStartIndex() );
        this.addBlockDescr( d );
        d.setEnd( ((CommonToken)$c).getStopIndex() );
    }
    ;

insertStatement
    : s='insert' '('
    expression
    c = ')'
        {
        JavaStatementBlockDescr d = new JavaStatementBlockDescr( $expression.text, JavaBlockDescr.BlockType.INSERT );
        d.setStart( ((CommonToken)$s).getStartIndex() );
        this.addBlockDescr( d );
        d.setEnd( ((CommonToken)$c).getStopIndex() );
    }
    ;

epStatement
    @init {
        JavaInterfacePointsDescr d = null;
    }
        : 
        ( s='exitPoints' '[' id=StringLiteral c=']' 
        {
            d = new JavaInterfacePointsDescr( $id.text );
            d.setType( JavaBlockDescr.BlockType.EXIT );
            d.setStart( ((CommonToken)$s).getStartIndex() );
            d.setEnd( ((CommonToken)$c).getStopIndex() ); 
            this.addBlockDescr( d );
        }
        |  s='entryPoints' '[' id=StringLiteral c=']' 
        {
            d = new JavaInterfacePointsDescr( $id.text );
            d.setType( JavaBlockDescr.BlockType.ENTRY );
            d.setStart( ((CommonToken)$s).getStartIndex() );
            d.setEnd( ((CommonToken)$c).getStopIndex() ); 
            this.addBlockDescr( d );
        }
        |  s='channels' '[' id=StringLiteral c=']' 
        {
            d = new JavaInterfacePointsDescr( $id.text );
            d.setType( JavaBlockDescr.BlockType.CHANNEL );
            d.setStart( ((CommonToken)$s).getStartIndex() );
            d.setEnd( ((CommonToken)$c).getStopIndex() ); 
            this.addBlockDescr( d );
        }
        ) 
        ;	

formalParameter
    :	variableModifier* type variableDeclaratorId
    ;

switchBlockStatementGroups
    :	(switchBlockStatementGroup)*
    ;

switchBlockStatementGroup
    :	switchLabel blockStatement*
    ;

switchLabel
    :	'case' constantExpression ':'
    |   'case' enumConstantName ':'
    |   'default' ':'
    ;

moreStatementExpressions
    :	(',' statementExpression)*
    ;

forControl
options {k=3;} // be efficient for common case: for (ID ID : ID) ...
scope VarDecl;
        @init {
            increaseLevel();
            $VarDecl::descr = new JavaLocalDeclarationDescr();
        }
        @after {
            addLocalDeclaration( $VarDecl::descr );
            decreaseLevel();
        }
    :	forVarControl
    |	forInit? ';' expression? ';' forUpdate?
    ;

forInit
    :	( variableModifier
            {
                $VarDecl::descr.updateStart( ((CommonToken)$variableModifier.start).getStartIndex() - 1 );
                $VarDecl::descr.addModifier( $variableModifier.text );
            }
        )*
        type
        {
            $VarDecl::descr.updateStart( ((CommonToken)$type.start).getStartIndex() - 1 );
            $VarDecl::descr.setType( $type.text );
            $VarDecl::descr.setEnd( ((CommonToken)$type.stop).getStopIndex() );
        }
        variableDeclarators
    |	expressionList
    ;

forVarControl
    :	( variableModifier
            {
                $VarDecl::descr.updateStart( ((CommonToken)$variableModifier.start).getStartIndex() - 1 );
                $VarDecl::descr.addModifier( $variableModifier.text );
            }
        )*
        type
        {
            $VarDecl::descr.updateStart( ((CommonToken)$type.start).getStartIndex() - 1 );
            $VarDecl::descr.setType( $type.text );
            $VarDecl::descr.setEnd( ((CommonToken)$type.stop).getStopIndex() );
        }
        id=Identifier 
        {
            JavaLocalDeclarationDescr.IdentifierDescr ident = new JavaLocalDeclarationDescr.IdentifierDescr();
            ident.setIdentifier( $id.text );
            ident.setStart( ((CommonToken)$id).getStartIndex() - 1 );
            ident.setEnd( ((CommonToken)$id).getStopIndex() );
            $VarDecl::descr.addIdentifier( ident );
        }
        ':' expression
    ;

forUpdate
    :	expressionList
    ;

// EXPRESSIONS

parExpression
    :	'(' expression ')'
    ;

expressionList
    :   expression (',' expression)*
    ;

statementExpression
    :	expression
    ;

constantExpression
    :	expression
    ;

expression
    :	assignmentExpression
    |   conditionalExpression (assignmentOperator expression)?
    ;

assignmentExpression
    :	id=conditionalExpression '=' expression
        {
            this.addAssignment( $id.text );
        }
    ;

assignmentOperator
    :	'+='
    |   '-='
    |   '*='
    |   '/='
    |   '&='
    |   '|='
    |   '^='
    |   '%='
    |   '<' '<' '='
    |   '>' '>' '='
    |   '>' '>' '>' '='
    ;

conditionalExpression
    :   conditionalOrExpression ( '?' expression ':' expression )?
    ;

conditionalOrExpression
    :   conditionalAndExpression ( '||' conditionalAndExpression )*
    ;

conditionalAndExpression
    :   inclusiveOrExpression ( '&&' inclusiveOrExpression )*
    ;

inclusiveOrExpression
    :   exclusiveOrExpression ( '|' exclusiveOrExpression )*
    ;

exclusiveOrExpression
    :   andExpression ( '^' andExpression )*
    ;

andExpression
    :   equalityExpression ( '&' equalityExpression )*
    ;

equalityExpression
    :   instanceOfExpression ( ('==' | '!=') instanceOfExpression )*
    ;

instanceOfExpression
    :   relationalExpression ('instanceof' type)?
    ;

relationalExpression
    :   shiftExpression ( relationalOp shiftExpression )*
    ;

relationalOp
    :	('<' '=' | '>' '=' | '<' | '>')
    ;

shiftExpression
    :   additiveExpression ( shiftOp additiveExpression )*
    ;

        // TODO: need a sem pred to check column on these >>>
shiftOp
    :	('<' '<' | '>' '>' '>' | '>' '>')
    ;


additiveExpression
    :   multiplicativeExpression ( ('+' | '-') multiplicativeExpression )*
    ;

multiplicativeExpression
    :   unaryExpression ( ( '*' | '/' | '%' ) unaryExpression )*
    ;

unaryExpression
    :   '+' unaryExpression
    |	'-' unaryExpression
    |   '++' primary
    |   '--' primary
    |   unaryExpressionNotPlusMinus
    ;

unaryExpressionNotPlusMinus
    :   '~' unaryExpression
    | 	'!' unaryExpression
    |   castExpression
    |   primary selector* ('++'|'--')?
    ;

castExpression
    :  '(' primitiveType ')' unaryExpression
    |  '(' (type | expression) ')' unaryExpressionNotPlusMinus
    ;

primary
    :	parExpression
    |   nonWildcardTypeArguments
        (explicitGenericInvocationSuffix | 'this' arguments)
    |   'this' ('.' Identifier)* (identifierSuffix)?
    |   'super' superSuffix
    |   epStatement ('.' methodName)* (identifierSuffix)?
    |   literal
    |   'new' creator
    |   i=Identifier { if( ! "(".equals( input.LT(1) == null ? "" : input.LT(1).getText() ) ) identifiers.add( $i.text );  } ('.' methodName)* (identifierSuffix)?
    |   primitiveType ('[' ']')* '.' 'class'
    |   'void' '.' 'class'
    ;

methodName
    : Identifier | 'insert' | 'update' | 'modify' | 'retract' | 'delete'
    ;

identifierSuffix
    :	('[' ']')+ '.' 'class'
    |	('[' expression ']')+ // can also be matched by selector, but do here
    |   arguments
    |   '.' 'class'
    |   '.' explicitGenericInvocation
    |   '.' 'this'
    |   '.' 'super' arguments
    |   '.' 'new' (nonWildcardTypeArguments)? innerCreator
    ;

creator
    :	nonWildcardTypeArguments? createdName
        (arrayCreatorRest | classCreatorRest)
    ;

createdName
    :	Identifier typeArguments?
        ('.' Identifier typeArguments?)*
    |	primitiveType
    ;

innerCreator
    :	Identifier classCreatorRest
    ;

arrayCreatorRest
    :	'['
        (   ']' ('[' ']')* arrayInitializer
        |   expression ']' ('[' expression ']')* ('[' ']')*
        )
    ;

classCreatorRest
    :	arguments classBody?
    ;

explicitGenericInvocation
    :	nonWildcardTypeArguments explicitGenericInvocationSuffix
    ;

nonWildcardTypeArguments
    :	'<' typeList '>'
    ;

explicitGenericInvocationSuffix
    :	'super' superSuffix
    |   Identifier arguments
    ;

selector
    :	'.' methodName (arguments)?
    |   '.' 'this'
    |   '.' 'super' superSuffix
    |   '.' 'new' (nonWildcardTypeArguments)? innerCreator
    |   '[' expression ']'
    ;

superSuffix
    :	arguments
    |   '.' Identifier (arguments)?
    ;
    
    arguments
    :	'(' expressionList? ')'
    ;

// LEXER

HexLiteral : '0' ('x'|'X') HexDigit+ IntegerTypeSuffix? ;

DecimalLiteral : ('0' | NonZeroDigit (Digits? | Underscores Digits)) IntegerTypeSuffix? ;

OctalLiteral : '0' ('0'..'7')+ IntegerTypeSuffix? ;

fragment
HexDigit : ('0'..'9'|'a'..'f'|'A'..'F') ;

fragment
IntegerTypeSuffix : ('l'|'L') ;

FloatingPointLiteral
    :   Digits '.' Digits? Exponent? FloatTypeSuffix?
    |   '.' Digits Exponent? FloatTypeSuffix?
    |   Digits Exponent FloatTypeSuffix?
    |   Digits Exponent? FloatTypeSuffix
    ;

fragment
Digits: Digit (DigitOrUnderscore* Digit)? ;

fragment
Digit: '0' | NonZeroDigit ;

fragment
NonZeroDigit: ('1'..'9') ;

fragment
DigitOrUnderscore: Digit | '_' ;

fragment
Underscores: '_'+ ;

fragment
Exponent : ('e'|'E') ('+'|'-')? ('0'..'9')+ ;

fragment
FloatTypeSuffix : ('f'|'F'|'d'|'D') ;

CharacterLiteral
    :   '\'' ( EscapeSequence | ~('\''|'\\') ) '\''
    ;

StringLiteral
    :  '"' ( EscapeSequence | ~('\\'|'"') )* '"'
    ;

fragment
EscapeSequence
    :   '\\' ('b'|'t'|'n'|'f'|'r'|'\"'|'\''|'\\')
    |   UnicodeEscape
    |   OctalEscape
    ;

fragment
OctalEscape
    :   '\\' ('0'..'3') ('0'..'7') ('0'..'7')
    |   '\\' ('0'..'7') ('0'..'7')
    |   '\\' ('0'..'7')
    ;

fragment
UnicodeEscape
    :   '\\' 'u' HexDigit HexDigit HexDigit HexDigit
    ;

ENUM:	'enum' {if ( !enumIsKeyword ) $type=Identifier;}
    ;

Identifier
	:	JavaLetter JavaLetterOrDigit*
	;

fragment
JavaLetter
	:	('a'..'z'|'A'..'Z'|'$'|'_')
	|   {Character.isJavaIdentifierStart(input.LA(1))}?
	    ~('\u0000'..'\u007F' | '\uD800'..'\uDBFF')
    |   {Character.isJavaIdentifierStart(Character.toCodePoint((char)input.LA(-1), (char)input.LA(1)))}?
        ('\uD800'..'\uDBFF') ('\uDC00'..'\uDFFF')
	;

fragment
JavaLetterOrDigit
	:	('a'..'z'|'A'..'Z'|'0'..'9'|'$'|'_')
    |   {Character.isJavaIdentifierPart(input.LA(1))}?
        ~('\u0000'..'\u007F' | '\uD800'..'\uDBFF')
    |   {Character.isJavaIdentifierPart(Character.toCodePoint((char)input.LA(-1), (char)input.LA(1)))}?
        ('\uD800'..'\uDBFF') ('\uDC00'..'\uDFFF')
    ;


WS  :  (' '|'\r'|'\t'|'\u000C'|'\n') {$channel=HIDDEN;}
    ;

COMMENT
    :   '/*' ( options {greedy=false;} : . )* '*/' {$channel=HIDDEN;}
    ;

LINE_COMMENT
    : '//' ~('\n'|'\r')* '\r'? '\n' {$channel=HIDDEN;}
    ;




© 2015 - 2024 Weber Informatics LLC | Privacy Policy