package grammar.java; import static grammar.GrammarDSL.*; import grammar.Expression; /** * Grammar rules for Java statements and declarations. * * @see JavaGrammar */ public class _C_Statements extends _B_Expressions { //============================================================================ // STATEMENTS //============================================================================ //---------------------------------------------------------------------------- // VARIABLE DECLARATION //---------------------------------------------------------------------------- { (this).toString(); } /***************************************************************************** * A variable name. Not simply an identifier because Java is "backward * compatible" with the C syntax for array declaration (putting square * brackets after the variable name instead of after the type). */ public final Expression variableDeclaratorId = rule_seq( identifier, star(square)); /***************************************************************************** * A prefix that appears in the declarations of non-field variables. */ public final Expression variableDeclarationPrefix = rule_seq( star(annotation), opt(_final, star(annotation)), type); /***************************************************************************** * A (variable name, value) pair, used in local variable declarations. */ public final Expression variableDeclarator = rule_seq( variableDeclaratorId, opt(eq, variableInitializer)); /****************************************************************************/ public final Expression localVariableDeclaration = rule_seq( variableDeclarationPrefix, list(comma, variableDeclarator) ); //---------------------------------------------------------------------------- // BLOCKS AND STATEMENT EXPRESSIONS //---------------------------------------------------------------------------- /****************************************************************************/ public final Expression methodInvocation = rule( nonPrimaryMethodInvocation, primaryMethodInvocation // prefix of nonPrimaryMethodInfocation ); /***************************************************************************** * Only expression that may have side effects can be used as statements. */ public final Expression statementExpression = rule( assignment, incrementExpression, methodInvocation, innerCreator, seq(_new, creator), innerCreator ); // TODO strictpf is valid here (and for abstract classes too) /***************************************************************************** * This is the prefix for classes defined inside a block. Notice the * similarity with variableDeclarationPrefix. */ public final Expression classDeclarationPrefix = rule_seq( star(annotation), opt(choice(_final, _abstract)), star(annotation)); /***************************************************************************** * Prefix for abstract classes defined inside blocks. */ public final Expression abstractClassDeclarationPrefix = rule_seq( star(annotation), opt(_abstract), star(annotation)); /***************************************************************************** * Things that can go in a block. This is a superset of simple statements. * The additional items are declarations. Declarations wouldn't make sense * in simple statement, because those statement can go directly after * an "if" or "while" (not inside a block). */ public final Expression blockStatement = rule( seq(localVariableDeclaration, semi), seq(classDeclarationPrefix, ref("classDeclaration")), seq(abstractClassDeclarationPrefix, ref("abstractClassDeclaration")), ref("statement") ); /****************************************************************************/ public final Expression block = rule_seq( lCuBra, star(blockStatement), rCuBra); //---------------------------------------------------------------------------- // LOOP STATEMENTS //---------------------------------------------------------------------------- /***************************************************************************** * A parameter declaration, used in method/constructor declarations, for/try * statements, ... */ public final Expression formalParameter = rule_seq( variableDeclarationPrefix, variableDeclaratorId ); /****************************************************************************/ public final Expression forInit = rule( localVariableDeclaration, list(comma, statementExpression) ); /****************************************************************************/ public final Expression forUpdate = rule(list(comma, statementExpression)); /****************************************************************************/ public final Expression forStatement = rule_seq( _for, lPar, opt(forInit), semi, opt(expression), semi, opt(forUpdate), rPar, ref("statement")); /****************************************************************************/ public final Expression forEachStatement = rule_seq( _for, lPar, formalParameter, colon, expression, rPar, ref("statement")); /****************************************************************************/ public final Expression whileStatement = rule_seq( _while, parExpression, ref("statement")); /****************************************************************************/ public final Expression doWhileStatement = rule_seq( _do, ref("statement"), _while, parExpression, semi); //---------------------------------------------------------------------------- // TRY STATEMENTS //---------------------------------------------------------------------------- /****************************************************************************/ public final Expression catchBlock = rule_seq( _catch, lPar, variableDeclarationPrefix, star(pipe, type), variableDeclaratorId, rPar, block ); /****************************************************************************/ public final Expression finallyBlock = rule_seq(_finally, block); /****************************************************************************/ public final Expression tryStatement = rule_seq( _try, block, choice( seq(plus(catchBlock), opt(finallyBlock)), finallyBlock ) ); /***************************************************************************** * A resource is a local variable used in a try-with-resources statement. * Its type must implement the java.lang.AutoCloseable interface. */ public final Expression resourceDeclaration = rule_seq( formalParameter, eq, expression ); /***************************************************************************** * Contrary to the regular try statement, there does not need to be a * catch or finally block following the try block. */ public final Expression tryWithResourcesStatement = rule_seq( _try, lPar, list(semi, resourceDeclaration), opt(semi), rPar, block, star(catchBlock), opt(finallyBlock) ); //---------------------------------------------------------------------------- // OTHER STATEMENTS //---------------------------------------------------------------------------- /***************************************************************************** * An assertion checks that the first (boolean) expression evaluates to true. * If it doesn't an AssertionError is thrown, and the second expression is * passed to its constructor, if present. */ public final Expression assertion = rule_seq( _assert, expression, opt(colon, expression), semi); /****************************************************************************/ public final Expression ifStatement = rule_seq( _if, parExpression, ref("statement"), opt(_else, ref("statement"))); /***************************************************************************** * Compile-time constant expression. Value of a primitive type or String * whose value is known at compile-time, as defined in JLS 15.28. To get an * idea why we can't use the grammar to specify those types further, consider * that "true ? (int) (1 + 1.0) : 2" is a constant expression. */ public final Expression constantExpression = rule_seq(expression); /****************************************************************************/ public final Expression enumConstantName = rule_seq(identifier); /****************************************************************************/ public final Expression switchLabel = rule_seq( choice( seq(_case, choice(constantExpression, enumConstantName)), _default ), colon ); /****************************************************************************/ public final Expression switchBlockStmtGroup = rule_seq( switchLabel, star(blockStatement)); /****************************************************************************/ public final Expression switchStatement = rule_seq( _switch, parExpression, lCuBra, star(switchBlockStmtGroup), rCuBra); /****************************************************************************/ public final Expression synchronizedBlock = rule_seq( _synchronized, parExpression, block); /****************************************************************************/ public final Expression returnStatement = rule_seq( _return, opt(expression), semi); /****************************************************************************/ public final Expression throwStatement = rule_seq(_throw, expression, semi); /***************************************************************************** * The "break;" form is only valid as or inside loop bodies, while the * "break <label>;" form is valid inside any statement that can have * sub-statements (loops, if, switch and blocks, but not anonymous classes). * * It turns out we could enforce those conditions within the grammar, but it * is more trouble than it is worth since the conditions can be trivially * checked afterwards. Especially for a real compiler which will need to * verify that the referenced labels exist anyway. For the curious, the * solution would entail redefining block, if, switch, ... for use * within loop statements, leading to some unwelcome duplication. */ public final Expression breakStatement = rule_seq( _break, opt(identifier), semi); /***************************************************************************** * Continue statements are only valid as or inside loop bodies. * The remark from breakStatement applies. */ public final Expression continueStatement = rule_seq( _continue, opt(identifier), semi); /***************************************************************************** * A statement preceded by a label, which will allow a quick exit from the * statement. A label can be applied to any statement, although it is only * ever useful on statements that can have "sub-statements", like blocks, * loops, etc.. One the sub-statements can be "break <label>;" which then * causes the specified enclosed statement to abort. */ public final Expression labeledStatement = rule_seq( identifier, colon, ref("statement")); //---------------------------------------------------------------------------- // STATEMENT //---------------------------------------------------------------------------- public final Expression statement = rule( block, assertion, ifStatement, forStatement, forEachStatement, whileStatement, doWhileStatement, tryStatement, tryWithResourcesStatement, switchStatement, synchronizedBlock, returnStatement, throwStatement, breakStatement, continueStatement, semi, labeledStatement, seq(statementExpression, semi) ); //============================================================================ // TYPE DECLARATIONS //============================================================================ /* A type is an interface, an annotation type, a class or an enum. * * This sections concerns itself with modifiers (annotations and keywords such * as public, final, ...) a lot. Often we will specify that a declaration is * preceded by zero or more modifiers selected amongst those that are valid * for the declared element. We could theoretically encode the fact that each * keyword modifier cannot appear more than once in the grammar. We chose not * to, as it would entail listing every possible keyword ordering. Annotation * have a similar restriction, which cannot be encoded in the grammar since * annotation names are arbitrary identifiers. */ //============================================================================ //---------------------------------------------------------------------------- // METHOD, CONSTRUCTOR & FIELD DECLARATION //---------------------------------------------------------------------------- /* The base forms of declarations, to be augmented with modifiers * (annotations and keywords) in specific kind of types. */ //---------------------------------------------------------------------------- /***************************************************************************** * The last parameter may be an ellipsis (allows passing variable number * of arguments which will be bundled as an array). * * Surprisingly "int[]... x" is allowed while "int... x[]" is not. */ public final Expression ellipsisParameter = rule_seq( variableDeclarationPrefix, ellipsis, identifier ); /***************************************************************************** * Parameter lists for methods and constructors. */ public final Expression formalParameterList = rule_seq( lPar, opt(choice( seq(list(comma, formalParameter), opt(comma, ellipsisParameter)), ellipsisParameter )), rPar ); /****************************************************************************/ public final Expression methodBody = rule_seq(block); /***************************************************************************** * The optional squares are used to specify array return types in something * that vaguely resembles C-style: "int test() [] ;" is the same as * "int[] test() ;". */ public final Expression methodDeclarationPrefix = rule_seq( opt(typeParameters), choice( seq(_void, identifier, formalParameterList), seq(type, identifier, formalParameterList, star(square)) ), opt(_throws, list(comma, classType)) ); /****************************************************************************/ public final Expression methodDeclaration = rule_seq( methodDeclarationPrefix, methodBody); /***************************************************************************** * This form is only acceptable in abstract classes and interfaces. */ public final Expression abstractMethodDeclaration = rule_seq( methodDeclarationPrefix, semi); /***************************************************************************** * The first statement in a constructor can be an optional call to another * constructor of the same class or to a super-constructor. * * e.g. plain "super()" is equivalent to "EnclosingClass.this.super()". */ public final Expression constructorBody = rule_seq( lCuBra, opt(constructorInvocation), star(blockStatement), rCuBra ); /****************************************************************************/ public final Expression constructorDeclaration = rule_seq( opt(typeParameters), identifier, formalParameterList, opt(_throws, list(comma, classType)), constructorBody ); /****************************************************************************/ public final Expression fieldDeclaration = rule_seq( type, list(comma, variableDeclarator), semi); //---------------------------------------------------------------------------- // TYPE DECLARATION MODIFIERS //---------------------------------------------------------------------------- /* Accessibility modifier keywords (public, private, protected) are mutually * exclusive. The abstract and final keyword are mutually exclusive. * * Top-level types have the same modifiers as nested types, except they can't * be private, protected or static. All top level types are visible within * their package, while public top-level types are visible everywhere. */ //---------------------------------------------------------------------------- /****************************************************************************/ public final Expression accessibilityModifier = rule( _public, _protected, _private); /****************************************************************************/ public final Expression accessibilityRestricter = rule( _protected, _private); /****************************************************************************/ public final Expression nestedEnumModifier = rule( annotation, accessibilityModifier, _static, _strictfp); /****************************************************************************/ public final Expression topLevelEnumModifier = rule( annotation, _public, _strictfp); /***************************************************************************** * The abstract modifier is redundant for an interface. The static modifier is * redundant for nested interfaces. They shouldn't be used. */ public final Expression nestedInterfaceModifier = rule( annotation, accessibilityModifier, _static, _strictfp, _abstract); /****************************************************************************/ public final Expression topLevelInterfaceModifier = rule( annotation, _public, _strictfp, _abstract); /***************************************************************************** * We omit the abstract modifier from this list, because we treat abstract * classes separately from regular classes later on. */ public final Expression nestedClassModifier = rule( annotation, accessibilityModifier, _static, _strictfp, _final); /****************************************************************************/ public final Expression topLevelClassModifier = rule( annotation, _public, _strictfp, _final); /****************************************************************************/ public final Expression nestedAbstractClassModifier = rule( annotation, accessibilityModifier, _static, _strictfp); /****************************************************************************/ public final Expression topLevelAbstractClassModifier = rule( annotation, _public, _strictfp); //---------------------------------------------------------------------------- /* A nested type declared in an interface is implicitly public and static. As * a result, such types can't have accessibility restricters as modifiers. */ //---------------------------------------------------------------------------- /****************************************************************************/ public final Expression interfaceEnumModifier = rule_seq( not(accessibilityRestricter), nestedEnumModifier); /****************************************************************************/ public final Expression interfaceInterfaceModifier = rule_seq( not(accessibilityRestricter), nestedInterfaceModifier); /****************************************************************************/ public final Expression interfaceClassModifier = rule_seq( not(accessibilityRestricter), nestedClassModifier); /****************************************************************************/ public final Expression interfaceAbstractClassModifier = rule_seq( not(accessibilityRestricter), nestedAbstractClassModifier); //---------------------------------------------------------------------------- /* The following rules for abstract classes modifier lists ensure that the * abstract keyword appears only once. */ //---------------------------------------------------------------------------- /****************************************************************************/ public final Expression nestedAbstractClassModifiers = rule_seq( star(nestedAbstractClassModifier), _abstract, star(nestedAbstractClassModifier) ); /****************************************************************************/ public final Expression interfaceAbstractClassModifiers = rule_seq( star(interfaceAbstractClassModifier), _abstract, star(interfaceAbstractClassModifier) ); /****************************************************************************/ public final Expression topLevelAbstractClassModifiers = rule_seq( star(topLevelAbstractClassModifier), _abstract, star(topLevelAbstractClassModifier) ); //---------------------------------------------------------------------------- // TYPE DECLARATION //---------------------------------------------------------------------------- /* Rules for the declaration of types in various context (the modifiers vary * according to the context). The common (non-modifier) part of each * declaration will be defined later. */ //---------------------------------------------------------------------------- /***************************************************************************** * Note that non-static nested types are called inner types. Note that * static members are not allowed in non-static inner types (not enforced by * the grammar). */ public final Expression nestedTypeDeclaration = rule( seq(star(nestedInterfaceModifier), ref("interfaceDeclaration")), seq(star(nestedInterfaceModifier), ref("annotationTypeDeclaration")), seq(star(nestedEnumModifier), ref("enumDeclaration")), seq(star(nestedClassModifier), ref("classDeclaration")), seq(nestedAbstractClassModifiers, ref("abstractClassDeclaration")) ); /****************************************************************************/ public final Expression interfaceTypeDeclaration = rule( seq(star(interfaceInterfaceModifier), ref("interfaceDeclaration")), seq(star(interfaceInterfaceModifier), ref("annotationTypeDeclaration")), seq(star(interfaceEnumModifier), ref("enumDeclaration")), seq(star(interfaceClassModifier), ref("classDeclaration")), seq(interfaceAbstractClassModifiers, ref("abstractClassDeclaration")) ); /****************************************************************************/ public final Expression topLevelTypeDeclaration = rule( semi, seq(star(topLevelInterfaceModifier), ref("interfaceDeclaration")), seq(star(topLevelInterfaceModifier), ref("annotationTypeDeclaration")), seq(star(topLevelEnumModifier), ref("enumDeclaration")), seq(star(topLevelClassModifier), ref("classDeclaration")), seq(topLevelAbstractClassModifiers, ref("abstractClassDeclaration")) ); //---------------------------------------------------------------------------- // INTERFACE DECLARATION //---------------------------------------------------------------------------- /***************************************************************************** * Interface fields are implicitly public, static and final, because * interfaces are only intended to give a specification of some behavior. * Thus all of these modifiers are redundant. */ public final Expression interfaceFieldModifier = rule( annotation, _public, _static, _final); /***************************************************************************** * As a consequence from the immutability of interface fields (see * interfaceFieldModifiers), the interface fields initializers should be * compile-time constants (as described in JLS 14.8). */ public final Expression interfaceFieldDeclaration = rule_seq( star(interfaceFieldModifier), fieldDeclaration); /***************************************************************************** * Interface methods are public and abstract by default, making those * modifiers redundant and discouraged by the JLS as a matter of style. */ public final Expression interfaceMethodModifier = rule( annotation, _public, _abstract); /****************************************************************************/ public final Expression interfaceMethodDeclaration = rule_seq( star(interfaceMethodModifier), abstractMethodDeclaration); /***************************************************************************** * Non-method class members are implicitly static. * A semicolon is not a member, but can appear in their stead. */ public final Expression interfaceMemberDeclaration = rule( semi, interfaceMethodDeclaration, interfaceFieldDeclaration, interfaceTypeDeclaration ); /****************************************************************************/ public final Expression interfaceBody = rule_seq( lCuBra, star(interfaceMemberDeclaration), rCuBra); /****************************************************************************/ public final Expression interfaceDeclaration = rule_seq( _interface, identifier, opt(typeParameters), opt(_extends, list(comma, classType)), interfaceBody ); //---------------------------------------------------------------------------- // ANNOTATION DECLARATION //---------------------------------------------------------------------------- /* An annotation type declaration makes a new annotation available for use. * The parameters that must/can be passed to the annotation are defined by the * attributes (methods) of the annotation type. You can also have a class * implement the annotation type. This is a feature best left alone as it has * no practical use cases. */ //---------------------------------------------------------------------------- /***************************************************************************** * A method of an annotation is called an "attribute". Each attribute * represent a parameter that must (or can, if a default value is specified) * be passed to an annotation when used (see ANNOTATION USAGE). * * Like interface methods, attributes are public and abstract by default. * * As per section 9.6.1 of the JLS, an attribute's return types must be one * of: primitive types (the boxed version are allowed), String, any * parameterized version of Class, an enum type, enumeration type; or * one-dimensional array of the aforementioned. This is no enforced by the * grammar. */ public final Expression annotationAttributeDeclaration = rule_seq( star(interfaceMethodModifier), type, identifier, lPar, rPar, opt(_default, elementValue), semi ); /***************************************************************************** * Member other than attributes in an annotation declaration follow the same * rules as the corresponding members in an interface. */ public final Expression annotationTypeMemberDeclaration = rule( semi, annotationAttributeDeclaration, interfaceFieldDeclaration, interfaceTypeDeclaration ); /****************************************************************************/ public final Expression annotationTypeBody = rule_seq( lCuBra, star(annotationTypeMemberDeclaration), rCuBra); /****************************************************************************/ public final Expression annotationTypeDeclaration = rule_seq( at, _interface, identifier, annotationTypeBody); //---------------------------------------------------------------------------- // CLASS DECLARATION //---------------------------------------------------------------------------- /****************************************************************************/ public final Expression classFieldModifier = rule( annotation, accessibilityModifier, _static, _final, _transient, _volatile); /****************************************************************************/ public final Expression classFieldDeclaration = rule_seq( star(classFieldModifier), fieldDeclaration); /****************************************************************************/ public final Expression classMethodModifier = rule( annotation, accessibilityModifier, _final, _static, _strictfp, _synchronized, _transient, _volatile); /****************************************************************************/ public final Expression classMethodDeclaration = rule_seq( star(classMethodModifier), methodDeclaration); /****************************************************************************/ public final Expression nativeMethodDeclaration = rule_seq( star(classMethodModifier), _native, star(classMethodModifier), abstractMethodDeclaration); /***************************************************************************** * The way the rule is setup ensures there will only be a single accessibility * modifier. */ public final Expression classConstructorDeclaration = rule_seq( star(annotation), opt(accessibilityModifier), star(annotation), constructorDeclaration); /***************************************************************************** * A class-level block is not a class member, but appears at the same place * as class members. */ public final Expression classMemberDeclaration = rule( semi, seq(opt(_static), block), nestedTypeDeclaration, classMethodDeclaration, nativeMethodDeclaration, classConstructorDeclaration, classFieldDeclaration ); /****************************************************************************/ public final Expression classBody = rule_seq( lCuBra, star(classMemberDeclaration), rCuBra); /****************************************************************************/ public final Expression classDeclaration = rule_seq( _class, identifier, opt(typeParameters), opt(_extends, classType), opt(_implements, list(comma, classType)), classBody ); //---------------------------------------------------------------------------- // ABSTRACT CLASS DECLARATION //---------------------------------------------------------------------------- /***************************************************************************** * An abstract method can't be private since subclasses have to see the * method in order to implement it. */ public final Expression abstractMethodModifier = rule( annotation, _public, _protected); /****************************************************************************/ public final Expression abstractMethodDeclarationWithModifiers = rule_seq( star(abstractMethodModifier), opt(_abstract, star(abstractMethodModifier)), abstractMethodDeclaration ); /***************************************************************************** * A class-level block is not a class member, but appears at the same place * as class members. */ public final Expression abstractClassMemberDeclaration = rule( classMemberDeclaration, abstractMethodDeclarationWithModifiers ); /****************************************************************************/ public final Expression abstractClassBody = rule_seq( lCuBra, star(abstractClassMemberDeclaration), rCuBra); /****************************************************************************/ public final Expression abstractClassDeclaration = rule_seq( _class, identifier, opt(typeParameters), opt(_extends, classType), opt(_implements, list(comma, classType)), abstractClassBody ); //---------------------------------------------------------------------------- // ENUM DECLARATION //---------------------------------------------------------------------------- /* An enum is basically an abstract class which has singleton nested classes * extending itself. The nested classes are called enumeration constants. */ //---------------------------------------------------------------------------- /***************************************************************************** * An enumeration constant declaration can be as simple as an identifier This * identifier can also be followed by parameters, which correspond to the * parameters to one of the enum's constructors. This can also be followed by * a whole class body (and needs to, if the enum itself has abstract * methods). */ public final Expression enumConstant = rule_seq( star(annotation), identifier, opt(arguments), opt(classBody) ); /***************************************************************************** * enum constructor are implicitly private, as they are only meant to be * used by enum constants. */ public final Expression enumConstructorDeclaration = rule_seq( star(annotation), opt(_private, star(annotation)), constructorDeclaration ); /****************************************************************************/ public final Expression enumMemberDeclaration = rule( enumConstructorDeclaration, seq(not(classConstructorDeclaration), abstractClassMemberDeclaration) ); /****************************************************************************/ public final Expression enumBody = rule_seq( lCuBra, opt(list(comma, enumConstant)), opt(comma), opt(semi, star(enumMemberDeclaration)), rCuBra); /****************************************************************************/ public final Expression enumDeclaration = rule_seq( _enum, identifier, opt(_implements, list(comma, classType)), enumBody); //============================================================================ // COMPILATION UNIT (TOP LEVEL) //============================================================================ /***************************************************************************** * Packages may be annotated. There can be at most one annotated package * declaration for any given package. The preferred way is to put this * declaration in the file "package-info.java" directly under the package * directory. This file does not declare a class. This file can also contain * package-level comments: insert a comment before the package declaration. */ public final Expression packageDeclaration = rule_seq( star(annotation), _package, qualifiedIdentifier, semi); /****************************************************************************/ public final Expression importDeclaration = rule_seq( _import, opt(_static), qualifiedIdentifier, opt(dot, star), semi); /****************************************************************************/ public final Expression prelude = rule_seq( spacing, opt(packageDeclaration), star(importDeclaration) ); /***************************************************************************** * A version of the prelude rule that ensures that the whole prelude is parsed * and not cut short in case of errors in import declarations. */ public final Expression fullPrelude = rule_seq( prelude, and(choice(_static, _private, _public, _strictfp, _abstract, _final, _class, _interface, _enum, seq(at, _interface), annotation, ref("macro"), ref("raw"), ref("prioritary"), endOfInput)) ); /****************************************************************************/ public final Expression compilationUnit = rule_seq( prelude, star(topLevelTypeDeclaration), endOfInput ); }