Java 1.5 Parser - Grammar Rules - Part 6

<- back

Next Chapter Grammar Rules - part 7

Annotations

Examples of Annotations:

@Override
@Deprecated
@Documented
@Edible(true)
@Author(first = "Oscar", last = "Wild")
@Target({ElementType.TYPE,ElementType.METHOD,
 ElementType.CONSTRUCTOR,ElementType.ANNOTATION_TYPE,
 ElementType.PACKAGE,ElementType.FIELD,ElementType.LOCAL_VARIABLE})

The Java symtax for annotation is

Java Syntax Rule
Annotations:
Annotation [Annotations]

Annotation:
@ TypeName [( [Identifier =] ElementValue)]

ElementValue:
ConditionalExpression
Annotation
ElementValueArrayInitializer

This is not totally correct. The above rules would not allow the annotation:
@MethodLevelAnnotationB(arg1="val1", arg2="val2").

How do the Java Specification define annotations? Consider the Chapter 9.7 Annotations

Java Syntax Rule
Annotations:
Annotation
Annotations Annotation

Annotation:
NormalAnnotation
MarkerAnnotation
SingleElementAnnotation

MarkerAnnotation:
@ TypeName

SingleElementAnnotation:
@ TypeName ( ElementValue )

NormalAnnotation:
@ TypeName ( ElementValuePairsopt )

ElementValuePairs:
ElementValuePair
ElementValuePairs , ElementValuePair

ElementValuePair:
Identifier = ElementValue

ElementValue:
ConditionalExpression
Annotation
ElementValueArrayInitializer

From Chapter 6.5 Determining the Meaning of a Name the TypeName definition reside

Java Syntax Rule
TypeName:
Identifier
PackageOrTypeName . Identifier

PackageOrTypeName:
Identifier
PackageOrTypeName . Identifier

The syntax should be rewritten to

Java Syntax Rule
Annotations:
Annotation [Annotations]

Annotation:
@ TypeName [( ElementValuePairsopt )]

ElementValuePairs:
ElementValuePair
ElementValuePairs , ElementValuePair

ElementValuePair:
[Identifier =] ElementValue

ElementValue:
ConditionalExpression
Annotation
ElementValueArrayInitializer

The above rules may be translated to Coco/R grammar

Coco/R EBFN Rule
PRODUCTIONS

Annotations =
Annotation {Annotation}.

Annotation =
AtSign QualifiedIdentifier [ LeftParenthesis [ElementValuePairs] RightParenthesis ].

ElementValuePairs =
ElementValuePair {Comma ElementValuePair}.

ElementValuePair =
[Identifier Assignment] ElementValue.

ElementValue =
ConditionalExpression |
Annotation |
ElementValueArrayInitializer.

Compiling the above rules will display two errors

checking
  Java15 deletable
  No production for ConditionalExpression
  No production for ElementValueArrayInitializer
2 errors detected

ConditionalExpression and ElementValueArrayInitializer need definitions

One observations is that Annotations could be removed and merged into Java15

Coco/R EBFN Rule
PRODUCTIONS

Java15 =
[{Annotation} Package

ElementValueArrayInitializer

Java Syntax Rule
ElementValueArrayInitializer:
{ [ElementValues] [,] }

ElementValues:
ElementValue [ElementValues]

The above rules does not looks correct. Compare with the rules in Java Language Specification 9.7 Annotations. ElementValues should contain a comma between the ElementValue elements.

Java Syntax Rule
ElementValueArrayInitializer:
{ ElementValuesopt ,opt }

ElementValues:
ElementValue
ElementValues , ElementValue

The above rules may be translated to Coco/R grammar

Coco/R EBFN Rule
PRODUCTIONS

ElementValueArrayInitializer =
LeftCurlyBrace ElementValues [Comma] RightCurlyBrace.

ElementValues =
ElementValue {Comma ElementValue}.

Compiling the above rules displays the following error

checking
  Java15 deletable
  No production for ConditionalExpression
1 errors detected

The Dummy ConditionalExpression

To be able to test the new added rules a dummy ConditionalExpression is created:

Coco/R EBFN Rule
PRODUCTIONS

ConditionalExpression =
Identifier.

Compiling gives

checking
  Java15 deletable
parser generated
0 errors detected

AST for Annotation

UML Class diagram

These are the classes that will represent annotation.

sourceFile_annotation_a.png

Update SourceFile

SourceFile must be updated to include annotation in front of the package statement.

org.structuredparsing.java15grammar.ast.ISourceFile:

package org.structuredparsing.java15grammar.ast;
 
import java.util.List;
 
public interface ISourceFile {
   public List< IAnnotationElement > getAnnotations();
   public IQualifiedIdentifier getPackageContent();
   public List< IImportStatement > getImportList();
}

org.structuredparsing.java15grammar.ast.SourceFile:

package org.structuredparsing.java15grammar.ast;
 
import java.util.ArrayList;
import java.util.List;
 
public class SourceFile implements ISourceFile {
 
   private List< IAnnotation > annotationList;
   private IQualifiedIdentifier packageContent;
   private List< IImportStatement > importList;
 
   public SourceFile() {
      annotationList = new ArrayList< IAnnotation >();
      importList = new ArrayList< IImportStatement >();
   }
 
   public void addAnnotation( IAnnotation annotation ) {
      annotationList.add( annotation );
   }
 
   @Override
   public List< IAnnotation > getAnnotations() {
      return annotationList;
   }
 
   @Override
   public IQualifiedIdentifier getPackageContent() {
      return this.packageContent;
   }
 
   public void setPacakgeContent( QualifiedIdentifier packageContent ) {
      this.packageContent = packageContent;
   }
 
   @Override
   public List< IImportStatement > getImportList() {
      return this.importList;
   }
 
   public void addImportContent( IImportStatement importContent ) {
      importList.add( importContent );
   }
}

Annotation

The Annotation class contains one annotation.

org.structuredparsing.java15grammar.ast.IAnnotation:

package org.structuredparsing.java15grammar.ast;
 
import java.util.List;
 
public interface IAnnotation {
   public IQualifiedIdentifier getQualifiedIdentifier();
   public List< IElementValuePair > getElementValuePairs();
}

org.structuredparsing.java15grammar.ast.Annotation:

package org.structuredparsing.java15grammar.ast;
 
import java.util.ArrayList;
import java.util.List;
 
public class Annotation implements IAnnotation {
   private QualifiedIdentifier qualifiedIdentifier;
   private List< IElementValuePair > elementValuePairElementList;
 
   public Annotation() {
      elementValuePairElementList = new ArrayList< IElementValuePair >();
   }
 
   public void setQualifiedIdentifier( QualifiedIdentifier qualifiedIdentifier ) {
      this.qualifiedIdentifier = qualifiedIdentifier;
   }
 
   @Override
   public QualifiedIdentifier getQualifiedIdentifier() {
      return qualifiedIdentifier;
   }
 
   public void addElementValuePair( IElementValuePair elementValuePairElement ) {
      elementValuePairElementList.add( elementValuePairElement );
   }
 
   @Override
   public List< IElementValuePair > getElementValuePairs() {
      return elementValuePairElementList;
   }
}

ElementValuePair

Annotations consist of one or several ElementValuePair.

org.structuredparsing.java15grammar.ast.IElementValuePair:

package org.structuredparsing.java15grammar.ast;
 
public interface IElementValuePair {
   public String getIdentifier();
   public IElementValue getElementValue();
}

org.structuredparsing.java15grammar.ast.ElementValuePair:

package org.structuredparsing.java15grammar.ast;
 
public class ElementValuePair implements IElementValuePair {
   private String sIdentifier;
   private IElementValue elementValue;
 
   public void setIdentifier( String sIdentifier ) {
      this.sIdentifier = sIdentifier;
   }
 
   @Override
   public String getIdentifier() {
      return sIdentifier;
   }
 
   public void setElementValue( IElementValue elementValue ) {
      this.elementValue = elementValue;
   }
 
   @Override
   public IElementValue getElementValue() {
      return elementValue;
   }
}

ElementValue

Each ElementValuePair contains one ElementValue. An element value may be a conditional expression or an annotation or a an array of ElementValue.

org.structuredparsing.java15grammar.ast.IElementValue:

package org.structuredparsing.java15grammar.ast;
 
import java.util.List;
 
public interface IElementValue {
   // IExpression, IAnnotation, List< IElementValue >
   public Object getElementValueContent();
}

org.structuredparsing.java15grammar.ast.ElementValue:

package org.structuredparsing.java15grammar.ast;
 
import java.util.ArrayList;
import java.util.List;
 
public class ElementValue implements IElementValue {
   private IExpression expression;
   private IAnnotation annotation;
   private List< IElementValue > elementValueArrayInitializerList;
 
   public void setExpression( IExpression expression ) {
      this.expression = expression;
      annotation = null;
      elementValueArrayInitializerList = null;
   }
 
   @Override
   public Object getElementValueContent() {
      if ( this.expression != null ) {
         return this.expression;
      }
      else if ( this.annotation != null ) {
         return this.annotation;
      }
      return this.elementValueArrayInitializerList;
   }
 
   public void setAnnotation( IAnnotation annotation ) {
      expression = null;
      this.annotation = annotation;
      elementValueArrayInitializerList = null;
   }
 
   public void addElementValue( IElementValue elementValue ) {
      if ( elementValueArrayInitializerList == null ) {
         expression = null;
         annotation = null;
         elementValueArrayInitializerList = new ArrayList< IElementValue >();
      }
      elementValueArrayInitializerList.add( elementValue );
   }
}

IExpression

org.structuredparsing.java15grammar.ast.IExpression:

package org.structuredparsing.java15grammar.ast;
 
public interface IExpression {
}

Update QualifiedIdentifier

QualifiedIdentifier is updated and also now implements IExpression. IExpression does not have any methods, so this means that a QualifiedIdentifier now also may be included as an expression (in Annotaions, for example).

public class QualifiedIdentifier implements IQualifiedIdentifier, IExpression { ... }

The Dummy LiteralExpression

This class, LiteralExpression will change in the future. And unittests that contains LiteralExpression will be affected, but that is a hit we must take.

org.structuredparsing.java15grammar.ast.LITERAL:

package org.structuredparsing.java15grammar.ast;
 
public enum LITERAL {
   STRING, INTEGER, FLOATING_POINT, CHARACTER, NULL, BOOLEAN_LITERAL
}

org.structuredparsing.java15grammar.ast.LiteralExpression:

package org.structuredparsing.java15grammar.ast;
 
public class LiteralExpression implements IExpression {
   private String literalContent;
   private LITERAL literalType;
 
   public void setLiteralContent( String literlaContent ) {
      this.literalContent = literlaContent;
   }
 
   public String getLiteralContent() {
      return this.literalContent;
   }
 
   public void setLiteralType( LITERAL literalType ) {
      this.literalType = literalType;
   }
 
   public LITERAL getLiteralType() {
      return this.literalType;
   }
}

Actions

Java15

The Java15 rule must be updated with more actions

Coco/R EBFN Rule
PRODUCTIONS

Java15 = (. StringBuilder sbId = null; Annotation annotation = null; .)
[{Annotation<out annotation> (. sourceFile.addAnnotation( annotation ); .)
} Package
QualifiedIdentifier<out sbId>
(. sourceFile.setPacakgeContent( sbId.toString() ); .)
SemiColon] {ImportDeclaration} {TypeDeclaration}.

Actions for Annotation

Coco/R EBFN Rule
PRODUCTIONS

Annotation<out Annotation annotation> =
(. QualifiedIdentifier qualifiedIdentifier = null; annotation = new Annotation(); .)
AtSign QualifiedIdentifier<out qualifiedIdentifier>
(. annotation.setQualifiedIdentifier( qualifiedIdentifier ); .)
[ LeftParenthesis [ElementValuePairs<annotation>] RightParenthesis ].

ElementValuePairs<Annotation annotation> =
(. ElementValuePair elementValuePair = null; .)
ElementValuePair<out elementValuePair>
(. annotation.addElementValuePair( elementValuePair ); .)
{Comma ElementValuePair<out elementValuePair>
(. annotation.addElementValuePair( elementValuePair ); .)
}.

ElementValuePair<out ElementValuePair elementValuePair> =
(. elementValuePair = new ElementValuePair(); ElementValue elementValue = null; .)
[IF(isIdentifierFollowedByAssignment()) Identifier
(. elementValuePair.setIdentifier( t.val ); .)
Assignment] ElementValue<out elementValue>
(. elementValuePair.setElementValue( elementValue ); .)
.

ElementValue<out ElementValue elementValue>
(. elementValue = new ElementValue(); IExpression expression = null; .)
=
ConditionalExpression<out expression>
(. elementValue.setExpression( expression ); .)
| (. Annotation annotation = null; .)
Annotation<out annotation>
(. elementValue.setAnnotation( annotation ); .)
|
ElementValueArrayInitializer<elementValue>
.

ElementValueArrayInitializer<ElementValue elementValue> =
LeftCurlyBrace ElementValues<elementValue> [Comma] RightCurlyBrace.

ElementValues<ElementValue elementValue> =
(. ElementValue eV = null; .)
ElementValue<out eV> (. elementValue.addElementValue( eV ); .)
{IF( isCommaNotFollowedByRightCurlyBrace() ) Comma ElementValue<out eV>
(. elementValue.addElementValue( eV ); .)
}.

Actions for ConditionalExpression

Even the ConditionalExpression rule must be updated with actions, however these actions will be changed in the near future.

Coco/R EBFN Rule
PRODUCTIONS

ConditionalExpression<out IExpression expr> =
Identifier (. QualifiedIdentifier q = new QualifiedIdentifier();
q.addIdentifier( t.al); expr = q; .)

Unittests

Here a few unittests are shown

@Test
public void testParser_annotation_infrontof_package___one_single_annotation_just_one_qialified_identifier() throws UnsupportedEncodingException {
        System.out.println("testParser_annotation_infrontof_package___one_single_annotation_just_one_qialified_identifier");
    // Initialize
    String sAnnotationIdentifier = "Documented";
    List< String > identifierList = new ArrayList< String >();
    identifierList.add( sAnnotationIdentifier );
    String sContent = "@" + sAnnotationIdentifier + " package parser;";
    final int nNR_OF_ANNOTATIONS = 1, nFIRST_ANNOTATION = 0;
    InputStream is = new ByteArrayInputStream(sContent.getBytes("UTF-8"));
    Scanner scanner = new Scanner(is);
    Parser instance = new Parser( scanner );
    // Test
    instance.Parse();
    ISourceFile sourceFile = instance.getSourceFile();
    // Validate
    assertNotNull( sourceFile.getPackageContent() );
    assertTrue( sourceFile.getImportList().isEmpty() );
    assertNotNull( sourceFile.getAnnotations() );
    assertEquals( nNR_OF_ANNOTATIONS, sourceFile.getAnnotations().size() );
    assertEquals( identifierList, sourceFile.getAnnotations().get( nFIRST_ANNOTATION ).getQualifiedIdentifier().getIdentifierList() );
    assertTrue( sourceFile.getAnnotations().get( nFIRST_ANNOTATION ).getElementValuePairs().isEmpty() );
}
 
@Test
public void testParser_annotation_infrontof_package___two_single_annotation_just_one_qialified_identifier() throws UnsupportedEncodingException {
    System.out.println("testParser_annotation_infrontof_package___two_single_annotation_just_one_qialified_identifier");
    // Initialize
    String sAnnotationIdentifier_1 = "Documented";
    String sAnnotationIdentifier_2 = "Storable";
    List< String > identifierList_1 = new ArrayList< String >();
    identifierList_1.add( sAnnotationIdentifier_1 );
    List< String > identifierList_2 = new ArrayList< String >();
    identifierList_2.add( sAnnotationIdentifier_2 );
    String sContent = "@" + sAnnotationIdentifier_1 + " @" + sAnnotationIdentifier_2 + " package parser;";
    final int nNR_OF_ANNOTATIONS = 2, nFIRST_ANNOTATION = 0, nSECOND_ANNOTATION = 1;
    InputStream is = new ByteArrayInputStream(sContent.getBytes("UTF-8"));
    Scanner scanner = new Scanner(is);
    Parser instance = new Parser( scanner );
    // Test
    instance.Parse();
    ISourceFile sourceFile = instance.getSourceFile();
    // Validate
    assertEquals( nNR_OF_ANNOTATIONS, sourceFile.getAnnotations().size() );
    assertEquals( identifierList_1, sourceFile.getAnnotations().get( nFIRST_ANNOTATION ).getQualifiedIdentifier().getIdentifierList() );
    assertTrue( sourceFile.getAnnotations().get( nFIRST_ANNOTATION ).getElementValuePairs().isEmpty() );
    assertEquals( identifierList_2, sourceFile.getAnnotations().get( nSECOND_ANNOTATION ).getQualifiedIdentifier().getIdentifierList() );
    assertTrue( sourceFile.getAnnotations().get( nSECOND_ANNOTATION ).getElementValuePairs().isEmpty() );
}

Next Chapter Grammar Rules - part 7


<- back

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License