org.codehaus.janino.Java Maven / Gradle / Ivy
Show all versions of janino Show documentation
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2001-2010 Arno Unkrig. All rights reserved.
* Copyright (c) 2015-2016 TIBCO Software Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
* products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.codehaus.janino;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import org.codehaus.commons.compiler.CompileException;
import org.codehaus.commons.compiler.Location;
import org.codehaus.commons.nullanalysis.Nullable;
import org.codehaus.janino.CodeContext.Offset;
import org.codehaus.janino.IClass.IMethod;
import org.codehaus.janino.Java.FunctionDeclarator.FormalParameter;
import org.codehaus.janino.Java.FunctionDeclarator.FormalParameters;
import org.codehaus.janino.Visitor.AbstractCompilationUnitVisitor;
import org.codehaus.janino.Visitor.AnnotationVisitor;
import org.codehaus.janino.Visitor.ElementValueVisitor;
import org.codehaus.janino.Visitor.LambdaBodyVisitor;
import org.codehaus.janino.Visitor.LambdaParametersVisitor;
import org.codehaus.janino.Visitor.ModifierVisitor;
import org.codehaus.janino.Visitor.ModuleDirectiveVisitor;
import org.codehaus.janino.Visitor.RvalueVisitor;
import org.codehaus.janino.Visitor.TryStatementResourceVisitor;
import org.codehaus.janino.Visitor.TypeArgumentVisitor;
import org.codehaus.janino.Visitor.TypeDeclarationVisitor;
import org.codehaus.janino.util.AbstractTraverser;
import org.codehaus.janino.util.iterator.ReverseListIterator;
/**
* This wrapper class defines classes that represent the elements of the Java programming language.
*
* Notice: "JLS7" refers to the Java Language Specification, Java SE 7
* Edition.
*
*/
public final
class Java {
private Java() {} // Don't instantiate me.
/**
* Representation of a Java "scope", e.g. a compilation unit, type, method or block.
*/
public
interface Scope {
/**
* @return The scope that encloses this scope, or {@code null}
*/
Scope getEnclosingScope();
}
/**
* This interface is implemented by objects which are associated with a location in the source code.
*/
public
interface Locatable {
/**
* @return The location of this object
*/
Location getLocation();
/**
* Throws a {@link CompileException} with the given message and this object's location.
*
* @param message The message to report
*/
void throwCompileException(String message) throws CompileException;
}
/**
* Abstract implementation of {@link Locatable}.
*/
public abstract static
class Located implements Locatable {
/**
* Indication of "no" or "unknown" location.
*/
public static final Located NOWHERE = new Located(Location.NOWHERE) {};
private final Location location;
protected
Located(Location location) {
//assert location != null;
this.location = location;
}
// Implement "Locatable".
@Override public Location
getLocation() { return this.location; }
@Override public void
throwCompileException(String message) throws CompileException {
throw new CompileException(message, this.location);
}
}
/**
* Holds the result of {@link Parser#parseAbstractCompilationUnit()}.
*/
public abstract static
class AbstractCompilationUnit implements Scope {
/**
* A string that explains the "file" (or similar resource) where this compilation unit was loaded from.
*/
@Nullable public final String optionalFileName;
/**
* The IMPORT declarations in this compilation unit.
*/
public final ImportDeclaration[] importDeclarations;
public
AbstractCompilationUnit(@Nullable String optionalFileName, ImportDeclaration[] importDeclarations) {
this.optionalFileName = optionalFileName;
this.importDeclarations = importDeclarations;
}
// Implement "Scope".
@Override public Scope
getEnclosingScope() { throw new InternalCompilerException("A compilation unit has no enclosing scope"); }
/**
* Invokes the "{@code visit...()}" method of {@link Visitor.AbstractCompilationUnitVisitor} for the concrete
* {@link AbstractCompilationUnit} type.
*/
@Nullable public abstract R
accept(AbstractCompilationUnitVisitor visitor) throws EX;
/**
* Represents a "single-type import declaration" like "{@code import java.util.Map;}".
*/
public static
class SingleTypeImportDeclaration extends ImportDeclaration {
/**
* The identifiers that constitute the type to be imported, e.g. "java", "util", "Map".
*/
public final String[] identifiers;
public
SingleTypeImportDeclaration(Location location, String[] identifiers) {
super(location);
this.identifiers = identifiers;
}
@Override @Nullable public final R
accept(Visitor.ImportVisitor visitor) throws EX {
return visitor.visitSingleTypeImportDeclaration(this);
}
@Override public String
toString() { return "import " + Java.join(this.identifiers, ".") + ';'; }
}
/**
* Represents a type-import-on-demand declaration like {@code import java.util.*;}.
*/
public static
class TypeImportOnDemandDeclaration extends ImportDeclaration {
/**
* The identifiers that constitute the package or type to import from, e.g. "java", "util".
*/
public final String[] identifiers;
public
TypeImportOnDemandDeclaration(Location location, String[] identifiers) {
super(location);
this.identifiers = identifiers;
}
@Override @Nullable public final R
accept(Visitor.ImportVisitor visitor) throws EX {
return visitor.visitTypeImportOnDemandDeclaration(this);
}
@Override public String
toString() { return "import " + Java.join(this.identifiers, ".") + ".*;"; }
}
/**
* Represents a single static import declaration like
*
* import java.util.Collections.EMPTY_MAP;
*
*/
public static
class SingleStaticImportDeclaration extends ImportDeclaration {
/**
* The identifiers that constitute the member to be imported, e.g. "java", "util", "Collections",
* "EMPTY_MAP".
*/
public final String[] identifiers;
public
SingleStaticImportDeclaration(Location location, String[] identifiers) {
super(location);
this.identifiers = identifiers;
}
@Override @Nullable public final R
accept(Visitor.ImportVisitor visitor) throws EX {
return visitor.visitSingleStaticImportDeclaration(this);
}
@Override public String
toString() { return "import static " + Java.join(this.identifiers, ".") + ";"; }
}
/**
* Represents a static-import-on-demand declaration like
*
* import static java.util.Collections.*;
*
*/
public static
class StaticImportOnDemandDeclaration extends ImportDeclaration {
/**
* The identifiers that constitute the type to import from, e.g. "java", "util", "Collections".
*/
public final String[] identifiers;
public
StaticImportOnDemandDeclaration(Location location, String[] identifiers) {
super(location);
this.identifiers = identifiers;
}
@Override @Nullable public final R
accept(Visitor.ImportVisitor visitor) throws EX {
return visitor.visitStaticImportOnDemandDeclaration(this);
}
@Override public String
toString() { return "import static " + Java.join(this.identifiers, ".") + ".*;"; }
}
/**
* Base class for the various IMPORT declarations.
*/
public abstract static
class ImportDeclaration extends Java.Located {
public
ImportDeclaration(Location location) { super(location); }
/**
* Invokes the "{@code visit...()}" method of {@link Visitor.ImportVisitor} for the concrete {@link
* ImportDeclaration} type.
*/
@Nullable public abstract R
accept(Visitor.ImportVisitor visitor) throws EX;
}
}
public static final
class CompilationUnit extends AbstractCompilationUnit {
/**
* The package declaration at the very top of this compilation unit (if any).
*/
@Nullable public PackageDeclaration optionalPackageDeclaration;
/**
* The top-level declarations in this compilation unit.
*/
public final List
packageMemberTypeDeclarations = new ArrayList();
public
CompilationUnit(@Nullable String optionalFileName) {
this(optionalFileName, new ImportDeclaration[0]);
}
public
CompilationUnit(@Nullable String optionalFileName, ImportDeclaration[] importDeclarations) {
super(optionalFileName, importDeclarations);
}
/**
* Sets the package declaration of this compilation unit.
*/
public void
setPackageDeclaration(@Nullable PackageDeclaration packageDeclaration) {
this.optionalPackageDeclaration = packageDeclaration;
}
/**
* Adds one top-level type declaration to this compilation unit.
*/
public void
addPackageMemberTypeDeclaration(PackageMemberTypeDeclaration pmtd) {
this.packageMemberTypeDeclarations.add(pmtd);
pmtd.setDeclaringCompilationUnit(this);
}
/**
* Gets all classes and interfaces declared in this compilation unit.
*/
public PackageMemberTypeDeclaration[]
getPackageMemberTypeDeclarations() {
return (PackageMemberTypeDeclaration[]) this.packageMemberTypeDeclarations.toArray(
new PackageMemberTypeDeclaration[this.packageMemberTypeDeclarations.size()]
);
}
/**
* Returns the package member class or interface declared with the given name.
*
* @param name Declared (i.e. not the fully qualified) name
* @return {@code null} if a package member type with that name is not declared in this compilation unit
*/
@Nullable public PackageMemberTypeDeclaration
getPackageMemberTypeDeclaration(String name) {
for (PackageMemberTypeDeclaration pmtd : this.packageMemberTypeDeclarations) {
if (pmtd.getName().equals(name)) return pmtd;
}
return null;
}
@Override @Nullable public R
accept(AbstractCompilationUnitVisitor visitor) throws EX {
return visitor.visitCompilationUnit(this);
}
}
/**
* Represents a {@code ModularCompilationUnit} as specified in JLS11 7.3.
*/
public static final
class ModularCompilationUnit extends AbstractCompilationUnit {
public final ModuleDeclaration moduleDeclaration;
public
ModularCompilationUnit(
@Nullable String optionalFileName,
ImportDeclaration[] importDeclarations,
ModuleDeclaration moduleDeclaration
) {
super(optionalFileName, importDeclarations);
this.moduleDeclaration = moduleDeclaration;
}
@Override @Nullable public R
accept(AbstractCompilationUnitVisitor visitor) throws EX {
return visitor.visitModularCompilationUnit(this);
}
}
public static final
class ModuleDeclaration extends Located {
public final Modifier[] modifiers;
public final boolean isOpen;
public final String[] moduleName;
public final ModuleDirective[] moduleDirectives;
public
ModuleDeclaration(
Location location,
Modifier[] modifiers,
boolean isOpen,
String[] moduleName,
ModuleDirective[] moduleDirectives
) {
super(location);
this.modifiers = modifiers;
this.isOpen = isOpen;
this.moduleName = moduleName;
this.moduleDirectives = moduleDirectives;
}
}
public
interface ModuleDirective {
@Nullable R
accept(Visitor.ModuleDirectiveVisitor visitor) throws EX;
}
public static final
class RequiresModuleDirective extends Located implements ModuleDirective {
public final Modifier[] requiresModifiers;
public final String[] moduleName;
protected
RequiresModuleDirective(Location location, Modifier[] requiresModifiers, String[] moduleName) {
super(location);
this.requiresModifiers = requiresModifiers;
this.moduleName = moduleName;
}
@Override @Nullable public R
accept(ModuleDirectiveVisitor visitor) throws EX { return visitor.visitRequiresModuleDirective(this); }
}
public static final
class ExportsModuleDirective extends Located implements ModuleDirective {
public final String[] packageName;
public final String[][] toModuleNames;
protected
ExportsModuleDirective(Location location, String[] packageName, String[][] toModuleNames) {
super(location);
this.packageName = packageName;
this.toModuleNames = toModuleNames;
}
@Override @Nullable public R
accept(ModuleDirectiveVisitor visitor) throws EX { return visitor.visitExportsModuleDirective(this); }
}
public static final
class OpensModuleDirective extends Located implements ModuleDirective {
public final String[] packageName;
public final String[][] toModuleNames;
protected
OpensModuleDirective(Location location, String[] packageName, String[][] toModuleNames) {
super(location);
this.packageName = packageName;
this.toModuleNames = toModuleNames;
}
@Override @Nullable public R
accept(ModuleDirectiveVisitor visitor) throws EX { return visitor.visitOpensModuleDirective(this); }
}
public static final
class UsesModuleDirective extends Located implements ModuleDirective {
public final String[] typeName;
protected
UsesModuleDirective(Location location, String[] typeName) {
super(location);
this.typeName = typeName;
}
@Override @Nullable public R
accept(ModuleDirectiveVisitor visitor) throws EX { return visitor.visitUsesModuleDirective(this); }
}
public static final
class ProvidesModuleDirective extends Located implements ModuleDirective {
public final String[] typeName;
public final String[][] withTypeNames;
protected
ProvidesModuleDirective(Location location, String[] typeName, String[][] withTypeNames) {
super(location);
this.typeName = typeName;
this.withTypeNames = withTypeNames;
}
@Override @Nullable public R
accept(ModuleDirectiveVisitor visitor) throws EX { return visitor.visitProvidesModuleDirective(this); }
}
/**
* Representation of a Java annotation.
*/
public
interface Annotation extends Locatable, ElementValue, Modifier {
/**
* Invokes the "{@code visit...()}" method of {@link Visitor.AnnotationVisitor} for the concrete {@link
* Annotation} type.
*/
@Nullable R
accept(Visitor.AnnotationVisitor visitor) throws EX;
/**
* Sets the enclosing scope for this annotation.
*/
@Override
void
setEnclosingScope(Scope enclosingScope);
/**
* @return The type of this annotation
*/
Type getType();
}
/**
* Convenience class.
*/
public abstract static
class AbstractAnnotation implements Annotation {
/**
* The type of this annotation.
*/
public final Type type;
public
AbstractAnnotation(Type type) { this.type = type; }
@Override public void
setEnclosingScope(Scope enclosingScope) { this.type.setEnclosingScope(enclosingScope); }
@Override public Location
getLocation() { return this.type.getLocation(); }
@Override @Nullable public final R
accept(ElementValueVisitor visitor) throws EX { return visitor.visitAnnotation(this); }
@Override @Nullable public final R
accept(ModifierVisitor visitor) throws EX { return this.accept((AnnotationVisitor) visitor); }
@Override public void
throwCompileException(String message) throws CompileException {
throw new CompileException(message, this.getLocation());
}
}
/**
* Representation of a "marker annotation", i.e. an annotation without any elements in parentheses.
*/
public static final
class MarkerAnnotation extends AbstractAnnotation {
public
MarkerAnnotation(Type type) { super(type); }
@Override public String toString() { return "@" + this.type; }
@Override public Type
getType() { return this.type; }
@Override @Nullable public R
accept(Visitor.AnnotationVisitor visitor) throws EX { return visitor.visitMarkerAnnotation(this); }
}
/**
* Representation of a "single-element annotation", i.e. an annotation followed by a single element in parentheses.
*/
public static final
class SingleElementAnnotation extends AbstractAnnotation {
/**
* The element value associated with this single-element annotation.
*/
public final ElementValue elementValue;
public
SingleElementAnnotation(ReferenceType type, ElementValue elementValue) {
super(type);
this.elementValue = elementValue;
}
@Override public void
setEnclosingScope(Scope enclosingScope) {
super.setEnclosingScope(enclosingScope);
this.elementValue.setEnclosingScope(enclosingScope);
}
@Override public String toString() { return "@" + this.type + '(' + this.elementValue + ')'; }
@Override public Type
getType() { return this.type; }
@Override @Nullable public R
accept(Visitor.AnnotationVisitor visitor)
throws EX { return visitor.visitSingleElementAnnotation(this); }
}
/**
* A "normal annotation", i.e. an annotation with multiple elements in parentheses and curly braces.
*/
public static final
class NormalAnnotation extends AbstractAnnotation {
/**
* The element-value-pairs associated with this annotation.
*/
public final ElementValuePair[] elementValuePairs;
public
NormalAnnotation(ReferenceType type, ElementValuePair[] elementValuePairs) {
super(type);
this.elementValuePairs = elementValuePairs;
}
@Override public void
setEnclosingScope(Scope enclosingScope) {
super.setEnclosingScope(enclosingScope);
for (ElementValuePair elementValuePair : this.elementValuePairs) {
elementValuePair.elementValue.setEnclosingScope(enclosingScope);
}
}
@Override public Type
getType() { return this.type; }
@Override public String
toString() {
switch (this.elementValuePairs.length) {
case 0: return "@" + this.type + "()";
case 1: return "@" + this.type + "(" + this.elementValuePairs[0] + ")";
default: return "@" + this.type + "(" + this.elementValuePairs[0] + ", ...)";
}
}
@Override @Nullable public R
accept(Visitor.AnnotationVisitor visitor) throws EX { return visitor.visitNormalAnnotation(this); }
}
/**
* @deprecated Many methods that previously accepted a parameter of this type now take a {@link Modifier}{@code
* []} (incompatible API change in JANINO version 3.0.13)
*/
@Deprecated public static
class Modifiers {
}
/**
* Base for the various modifiers (access modifiers, annotations).
*/
public
interface Modifier extends Locatable {
/**
* Invokes the "{@code visit...()}" method of {@link Visitor.ModifierVisitor} for the concrete
* {@link Modifier} type.
*/
@Nullable R
accept(ModifierVisitor modifierVisitor) throws EX;
}
/**
* Representation of the modifier flags and annotations that are associated with a declaration.
*/
public static
class AccessModifier extends Located implements Modifier {
/**
* {@code "public"}, {@code default}, etc.
*/
public final String keyword;
public
AccessModifier(String keyword, Location location) {
super(location);
this.keyword = keyword;
}
@Override @Nullable public R
accept(ModifierVisitor visitor) throws EX { return visitor.visitAccessModifier(this); }
@Override public String
toString() { return this.keyword; }
}
/**
* Representation of a "name = value" element in a {@link NormalAnnotation}.
*/
public static
class ElementValuePair {
/**
* The element name.
*/
public final String identifier;
/**
* The element value.
*/
public final ElementValue elementValue;
public
ElementValuePair(String identifier, ElementValue elementValue) {
this.identifier = identifier;
this.elementValue = elementValue;
}
@Override public String
toString() { return this.identifier + " = " + this.elementValue; }
}
/**
* Base of the possible element values in a {@link NormalAnnotation}.
*/
public
interface ElementValue extends Locatable {
/**
* Invokes the "{@code visit...()}" method of {@link Visitor.ElementValueVisitor} for the concrete {@link
* ElementValue} type.
*/
@Nullable R
accept(Visitor.ElementValueVisitor visitor) throws EX;
/**
* In most cases, the scope is the enclosing {@link BlockStatement}, except for top-level class/interface
* annotation class-literal element-value-pairs, where the enclosing scope is the compilation unit.
*/
void
setEnclosingScope(Scope scope);
}
/**
* An element value in the form of an array initializer, e.g. "SuppressWarnings({ "null", "unchecked"
* })
".
*/
public static final
class ElementValueArrayInitializer extends Located implements ElementValue {
/**
* The element values in the body of the array initializer.
*/
public final ElementValue[] elementValues;
public
ElementValueArrayInitializer(ElementValue[] elementValues, Location location) {
super(location);
this.elementValues = elementValues;
}
@Override public void
setEnclosingScope(Scope scope) {
for (ElementValue elementValue : this.elementValues) elementValue.setEnclosingScope(scope);
}
@Override public String
toString() {
switch (this.elementValues.length) {
case 0: return "{}";
case 1: return "{ " + this.elementValues[0] + " }";
default: return "{ " + this.elementValues[0] + ", ... }";
}
}
@Override @Nullable public R
accept(Visitor.ElementValueVisitor visitor) throws EX {
return visitor.visitElementValueArrayInitializer(this);
}
}
/**
* Representation of a package declaration like {@code package com.acme.tools;}.
*/
public static
class PackageDeclaration extends Located {
/**
* The package name, e.g. "{@code com.acme.tools}".
*/
public final String packageName;
public
PackageDeclaration(Location location, String packageName) {
super(location);
this.packageName = packageName;
}
}
/**
* Base for the various class declarations (top-level class, local class, anonymous class, nested class, top-level
* enum, nested enum).
*/
public
interface ClassDeclaration extends TypeDeclaration {
/**
* Returns the initializers for class variables (JLS7 8.3.2.1) and instance variables (JLS7 8.3.2.2), and
* the instance initializers (JLS7 8.6) and static initializers (JLS7 8.7) in the order as they appear in
* the type declaration.
*/
List getVariableDeclaratorsAndInitializers();
/**
* @return The synthetic fields that were created while this type declaration was compiled
*/
SortedMap getSyntheticFields();
}
/**
* Base for the various kinds of type declarations, e.g. top-level class, member interface, local class.
*/
public
interface TypeDeclaration extends Annotatable, Locatable, Scope {
/**
* Returns the member type with the given name.
*
* @return {@code null} if a member type with that name is not declared
*/
@Nullable MemberTypeDeclaration getMemberTypeDeclaration(String name);
/**
* @return The (possibly empty) set of member types declared inside this {@link TypeDeclaration}
*/
Collection getMemberTypeDeclarations();
/**
* Returns the first method declared with the given name. (Does not honor inherited methods.)
*
* @return {@code null} if a method with this name is not declared
*/
@Nullable MethodDeclarator getMethodDeclaration(String name);
/**
* @return The list of methods declared in this {@link TypeDeclaration}, not including methods declared in
* supertypes
*/
List getMethodDeclarations();
/**
* Determines the effective class name, e.g. "pkg.Outer$Inner".
*/
String getClassName();
/**
* Creates a unique name for a local class or interface.
*/
String createLocalTypeName(String localTypeName);
/**
* Creates a unique name for an anonymous class.
*/
String createAnonymousClassName();
/**
* Invokes the "{@code visit...()}" method of {@link Visitor.TypeDeclarationVisitor} for the concrete {@link
* TypeDeclaration} type.
*/
@Nullable R accept(Visitor.TypeDeclarationVisitor visitor) throws EX;
}
/**
* Representation of a Java element that can be annotated with a DOC comment ("/** ...
* */
").
*/
public
interface DocCommentable {
/**
* @return The doc comment of the object or {@code null}
*/
@Nullable String getDocComment();
/**
* Returns {@code true} if the object has a doc comment and the {@code @deprecated} tag appears in the doc
* comment.
*/
boolean hasDeprecatedDocTag();
}
/**
* Represents a class or interface declaration on compilation unit level. These are called "package member types"
* because they are immediate members of a package.
*/
public
interface PackageMemberTypeDeclaration extends NamedTypeDeclaration {
/**
* Sets the {@link AbstractCompilationUnit} in which this top-level type is declared.
*/
void
setDeclaringCompilationUnit(CompilationUnit declaringCompilationUnit);
/**
* @return The {@link AbstractCompilationUnit} in which this top-level type is declared.
*/
CompilationUnit
getDeclaringCompilationUnit();
Access
getAccess();
}
/**
* Represents a class or interface declaration where the immediately enclosing scope is another class or interface
* declaration.
*/
public
interface MemberTypeDeclaration extends NamedTypeDeclaration, TypeBodyDeclaration {
Access
getAccess();
}
/**
* Represents the declaration of a class or an interface that has a name. (All type declarations are named, except
* for anonymous classes.)
*/
public
interface NamedTypeDeclaration extends TypeDeclaration {
/**
* @return The declared (not the fully qualified) name of the class or interface
*/
String getName();
/**
* @return The declared type parameters
*/
@Nullable TypeParameter[] getOptionalTypeParameters();
}
/**
* Represents the declaration of an inner class, i.e. a class that exists in the context of zero or more "enclosing
* instances". These are anonymous classes, local classes and member classes.
*/
interface InnerClassDeclaration extends ClassDeclaration {
/**
* Inner classes have zero or more synthetic fields that hold references to their enclosing context:
*
* - {@code this$n}
* -
* (Mandatory for non-private non-static member classes; optional for private non-static
* member classes, local classes in non-static context, and anonymous classes in
* non-static context; forbidden for static member classes, local classes in static
* context, and anonymous classes in static context)
* Holds a reference to the immediately enclosing instance. {@code n} is
* N-1 for the Nth nesting level; e.g. the public non-static member class of a
* package member class has a synthetic field {@code this$0}.
*
* - {@code val$local-variable-name}
* -
* (Allowed for local classes and anonymous classes; forbidden for member classes)
* Hold copies of {@code final} local variables of the defining context.
*
*
*
* Notice that these fields are not included in the {@link IClass.IField} array returned by {@link
* IClass#getDeclaredIFields2()}.
*
*
* If a synthetic field with the same name exists already, then it must have the same type and the
* redefinition is ignored.
*
*
* @param iField
*/
void defineSyntheticField(IClass.IField iField) throws CompileException;
}
/**
* Abstract implementation of {@link TypeDeclaration}.
*/
public abstract static
class AbstractTypeDeclaration implements TypeDeclaration {
private final Location location;
private final Modifier[] modifiers;
@Nullable private final TypeParameter[] optionalTypeParameters;
private final List declaredMethods = new ArrayList();
private final List declaredClassesAndInterfaces = new ArrayList();
@Nullable private Scope enclosingScope;
/**
* Holds the resolved type during compilation.
*/
@Nullable IClass resolvedType;
public
AbstractTypeDeclaration(
Location location,
Modifier[] modifiers,
@Nullable TypeParameter[] optionalTypeParameters
) {
this.location = location;
this.modifiers = modifiers;
this.optionalTypeParameters = optionalTypeParameters;
}
/**
* Sets the enclosing scope of this {@link TypeDeclaration}.
*/
public void
setEnclosingScope(Scope enclosingScope) {
if (this.enclosingScope != null && enclosingScope != this.enclosingScope) {
throw new InternalCompilerException(
"Enclosing scope is already set for type declaration \""
+ this.toString()
+ "\" at "
+ this.getLocation()
);
}
this.enclosingScope = enclosingScope;
for (Modifier m : this.modifiers) {
if (m instanceof Annotation) ((Annotation) m).setEnclosingScope(enclosingScope);
}
if (this.optionalTypeParameters != null) {
for (TypeParameter tp : this.optionalTypeParameters) {
if (tp.optionalBound != null) {
for (ReferenceType boundType : tp.optionalBound) {
boundType.setEnclosingScope(enclosingScope);
}
}
}
}
}
public Modifier[]
getModifiers() { return this.modifiers; }
@Override public Annotation[]
getAnnotations() { return Java.getAnnotations(this.modifiers); }
@Nullable public TypeParameter[]
getOptionalTypeParameters() { return this.optionalTypeParameters; }
@Override public Scope
getEnclosingScope() { assert this.enclosingScope != null; return this.enclosingScope; }
/**
* Invalidates the method cache of the {@link #resolvedType}. This is necessary when methods are added
* during compilation
*/
public void
invalidateMethodCaches() {
if (this.resolvedType != null) {
this.resolvedType.invalidateMethodCaches();
}
}
/**
* Adds one {@link MemberTypeDeclaration} to this type.
*/
public void
addMemberTypeDeclaration(MemberTypeDeclaration mcoid) {
this.declaredClassesAndInterfaces.add(mcoid);
mcoid.setDeclaringType(this);
}
/**
* Adds one {@link MethodDeclarator} to this type.
*/
public void
addDeclaredMethod(MethodDeclarator method) {
this.declaredMethods.add(method);
method.setDeclaringType(this);
}
// Implement TypeDeclaration.
@Override public Collection
getMemberTypeDeclarations() { return this.declaredClassesAndInterfaces; }
@Override @Nullable public MemberTypeDeclaration
getMemberTypeDeclaration(String name) {
for (MemberTypeDeclaration mtd : this.declaredClassesAndInterfaces) {
if (mtd.getName().equals(name)) return mtd;
}
return null;
}
@Override @Nullable public MethodDeclarator
getMethodDeclaration(String name) {
for (MethodDeclarator md : this.declaredMethods) {
if (md.name.equals(name)) return md;
}
return null;
}
@Override public List
getMethodDeclarations() { return this.declaredMethods; }
@Override public String
createLocalTypeName(String localTypeName) {
return (
this.getClassName()
+ '$'
+ ++this.localClassCount
+ '$'
+ localTypeName
);
}
@Override public String
createAnonymousClassName() {
return (
this.getClassName()
+ '$'
+ ++this.anonymousClassCount
);
}
// Implement "Locatable".
@Override public Location
getLocation() { return this.location; }
@Override public void
throwCompileException(String message) throws CompileException {
throw new CompileException(message, this.location);
}
@Override public abstract String
toString();
/**
* For naming anonymous classes.
*/
public int anonymousClassCount;
/**
* For naming local classes.
*/
public int localClassCount;
}
/**
* Base for the various class declaration kinds.
*/
public abstract static
class AbstractClassDeclaration extends AbstractTypeDeclaration implements ClassDeclaration {
/**
* List of {@link ConstructorDeclarator}s of this class.
*/
public final List constructors = new ArrayList();
/**
* List of {@link TypeBodyDeclaration}s of this class: Field declarations (both static and non-static),
* (static and non-static) initializers (a.k.a. "class initializers" and "instance initializers").
*/
public final List variableDeclaratorsAndInitializers = new ArrayList();
public
AbstractClassDeclaration(
Location location,
Modifier[] modifiers,
@Nullable TypeParameter[] optionalTypeParameters
) { super(location, modifiers, optionalTypeParameters); }
/**
* Adds one {@link ConstructorDeclarator} to this class.
*/
public void
addConstructor(ConstructorDeclarator cd) {
this.constructors.add(cd);
cd.setDeclaringType(this);
}
/**
* Adds one field declaration to this class.
*/
public void
addFieldDeclaration(FieldDeclaration fd) {
this.variableDeclaratorsAndInitializers.add(fd);
fd.setDeclaringType(this);
// Clear resolved type cache.
if (this.resolvedType != null) this.resolvedType.clearIFieldCaches();
}
/**
* Adds one initializer to this class.
*/
public void
addInitializer(Initializer i) {
this.variableDeclaratorsAndInitializers.add(i);
i.setDeclaringType(this);
// Clear resolved type cache.
if (this.resolvedType != null) this.resolvedType.clearIFieldCaches();
}
// Compile time members.
// Forward-implement InnerClassDeclaration.
/**
* @see Java.InnerClassDeclaration#defineSyntheticField(IClass.IField)
*/
public void
defineSyntheticField(IClass.IField iField) throws CompileException {
if (!(this instanceof InnerClassDeclaration)) throw new InternalCompilerException();
IClass.IField if2 = (IClass.IField) this.syntheticFields.get(iField.getName());
if (if2 != null) {
if (iField.getType() != if2.getType()) throw new InternalCompilerException();
return;
}
this.syntheticFields.put(iField.getName(), iField);
}
@Override public List
getVariableDeclaratorsAndInitializers() {
return this.variableDeclaratorsAndInitializers;
}
/**
* @return The declared constructors, or the default constructor
*/
ConstructorDeclarator[]
getConstructors() {
if (this.constructors.isEmpty()) {
ConstructorDeclarator defaultConstructor = new ConstructorDeclarator(
this.getLocation(), // location
null, // optionalDocComment
Java.accessModifiers(this.getLocation(), "public"), // modifiers
new FormalParameters(this.getLocation()), // formalParameters
new Type[0], // thrownExceptions
null, // optionalExplicitConstructorInvocation
Collections.emptyList() // optionalStatements
);
defaultConstructor.setDeclaringType(this);
return new ConstructorDeclarator[] { defaultConstructor };
}
return (ConstructorDeclarator[]) this.constructors.toArray(
new ConstructorDeclarator[this.constructors.size()]
);
}
@Override public SortedMap
getSyntheticFields() { return this.syntheticFields; }
/**
* All field names start with "this$" or "val$".
*/
final SortedMap syntheticFields = new TreeMap();
}
/**
* Representation of a JLS7 15.9.5 "anonymous class declaration".
*/
public static final
class AnonymousClassDeclaration extends AbstractClassDeclaration implements InnerClassDeclaration {
/**
* Base class or interface.
*/
public final Type baseType;
public
AnonymousClassDeclaration(Location location, Type baseType) {
super(
location, // location
Java.accessModifiers(location, "private", "final"), // modifiers
null // optionalTypeParameters
);
(this.baseType = baseType).setEnclosingScope(new EnclosingScopeOfTypeDeclaration(this));
}
@Override @Nullable public R
accept(Visitor.TypeDeclarationVisitor visitor) throws EX {
return visitor.visitAnonymousClassDeclaration(this);
}
// Implement TypeDeclaration.
@Override public String
getClassName() {
if (this.myName != null) return this.myName;
Scope s = this.getEnclosingScope();
for (; !(s instanceof TypeDeclaration); s = s.getEnclosingScope());
return (this.myName = ((TypeDeclaration) s).createAnonymousClassName());
}
@Nullable private String myName;
@Override public String
toString() { return this.getClassName(); }
}
/**
* Base for the various named class declarations.
*/
public abstract static
class NamedClassDeclaration extends AbstractClassDeclaration implements NamedTypeDeclaration, DocCommentable {
@Nullable private final String optionalDocComment;
/**
* The simple name of this class.
*/
public final String name;
/**
* The type of the extended class.
*/
@Nullable public final Type optionalExtendedType;
/**
* The types of the implemented interfaces.
*/
public final Type[] implementedTypes;
public
NamedClassDeclaration(
Location location,
@Nullable String optionalDocComment,
Modifier[] modifiers,
String name,
@Nullable TypeParameter[] optionalTypeParameters,
@Nullable Type optionalExtendedType,
Type[] implementedTypes
) {
super(location, modifiers, optionalTypeParameters);
this.optionalDocComment = optionalDocComment;
this.name = name;
this.optionalExtendedType = optionalExtendedType;
if (optionalExtendedType != null) {
optionalExtendedType.setEnclosingScope(new EnclosingScopeOfTypeDeclaration(this));
}
this.implementedTypes = implementedTypes;
for (Type implementedType : implementedTypes) {
implementedType.setEnclosingScope(new EnclosingScopeOfTypeDeclaration(this));
}
}
@Override public String
toString() { return this.name; }
// Implement NamedTypeDeclaration.
@Override public String
getName() { return this.name; }
// Implement DocCommentable.
@Override @Nullable public String
getDocComment() { return this.optionalDocComment; }
@Override public boolean
hasDeprecatedDocTag() {
return this.optionalDocComment != null && this.optionalDocComment.indexOf("@deprecated") != -1;
}
public boolean
isAbstract() { return Java.hasAccessModifier(this.getModifiers(), "abstract"); }
public boolean
isFinal() { return Java.hasAccessModifier(this.getModifiers(), "final"); }
public boolean
isStrictfp() { return Java.hasAccessModifier(this.getModifiers(), "strictfp"); }
}
/**
* Lazily determines and returns the enclosing {@link Java.Scope} of the given {@link Java.TypeDeclaration}.
*/
public static final
class EnclosingScopeOfTypeDeclaration implements Scope {
/**
* The specific type declaration.
*/
public final TypeDeclaration typeDeclaration;
public
EnclosingScopeOfTypeDeclaration(TypeDeclaration typeDeclaration) { this.typeDeclaration = typeDeclaration; }
@Override public Scope
getEnclosingScope() { return this.typeDeclaration.getEnclosingScope(); }
}
/**
* Representation of a "member class declaration", i.e. a class declaration that appears inside another class or
* interface declaration.
*/
public static
class MemberClassDeclaration extends NamedClassDeclaration implements MemberTypeDeclaration, InnerClassDeclaration {
public
MemberClassDeclaration(
Location location,
@Nullable String optionalDocComment,
Modifier[] modifiers,
String name,
@Nullable TypeParameter[] optionalTypeParameters,
@Nullable Type optionalExtendedType,
Type[] implementedTypes
) {
super(
location, // location
optionalDocComment, // optionalDocComment
modifiers, // modifiers
name, // name
optionalTypeParameters, // optionalTypeParameters
optionalExtendedType, // optionalExtendedType
implementedTypes // implementedTypes
);
}
@Override public Access
getAccess() { return Java.modifiers2Access(this.getModifiers()); }
// Implement TypeBodyDeclaration.
@Override public void
setDeclaringType(TypeDeclaration declaringType) { this.setEnclosingScope(declaringType); }
@Override public TypeDeclaration
getDeclaringType() { return (TypeDeclaration) this.getEnclosingScope(); }
// Implement TypeDeclaration.
@Override public String
getClassName() { return this.getDeclaringType().getClassName() + '$' + this.getName(); }
// SUPPRESS CHECKSTYLE LineLength:2
@Override @Nullable public R accept(Visitor.TypeDeclarationVisitor visitor) throws EX { return visitor.visitMemberClassDeclaration(this); }
@Override @Nullable public R accept(Visitor.TypeBodyDeclarationVisitor visitor) throws EX { return visitor.visitMemberClassDeclaration(this); }
public boolean
isStatic() { return Java.hasAccessModifier(this.getModifiers(), "static"); }
}
/**
* Representation of a "member enum declaration", i.e. an enum declaration that appears inside another class or
* interface declaration.
*/
public static final
class MemberEnumDeclaration extends MemberClassDeclaration implements EnumDeclaration {
private final List constants = new ArrayList();
public
MemberEnumDeclaration(
Location location,
@Nullable String optionalDocComment,
Modifier[] modifiers,
String name,
Type[] implementedTypes
) {
super(
location, // location
optionalDocComment, // optionalDocComment
modifiers, // modifiers
name, // name
null, // optionalTypeParameters
null, // optionalExtendedType
implementedTypes // implementedTypes
);
}
@Override public Type[]
getImplementedTypes() { return this.implementedTypes; }
@Override public List
getConstants() { return this.constants; }
@Override public void
addConstant(EnumConstant ec) { this.constants.add(ec); }
// SUPPRESS CHECKSTYLE LineLength:2
@Override @Nullable public R accept(Visitor.TypeDeclarationVisitor visitor) throws EX { return visitor.visitMemberEnumDeclaration(this); }
@Override @Nullable public R accept(Visitor.TypeBodyDeclarationVisitor visitor) throws EX { return visitor.visitMemberEnumDeclaration(this); }
}
/**
* Representation of a "local class declaration" i.e. a class declaration that appears inside a method body.
*/
public static final
class LocalClassDeclaration extends NamedClassDeclaration implements InnerClassDeclaration {
public
LocalClassDeclaration(
Location location,
@Nullable String optionalDocComment,
Modifier[] modifiers,
String name,
@Nullable TypeParameter[] optionalTypeParameters,
@Nullable Type optionalExtendedType,
Type[] implementedTypes
) {
super(
location, // location
optionalDocComment, // optionalDocComment
modifiers, // modifiers
name, // name
optionalTypeParameters, // optionalTypeParameters
optionalExtendedType, // optionalExtendedType
implementedTypes // implementedTypes
);
}
// Implement TypeDeclaration.
@Override public String
getClassName() {
for (Scope s = this.getEnclosingScope();; s = s.getEnclosingScope()) {
if (s instanceof Java.TypeDeclaration) {
return ((Java.TypeDeclaration) s).getClassName() + '$' + this.name;
}
}
}
@Override @Nullable public R
accept(Visitor.TypeDeclarationVisitor visitor) throws EX {
return visitor.visitLocalClassDeclaration(this);
}
}
/**
* Implementation of a "package member class declaration", a.k.a. "top-level class declaration".
*/
public static
class PackageMemberClassDeclaration extends NamedClassDeclaration implements PackageMemberTypeDeclaration {
public
PackageMemberClassDeclaration(
Location location,
@Nullable String optionalDocComment,
Modifier[] modifiers,
String name,
@Nullable TypeParameter[] optionalTypeParameters,
@Nullable Type optionalExtendedType,
Type[] implementedTypes
) {
super(
location, // location
optionalDocComment, // optionalDocComment
modifiers, // modifiers
name, // name
optionalTypeParameters, // optionalTypeParameters
optionalExtendedType, // optionalExtendedType
implementedTypes // implementedTypes
);
}
// Implement PackageMemberTypeDeclaration.
@Override public void
setDeclaringCompilationUnit(CompilationUnit declaringCompilationUnit) {
this.setEnclosingScope(declaringCompilationUnit);
}
@Override public CompilationUnit
getDeclaringCompilationUnit() { return (CompilationUnit) this.getEnclosingScope(); }
@Override public Access
getAccess() { return Java.modifiers2Access(this.getModifiers()); }
// Implement TypeDeclaration.
@Override public String
getClassName() {
String className = this.getName();
CompilationUnit compilationUnit = (CompilationUnit) this.getEnclosingScope();
PackageDeclaration opd = compilationUnit.optionalPackageDeclaration;
if (opd != null) className = opd.packageName + '.' + className;
return className;
}
@Override @Nullable public R
accept(TypeDeclarationVisitor visitor) throws EX {
return visitor.visitPackageMemberClassDeclaration(this);
}
public boolean
isStatic() { return Java.hasAccessModifier(this.getModifiers(), "static"); }
}
/**
* Base for package member (a.k.a. "top-level") enum declarations and nested enum declarations.
*/
public
interface EnumDeclaration extends ClassDeclaration, NamedTypeDeclaration, DocCommentable {
Modifier[] getModifiers();
@Override String getName();
/**
* @return The interfaces that this enum implements
*/
Type[] getImplementedTypes();
/**
* @return The constants that this enum declares
*/
List getConstants();
/**
* Adds another constant to this enum declaration.
*/
void addConstant(Java.EnumConstant ec);
}
/**
* Representation of an "enum constant", see JLS7 8.9.1.
*/
public static final
class EnumConstant extends AbstractClassDeclaration implements DocCommentable {
/**
* The optional "doc comment" that appeared in the compilation unit immediately before this enum constant
* declaration.
*/
@Nullable public final String optionalDocComment;
/**
* The name of the declared enum constant.
*/
public final String name;
/**
* The optional arguments that appear after the enum constant name iff the enum declares constructors with
* one or more parameters.
*/
@Nullable public final Rvalue[] optionalArguments;
public
EnumConstant(
Location location,
@Nullable String optionalDocComment,
Modifier[] modifiers,
String name,
@Nullable Rvalue[] optionalArguments
) {
super(location, modifiers, null);
this.optionalDocComment = optionalDocComment;
this.name = name;
this.optionalArguments = optionalArguments;
}
@Override public String
getClassName() { return this.name; }
@Override @Nullable public String
getDocComment() { return this.optionalDocComment; }
@Override public boolean
hasDeprecatedDocTag() {
return this.optionalDocComment != null && this.optionalDocComment.indexOf("@deprecated") != -1;
}
@Override @Nullable public R
accept(Visitor.TypeDeclarationVisitor visitor) throws EX {
return visitor.visitEnumConstant(this);
}
@Override public String
toString() { return "enum " + this.name + " { ... }"; }
}
/**
* Implementation of a "package member enum declaration", a.k.a. "top-level enum declaration".
*/
public static final
class PackageMemberEnumDeclaration extends PackageMemberClassDeclaration implements EnumDeclaration {
private final List constants = new ArrayList();
public
PackageMemberEnumDeclaration(
Location location,
@Nullable String optionalDocComment,
Modifier[] modifiers,
String name,
Type[] implementedTypes
) {
super(
location,
optionalDocComment,
modifiers,
name,
null, // optionalTypeParameters
null, // optionalExtendedType
implementedTypes
);
}
@Override public Type[]
getImplementedTypes() { return this.implementedTypes; }
@Override public List
getConstants() { return this.constants; }
@Override public void
addConstant(EnumConstant ec) { this.constants.add(ec); }
@Override @Nullable public R
accept(Visitor.TypeDeclarationVisitor visitor) throws EX {
return visitor.visitPackageMemberEnumDeclaration(this);
}
}
/**
* Base for the various interface declaration kinds.
*/
public abstract static
class InterfaceDeclaration extends AbstractTypeDeclaration implements NamedTypeDeclaration, DocCommentable {
@Nullable private final String optionalDocComment;
/**
* The simple name of the interface.
*/
public final String name;
protected
InterfaceDeclaration(
Location location,
@Nullable String optionalDocComment,
Modifier[] modifiers,
String name,
@Nullable TypeParameter[] optionalTypeParameters,
Type[] extendedTypes
) {
super(location, modifiers, optionalTypeParameters);
this.optionalDocComment = optionalDocComment;
this.name = name;
this.extendedTypes = extendedTypes;
for (Type extendedType : extendedTypes) {
extendedType.setEnclosingScope(new EnclosingScopeOfTypeDeclaration(this));
}
}
@Override public String
toString() { return this.name; }
/**
* Adds one constant declaration to this interface declaration.
*/
public void
addConstantDeclaration(FieldDeclaration fd) {
this.constantDeclarations.add(fd);
fd.setDeclaringType(this);
// Clear resolved type cache.
if (this.resolvedType != null) this.resolvedType.clearIFieldCaches();
}
/**
* The types of the interfaces that this interface extends.
*/
public final Type[] extendedTypes;
/**
* The constants that this interface declares.
*/
public final List constantDeclarations = new ArrayList();
/**
* Set during "compile()".
*/
@Nullable IClass[] interfaces;
// Implement NamedTypeDeclaration.
@Override public String
getName() { return this.name; }
// Implement DocCommentable.
@Override @Nullable public String
getDocComment() { return this.optionalDocComment; }
@Override public boolean
hasDeprecatedDocTag() {
return this.optionalDocComment != null && this.optionalDocComment.indexOf("@deprecated") != -1;
}
}
/**
* Representation of a "member interface declaration", i.e. an interface declaration that appears inside another
* class or interface declaration.
*/
public static
class MemberInterfaceDeclaration
extends InterfaceDeclaration
implements MemberTypeDeclaration {
public
MemberInterfaceDeclaration(
Location location,
@Nullable String optionalDocComment,
Modifier[] modifiers,
String name,
@Nullable TypeParameter[] optionalTypeParameters,
Type[] extendedTypes
) {
super(
location, // location
optionalDocComment, // optionalDocComment
modifiers, // modifiers
name, // name
optionalTypeParameters, // optionalTypeParameters
extendedTypes // extendedTypes
);
}
// Implement MemberTypeDeclaration.
@Override public Access
getAccess() { return Java.modifiers2Access(this.getModifiers()); }
// Implement TypeDeclaration.
@Override public String
getClassName() {
NamedTypeDeclaration declaringType = (NamedTypeDeclaration) this.getEnclosingScope();
return (
declaringType.getClassName()
+ '$'
+ this.getName()
);
}
// Implement TypeBodyDeclaration.
@Override public void
setDeclaringType(TypeDeclaration declaringType) { this.setEnclosingScope(declaringType); }
@Override public TypeDeclaration
getDeclaringType() { return (TypeDeclaration) this.getEnclosingScope(); }
// SUPPRESS CHECKSTYLE LineLength:2
@Override @Nullable public R accept(Visitor.TypeDeclarationVisitor visitor) throws EX { return visitor.visitMemberInterfaceDeclaration(this); }
@Override @Nullable public R accept(Visitor.TypeBodyDeclarationVisitor visitor) throws EX { return visitor.visitMemberInterfaceDeclaration(this); }
}
/**
* Representation of a member annotation type declaration, a.k.a. "nested annotation type declaration".
*/
public static final
class MemberAnnotationTypeDeclaration extends MemberInterfaceDeclaration implements AnnotationTypeDeclaration {
public
MemberAnnotationTypeDeclaration(
Location location,
@Nullable String optionalDocComment,
Modifier[] modifiers,
String name
) {
super(
location, // location
optionalDocComment, // optionalDocComment
modifiers, // modifiers
name, // name
null, // optionalTypeParameters
new Type[] { new ReferenceType( // extendedTypes
location,
new Annotation[0],
new String[] { "java", "lang", "annotation", "Annotation" },
null // optionalTypeArguments
)}
);
}
// SUPPRESS CHECKSTYLE LineLength:2
@Override @Nullable public R accept(Visitor.TypeDeclarationVisitor visitor) throws EX { return visitor.visitMemberAnnotationTypeDeclaration(this); }
@Override @Nullable public R accept(Visitor.TypeBodyDeclarationVisitor visitor) throws EX { return visitor.visitMemberAnnotationTypeDeclaration(this); }
}
/**
* Representation of a "package member interface declaration", a.k.a. "top-level interface declaration".
*
* {@link PackageMemberAnnotationTypeDeclaration} extends this class.
*
*/
public static
class PackageMemberInterfaceDeclaration extends InterfaceDeclaration implements PackageMemberTypeDeclaration {
public
PackageMemberInterfaceDeclaration(
Location location,
@Nullable String optionalDocComment,
Modifier[] modifiers,
String name,
@Nullable TypeParameter[] optionalTypeParameters,
Type[] extendedTypes
) {
super(
location, // location
optionalDocComment, // optionalDocComment
modifiers, // modifiers
name, // name
optionalTypeParameters, // optionalTypeParameters
extendedTypes // extendedTypes
);
}
// Implement PackageMemberTypeDeclaration.
@Override public void
setDeclaringCompilationUnit(CompilationUnit declaringCompilationUnit) {
this.setEnclosingScope(declaringCompilationUnit);
}
@Override public CompilationUnit
getDeclaringCompilationUnit() { return (CompilationUnit) this.getEnclosingScope(); }
@Override public Access
getAccess() { return Java.modifiers2Access(this.getModifiers()); }
@Override public Annotation[]
getAnnotations() { return Java.getAnnotations(this.getModifiers()); }
public boolean isAbstract() { return Java.hasAccessModifier(this.getModifiers(), "abstract"); }
public boolean isStatic() { return Java.hasAccessModifier(this.getModifiers(), "static"); }
public boolean isStrictfp() { return Java.hasAccessModifier(this.getModifiers(), "strictfp"); }
// Implement TypeDeclaration.
@Override public String
getClassName() {
String className = this.getName();
CompilationUnit compilationUnit = (CompilationUnit) this.getEnclosingScope();
PackageDeclaration opd = compilationUnit.optionalPackageDeclaration;
if (opd != null) className = opd.packageName + '.' + className;
return className;
}
@Override @Nullable public R
accept(Visitor.TypeDeclarationVisitor visitor) throws EX {
return visitor.visitPackageMemberInterfaceDeclaration(this);
}
}
/**
* Representation of a package member annotation type declaration, a.k.a. "top-level annotation type declaration".
*/
public static final
class PackageMemberAnnotationTypeDeclaration
extends PackageMemberInterfaceDeclaration
implements AnnotationTypeDeclaration {
public
PackageMemberAnnotationTypeDeclaration(
Location location,
@Nullable String optionalDocComment,
Modifier[] modifiers,
String name
) {
super(
location,
optionalDocComment,
modifiers, // modifiers
name, // name
null, // optionalTypeParameters
new Type[] { new ReferenceType( // extendedTypes
location, // location
new Annotation[0], // annotations
new String[] { "java", "lang", "annotation", "Annotation" }, // identifiers
null // optionalTypeArguments
)}
);
}
@Override @Nullable public R
accept(Visitor.TypeDeclarationVisitor visitor) throws EX {
return visitor.visitPackageMemberAnnotationTypeDeclaration(this);
}
}
/**
* Base for package member ("top-level") and member ("nested") annotation type declarations.
*/
public
interface AnnotationTypeDeclaration extends NamedTypeDeclaration, DocCommentable {
Modifier[] getModifiers();
}
/**
* Representation of a type parameter (which declares a type variable).
*/
public static
class TypeParameter {
/**
* The name of the type variable.
*/
public final String name;
/**
* The optional bound of the type parameter.
*/
@Nullable public final ReferenceType[] optionalBound;
public
TypeParameter(String name, @Nullable ReferenceType[] optionalBound) {
assert name != null;
this.name = name;
this.optionalBound = optionalBound;
}
@Override public String
toString() {
return (
this.optionalBound != null
? this.name + " extends " + Java.join(this.optionalBound, " & ")
: this.name
);
}
}
/**
* Representation of a "ClassBodyDeclaration" or an "InterfaceMemberDeclaration". These are:
*
* - Field declarators
* - Method declarators
* - Static and non-static initializers
* - Member type declarations
*
*/
public
interface TypeBodyDeclaration extends Locatable, Scope {
/**
* Sets the type declaration that this declaration belongs to.
*/
void setDeclaringType(TypeDeclaration declaringType);
/**
* @return The type declaration that this declaration belongs to.
*/
TypeDeclaration getDeclaringType();
Modifier[] getModifiers();
/**
* Invokes the "{@code visit...()}" method of {@link Visitor.TypeBodyDeclarationVisitor} for the concrete
* {@link TypeBodyDeclaration} type.
*/
@Nullable R
accept(Visitor.TypeBodyDeclarationVisitor visitor) throws EX;
}
/**
* Abstract implementation of {@link TypeBodyDeclaration}.
*/
public abstract static
class AbstractTypeBodyDeclaration extends Located implements TypeBodyDeclaration {
@Nullable private TypeDeclaration declaringType;
public final Modifier[] modifiers;
protected
AbstractTypeBodyDeclaration(Location location, Modifier[] modifiers) {
super(location);
this.modifiers = modifiers;
}
// Implement TypeBodyDeclaration.
@Override public void
setDeclaringType(TypeDeclaration declaringType) {
if (this.declaringType != null) {
throw new InternalCompilerException(
"Declaring type for type body declaration \""
+ this.toString()
+ "\"at "
+ this.getLocation()
+ " is already set"
);
}
this.declaringType = declaringType;
}
@Override public TypeDeclaration
getDeclaringType() { assert this.declaringType != null; return this.declaringType; }
@Override public Modifier[]
getModifiers() { return this.modifiers; }
/**
* @return The annotations of this function
*/
public Annotation[]
getAnnotations() { return Java.getAnnotations(this.modifiers); }
/**
* Forward-implements {@link BlockStatement#setEnclosingScope(Java.Scope)}.
*/
public void
setEnclosingScope(Scope enclosingScope) {
// Catch 22: In the initializers, some statements have their enclosing scope already set!
if (
enclosingScope instanceof Java.MethodDeclarator
&& "".equals(((Java.MethodDeclarator) enclosingScope).name)
) {
return;
}
assert this.declaringType == null;
this.declaringType = (TypeDeclaration) enclosingScope;
}
// Implement "Scope".
@Override public Scope
getEnclosingScope() { assert this.declaringType != null; return this.declaringType; }
}
/**
* Representation of an "instance initializer" (JLS7 8.6) or "static initializer" (JLS7 8.7).
*/
public static final
class Initializer extends AbstractTypeBodyDeclaration implements BlockStatement {
/**
* The block that poses the initializer.
*/
public final Block block;
public
Initializer(Location location, Modifier[] modifiers, Block block) {
super(location, modifiers);
(this.block = block).setEnclosingScope(this);
}
public boolean
isStatic() { return Java.hasAccessModifier(this.getModifiers(), "static"); }
@Override public String
toString() { return Java.toString(this.getModifiers()) + this.block; }
// Implement BlockStatement.
// SUPPRESS CHECKSTYLE LineLength:2
@Override @Nullable public R accept(Visitor.TypeBodyDeclarationVisitor visitor) throws EX { return visitor.visitInitializer(this); }
@Override @Nullable public R accept(Visitor.BlockStatementVisitor visitor) throws EX { return visitor.visitInitializer(this); }
@Override @Nullable public Java.LocalVariable
findLocalVariable(String name) { return this.block.findLocalVariable(name); }
}
/**
* Abstract base class for {@link Java.ConstructorDeclarator} and {@link Java.MethodDeclarator}.
*/
public abstract static
class FunctionDeclarator extends AbstractTypeBodyDeclaration implements Annotatable, DocCommentable {
@Nullable private final String optionalDocComment;
/**
* The return type of the function (VOID for constructors).
*/
public final Type type;
/**
* The name of the function ({@code ""} for constructors).
*/
public final String name;
/**
* The parameters of the function.
*/
public final FormalParameters formalParameters;
/**
* The types of the declared exceptions.
*/
public final Type[] thrownExceptions;
/**
* The statements that comprise the function; {@code null} for abstract method declarations.
*/
@Nullable public final List extends BlockStatement> optionalStatements;
public
FunctionDeclarator(
Location location,
@Nullable String optionalDocComment,
Modifier[] modifiers,
Type type,
String name,
FormalParameters formalParameters,
Type[] thrownExceptions,
@Nullable List extends BlockStatement> optionalStatements
) {
super(location, modifiers);
this.optionalDocComment = optionalDocComment;
this.type = type;
this.name = name;
this.formalParameters = formalParameters;
this.thrownExceptions = thrownExceptions;
this.optionalStatements = optionalStatements;
this.type.setEnclosingScope(this);
for (FormalParameter fp : formalParameters.parameters) fp.type.setEnclosingScope(this);
for (Type te : thrownExceptions) te.setEnclosingScope(this);
if (optionalStatements != null) {
for (Java.BlockStatement bs : optionalStatements) {
// Field declaration initializers are also BlockStatements - their enclosing scope is already
// set (the enclosing type declaration), and must not be re-set here.
if (!(bs instanceof FieldDeclaration)) bs.setEnclosingScope(this);
}
}
}
public Access
getAccess() { return Java.modifiers2Access(this.getModifiers()); }
@Override public Annotation[]
getAnnotations() { return Java.getAnnotations(this.getModifiers()); }
@Override @Nullable public final R
accept(Visitor.TypeBodyDeclarationVisitor visitor) throws EX {
return visitor.visitFunctionDeclarator(this);
}
/**
* Invokes the "{@code visit...()}" method of {@link Visitor.FunctionDeclaratorVisitor} for the concrete
* {@link FunctionDeclarator} type.
*/
@Nullable public abstract R
accept(Visitor.FunctionDeclaratorVisitor visitor) throws EX;
// Override "AbstractTypeBodyDeclaration"
@Override public void
setDeclaringType(TypeDeclaration declaringType) {
super.setDeclaringType(declaringType);
for (Annotation a : this.getAnnotations()) a.setEnclosingScope(declaringType);
}
@Override public void
setEnclosingScope(Scope enclosingScope) {
super.setEnclosingScope(enclosingScope);
for (Annotation a : this.getAnnotations()) a.setEnclosingScope(enclosingScope);
}
// Implement "Scope".
@Override public Scope
getEnclosingScope() { return this.getDeclaringType(); }
/**
* Set by "compile()".
*/
@Nullable IClass returnType;
// Implement DocCommentable.
@Override @Nullable public String
getDocComment() { return this.optionalDocComment; }
@Override public boolean
hasDeprecatedDocTag() {
return this.optionalDocComment != null && this.optionalDocComment.indexOf("@deprecated") != -1;
}
/**
* Representation of the (formal) function parameters.
*/
public static final
class FormalParameters extends Located {
/**
* The parameters of this function, but not the {@link #variableArity}.
*/
public final FormalParameter[] parameters;
/**
* Whether this method has "variable arity", i.e. its last parameter has an ellipsis ("...") after the
* type.
*/
public final boolean variableArity;
public
FormalParameters(Location location) { this(location, new FormalParameter[0], false); }
public
FormalParameters(Location location, FormalParameter[] parameters, boolean variableArity) {
super(location);
this.parameters = parameters;
this.variableArity = variableArity;
}
@Override public String
toString() {
if (this.parameters.length == 0) return "()";
StringBuilder sb = new StringBuilder("(");
for (int i = 0; i < this.parameters.length; i++) {
if (i > 0) sb.append(", ");
sb.append(this.parameters[i].toString(i == this.parameters.length - 1 && this.variableArity));
}
return sb.append(')').toString();
}
}
/**
* Representation of a (formal) function parameter.
*/
public static final
class FormalParameter extends Located {
public final Modifier[] modifiers;
/**
* The type of the parameter.
*/
public final Type type;
/**
* The name of the parameter.
*/
public final String name;
public
FormalParameter(Location location, Modifier[] modifiers, Type type, String name) {
super(location);
this.modifiers = modifiers;
this.type = type;
this.name = name;
}
public boolean
isFinal() { return Java.hasAccessModifier(this.modifiers, "final"); }
/**
* @param hasEllipsis Whether this is the last function parameter and has an ellipsis ("...") after the
* type
*/
public String
toString(boolean hasEllipsis) { return this.type.toString() + (hasEllipsis ? "... " : " ") + this.name; }
@Override public String
toString() { return this.toString(false); }
// Compile time members.
/**
* The local variable associated with this parameter.
*/
@Nullable public Java.LocalVariable localVariable;
}
// Compile time members
/**
* Mapping of variable names to {@link LocalVariable}s.
*/
@Nullable public Map localVariables;
public boolean
isStrictfp() { return Java.hasAccessModifier(this.getModifiers(), "strictfp"); }
}
/**
* Representation of a "catch" parameter.
*/
public static final
class CatchParameter extends Located {
/**
* Whether the parameter is declared FINAL.
*/
public final boolean finaL;
/**
* The types of the parameter.
*/
public final Type[] types;
/**
* The name of the parameter.
*/
public final String name;
/**
* The local variable associated with this parameter.
*/
@Nullable public Java.LocalVariable localVariable;
public
CatchParameter(Location location, boolean finaL, Type[] types, String name) {
super(location);
this.finaL = finaL;
this.types = types;
this.name = name;
}
@Override public String
toString() {
StringBuilder sb = new StringBuilder();
if (this.finaL) sb.append("final ");
sb.append(this.types[0]);
for (int i = 1; i < this.types.length; i++) sb.append(" | ").append(this.types[i]);
return sb.append(" ").append(this.name).toString();
}
public void
setEnclosingScope(Scope enclosingScope) {
for (Type t : this.types) t.setEnclosingScope(enclosingScope);
}
}
/**
* Representation of a constructor declarator.
*/
public static final
class ConstructorDeclarator extends FunctionDeclarator {
/**
* The resolved {@link IClass.IConstructor}.
*/
@Nullable IClass.IConstructor iConstructor;
/**
* The {@link AlternateConstructorInvocation} or {@link SuperConstructorInvocation}, if any.
*/
@Nullable public final ConstructorInvocation optionalConstructorInvocation;
public
ConstructorDeclarator(
Location location,
@Nullable String optionalDocComment,
Modifier[] modifiers,
FormalParameters formalParameters,
Type[] thrownExceptions,
@Nullable ConstructorInvocation optionalConstructorInvocation,
List extends BlockStatement> statements
) {
super(
location, // location
optionalDocComment, // optionalDocComment
modifiers, // modifiers
new PrimitiveType(location, Primitive.VOID), // type
"", // name
formalParameters, // formalParameters
thrownExceptions, // thrownExceptions
statements // optionalStatements
);
this.optionalConstructorInvocation = optionalConstructorInvocation;
if (optionalConstructorInvocation != null) optionalConstructorInvocation.setEnclosingScope(this);
}
/**
* @return The {@link AbstractClassDeclaration} where this {@link ConstructorDeclarator} appears
*/
public AbstractClassDeclaration
getDeclaringClass() { return (AbstractClassDeclaration) this.getEnclosingScope(); }
// Compile time members.
/**
* Synthetic parameter name to {@link Java.LocalVariable} mapping.
*/
final Map syntheticParameters = new HashMap();
// Implement "FunctionDeclarator":
@Override public String
toString() {
StringBuilder sb = new StringBuilder(this.getDeclaringClass().getClassName()).append('(');
FormalParameter[] fps = this.formalParameters.parameters;
for (int i = 0; i < fps.length; ++i) {
if (i > 0) sb.append(", ");
sb.append(fps[i].toString(i == fps.length - 1 && this.formalParameters.variableArity));
}
sb.append(')');
return sb.toString();
}
@Override @Nullable public R
accept(Visitor.FunctionDeclaratorVisitor visitor) throws EX {
return visitor.visitConstructorDeclarator(this);
}
}
/**
* Representation of Java elements that can be annotated: Fields, constructors, methods, type declarations.
*/
public
interface Annotatable {
/**
* @return The annotations of this {@link TypeDeclaration}, {@link FieldDeclaration}, {@link MethodDeclarator}
* or {@link ConstructorDeclarator}
*/
Annotation[] getAnnotations();
}
/**
* Representation of a method declarator.
*/
public static final
class MethodDeclarator extends FunctionDeclarator {
/**
* @param defaultValue See {@link #defaultValue}
*/
public
MethodDeclarator(
Location location,
@Nullable String optionalDocComment,
Java.Modifier[] modifiers,
@Nullable TypeParameter[] optionalTypeParameters,
Type type,
String name,
FormalParameters formalParameters,
Type[] thrownExceptions,
@Nullable ElementValue defaultValue,
@Nullable List extends BlockStatement> optionalStatements
) {
super(
location, // location
optionalDocComment, // optionalDocComment
modifiers, // modifiers
type, // type
name, // name
formalParameters, // formalParameters
thrownExceptions, // thrownExceptions
optionalStatements // optionalStatements
);
this.optionalTypeParameters = optionalTypeParameters;
this.defaultValue = defaultValue;
}
/**
* @return The declared type parameters
*/
@Nullable TypeParameter[]
getOptionalTypeParameters() { return this.optionalTypeParameters; }
@Override public void
setDeclaringType(TypeDeclaration declaringType) {
super.setDeclaringType(declaringType);
if (this.optionalTypeParameters != null) {
for (TypeParameter tp : this.optionalTypeParameters) {
if (tp.optionalBound != null) {
for (ReferenceType boundType : tp.optionalBound) {
boundType.setEnclosingScope(declaringType);
}
}
}
}
}
@Override public void
setEnclosingScope(Scope enclosingScope) {
super.setEnclosingScope(enclosingScope);
if (this.optionalTypeParameters != null) {
for (TypeParameter tp : this.optionalTypeParameters) {
if (tp.optionalBound != null) {
for (ReferenceType boundType : tp.optionalBound) {
boundType.setEnclosingScope(enclosingScope);
}
}
}
}
}
@Override public String
toString() {
StringBuilder sb = new StringBuilder(this.name).append('(');
FormalParameter[] fps = this.formalParameters.parameters;
for (int i = 0; i < fps.length; ++i) {
if (i > 0) sb.append(", ");
sb.append(fps[i].toString(i == fps.length - 1 && this.formalParameters.variableArity));
}
sb.append(')');
return sb.toString();
}
@Override @Nullable public R
accept(Visitor.FunctionDeclaratorVisitor visitor) throws EX {
return visitor.visitMethodDeclarator(this);
}
/**
* The type parameters declared for the method.
*/
@Nullable public final TypeParameter[] optionalTypeParameters;
/**
* The optional "default value" of the declared method (only methods of annotation types can have a default
* value).
*/
@Nullable public Java.ElementValue defaultValue;
/**
* The resolved {@link IMethod}.
*/
@Nullable IClass.IMethod iMethod;
public boolean isStatic() { return Java.hasAccessModifier(this.getModifiers(), "static"); }
public boolean isDefault() { return Java.hasAccessModifier(this.getModifiers(), "default"); }
public boolean isAbstract() { return Java.hasAccessModifier(this.getModifiers(), "abstract"); }
public boolean isNative() { return Java.hasAccessModifier(this.getModifiers(), "native"); }
public boolean isFinal() { return Java.hasAccessModifier(this.getModifiers(), "final"); }
public boolean isSynchronized() { return Java.hasAccessModifier(this.getModifiers(), "synchronized"); }
}
/**
* This class is derived from "Statement", because it provides for the initialization of the field. In other words,
* "compile()" generates the code that initializes the field.
*/
public static final
class FieldDeclaration extends Statement implements Annotatable, TypeBodyDeclaration, DocCommentable {
@Nullable private final String optionalDocComment;
/**
* The modifiers of this field declaration.
*/
public final Modifier[] modifiers;
/**
* The type of this field.
*/
public final Type type;
/**
* The declarators of this field declaration, e.g. "int a, b;".
*/
public final VariableDeclarator[] variableDeclarators;
public
FieldDeclaration(
Location location,
@Nullable String optionalDocComment,
Modifier[] modifiers,
Type type,
VariableDeclarator[] variableDeclarators
) {
super(location);
this.optionalDocComment = optionalDocComment;
this.modifiers = modifiers;
this.type = type;
this.variableDeclarators = variableDeclarators;
this.type.setEnclosingScope(this);
for (VariableDeclarator vd : variableDeclarators) vd.setEnclosingScope(this);
}
// Implement TypeBodyDeclaration.
@Override public void
setDeclaringType(TypeDeclaration declaringType) { this.setEnclosingScope(declaringType); }
@Override public TypeDeclaration
getDeclaringType() { return (TypeDeclaration) this.getEnclosingScope(); }
@Override public void
setEnclosingScope(Scope enclosingScope) {
super.setEnclosingScope(enclosingScope);
for (Annotation a : this.getAnnotations()) a.setEnclosingScope(enclosingScope);
}
@Override public Modifier[]
getModifiers() { return this.modifiers; }
@Override public String
toString() {
StringBuilder sb = (
new StringBuilder()
.append(Java.toString(this.getModifiers()))
.append(this.type)
.append(' ')
.append(this.variableDeclarators[0])
);
for (int i = 1; i < this.variableDeclarators.length; ++i) {
sb.append(", ").append(this.variableDeclarators[i]);
}
return sb.toString();
}
// SUPPRESS CHECKSTYLE LineLength:2
@Override @Nullable public R accept(Visitor.TypeBodyDeclarationVisitor visitor) throws EX { return visitor.visitFieldDeclaration(this); }
@Override @Nullable public R accept(Visitor.BlockStatementVisitor visitor) throws EX { return visitor.visitFieldDeclaration(this); }
// Implement DocCommentable.
@Override @Nullable public String
getDocComment() { return this.optionalDocComment; }
@Override public boolean
hasDeprecatedDocTag() {
return this.optionalDocComment != null && this.optionalDocComment.indexOf("@deprecated") != -1;
}
public Access
getAccess() { return Java.modifiers2Access(this.modifiers); }
@Override
public Annotation[]
getAnnotations() { return Java.getAnnotations(this.modifiers); }
public boolean isFinal() { return Java.hasAccessModifier(this.modifiers, "final"); }
public boolean isPrivate() { return Java.hasAccessModifier(this.modifiers, "private"); }
public boolean isStatic() { return Java.hasAccessModifier(this.modifiers, "static"); }
public boolean isTransient() { return Java.hasAccessModifier(this.modifiers, "transient"); }
public boolean isVolatile() { return Java.hasAccessModifier(this.modifiers, "volatile"); }
}
/**
* Used by FieldDeclaration and LocalVariableDeclarationStatement.
*/
public static final
class VariableDeclarator extends Located {
/**
* The name of this field or local variable.
*/
public final String name;
/**
* The number of "[]"s after the name.
*/
public final int brackets;
/**
* The initializer for the variable, if any.
*/
@Nullable public final ArrayInitializerOrRvalue optionalInitializer;
public
VariableDeclarator(
Location location,
String name,
int brackets,
@Nullable ArrayInitializerOrRvalue optionalInitializer
) {
super(location);
this.name = name;
this.brackets = brackets;
this.optionalInitializer = optionalInitializer;
// Used both by field declarations an local variable declarations, so naming conventions checking (JLS7
// 6.4.2) cannot be done here.
}
/**
* Sets the immediately enclosing scope for the (optional) initializer.
*/
public void
setEnclosingScope(Scope s) {
if (this.optionalInitializer != null) this.optionalInitializer.setEnclosingScope(s);
}
@Override public String
toString() {
StringBuilder sb = new StringBuilder(this.name);
for (int i = 0; i < this.brackets; ++i) sb.append("[]");
if (this.optionalInitializer != null) sb.append(" = ").append(this.optionalInitializer);
return sb.toString();
}
// Compile time members.
/**
* Used only if the variable declarator declares a local variable.
*/
@Nullable public LocalVariable localVariable;
}
/**
* Everything that can be compiled to code, e.g. the statements occurring in the body of a method or in a block,
* explicit constructor invocations and instance/static initializers.
*/
public
interface BlockStatement extends Locatable, Scope {
/**
* Sets the enclosing scope of this {@link BlockStatement}.
*/
void setEnclosingScope(Scope enclosingScope);
// Implement Scope.
@Override Scope
getEnclosingScope();
/**
* Invokes the "{@code visit...()}" method of {@link Visitor.BlockStatementVisitor} for the concrete
* {@link BlockStatement} type.
*/
@Nullable R
accept(Visitor.BlockStatementVisitor visitor) throws EX;
/**
* @return The local variable with the given name
*/
@Nullable Java.LocalVariable
findLocalVariable(String name);
}
/**
* Everything that can occur in the body of a method or in a block. Particularly, explicit constructor invocations
* and initializers are not statements in this sense.
*
* This class is misnamed; according to JLS7 8.8.7 and 14.2, its name should be "BlockStatement".
*
*/
public abstract static
class Statement extends Located implements BlockStatement {
@Nullable private Scope enclosingScope;
protected
Statement(Location location) { super(location); }
// Implement "BlockStatement".
@Override public void
setEnclosingScope(Scope enclosingScope) {
if (this.enclosingScope != null && enclosingScope != this.enclosingScope) {
// Catch 22: In the initializers, some statements have their enclosing scope already set!
if (
enclosingScope instanceof Java.MethodDeclarator
&& "".equals(((Java.MethodDeclarator) enclosingScope).name)
) return;
throw new InternalCompilerException(
"Enclosing scope is already set for statement \""
+ this.toString()
+ "\" at "
+ this.getLocation()
);
}
this.enclosingScope = enclosingScope;
}
@Override public Scope
getEnclosingScope() {
assert this.enclosingScope != null;
return this.enclosingScope;
}
// Compile time members
/**
* The map of currently visible local variables.
*/
@Nullable public Map localVariables;
@Override @Nullable public Java.LocalVariable
findLocalVariable(String name) {
Map lvs = this.localVariables;
if (lvs == null) { return null; }
return (LocalVariable) lvs.get(name);
}
}
/**
* Representation of a JLS7 14.7 "labeled statement".
*/
public static final
class LabeledStatement extends BreakableStatement {
/**
* The label of this labeled statement.
*/
public final String label;
/**
* The labeled block.
*/
public final Statement body;
public
LabeledStatement(Location location, String label, Statement body) {
super(location);
this.label = label;
(this.body = body).setEnclosingScope(this);
}
@Override public String
toString() { return this.label + ": " + this.body; }
// Compile time members:
@Override @Nullable public R
accept(Visitor.BlockStatementVisitor visitor) throws EX { return visitor.visitLabeledStatement(this); }
}
/**
* Representation of a Java "block" (JLS7 14.2).
*
* The statements that the block defines are executed in sequence.
*
*/
public static final
class Block extends Statement {
/**
* The list of statements that comprise the body of the block.
*/
public final List statements = new ArrayList();
public
Block(Location location) { super(location); }
/**
* Adds one statement to the end of the block.
*/
public void
addStatement(BlockStatement statement) {
this.statements.add(statement);
statement.setEnclosingScope(this);
}
/**
* Adds a list of statements to the end of the block.
*/
public void
addStatements(List extends BlockStatement> statements) {
this.statements.addAll(statements);
for (BlockStatement bs : statements) bs.setEnclosingScope(this);
}
/**
* @return A copy of the list of statements that comprise the body of the block
*/
public BlockStatement[]
getStatements() {
return (BlockStatement[]) this.statements.toArray(new BlockStatement[this.statements.size()]);
}
// Compile time members.
@Override @Nullable public R
accept(Visitor.BlockStatementVisitor visitor) throws EX { return visitor.visitBlock(this); }
@Override public String
toString() { return "{ ... }"; }
}
/**
* Base class for statements that can be terminated abnormally with a {@code break} statement.
*
* According JLS7 14.15, statements that can be terminated abnormally with a {@code break} statement are:s
*
*
* - {@link ContinuableStatement}s ({@code for}, {@code do} and {@code while})
* - Labeled statements
* - {@code switch} statements
*
*/
public abstract static
class BreakableStatement extends Statement {
protected
BreakableStatement(Location location) { super(location); }
/**
* This one's filled in by the first BREAK statement, and is {@link Offset#set()} by this breakable statement.
*/
@Nullable CodeContext.Offset whereToBreak;
}
/**
* Base class for statements that support the "continue" statement.
*
* According to the JLS7 14.16, these are {@code for}, {@code do} and {@code while}.
*
*/
public abstract static
class ContinuableStatement extends BreakableStatement {
protected
ContinuableStatement(Location location, BlockStatement body) {
super(location);
(this.body = body).setEnclosingScope(this);
}
/**
* This one's filled in by the first CONTINUE statement, and is {@link Offset#set()} by this continuable
* statement.
*/
@Nullable protected CodeContext.Offset whereToContinue;
/**
* The body of this continuable statement.
*/
public final BlockStatement body;
}
/**
* Representation of the JLS7 14.8 "expression statement".
*/
public static final
class ExpressionStatement extends Statement {
/**
* The rvalue that is evaluated when the statement is executed.
*/
public final Rvalue rvalue;
public
ExpressionStatement(Rvalue rvalue) throws CompileException {
super(rvalue.getLocation());
if (!(
rvalue instanceof Java.Assignment
|| rvalue instanceof Java.Crement
|| rvalue instanceof Java.MethodInvocation
|| rvalue instanceof Java.SuperclassMethodInvocation
|| rvalue instanceof Java.NewClassInstance
|| rvalue instanceof Java.NewAnonymousClassInstance
)) {
String expressionType = rvalue.getClass().getName();
expressionType = expressionType.substring(expressionType.lastIndexOf('.') + 1);
this.throwCompileException(
expressionType
+ " is not allowed as an expression statement. "
+ "Expressions statements must be one of assignments, method invocations, or object allocations."
);
}
(this.rvalue = rvalue).setEnclosingScope(this);
}
@Override public String
toString() { return this.rvalue.toString() + ';'; }
// Compile time members:
@Override @Nullable public R
accept(Visitor.BlockStatementVisitor visitor) throws EX {
return visitor.visitExpressionStatement(this);
}
}
/**
* Representation of the JLS7 14.3 "local class declaration statement".
*/
public static final
class LocalClassDeclarationStatement extends Statement {
/**
* The class declaration that poses the body of the statement.
*/
public final LocalClassDeclaration lcd;
public
LocalClassDeclarationStatement(Java.LocalClassDeclaration lcd) {
super(lcd.getLocation());
(this.lcd = lcd).setEnclosingScope(this);
}
@Override public String
toString() { return this.lcd.toString(); }
@Override @Nullable public R
accept(Visitor.BlockStatementVisitor visitor) throws EX {
return visitor.visitLocalClassDeclarationStatement(this);
}
}
/**
* Representation of a JLS7 14.9 IF statement.
*/
public static final
class IfStatement extends Statement {
/**
* The condition of the IF statement.
*/
public final Rvalue condition;
/**
* The "then statement", which is executed iff the condition evaluates to TRUE.
*/
public final BlockStatement thenStatement;
/**
* The optional ELSE statement, which is executed iff the condition evaluates to FALSE.
*/
@Nullable public final BlockStatement elseStatement;
public
IfStatement(Location location, Rvalue condition, BlockStatement thenStatement) {
this(location, condition, thenStatement, null);
}
public
IfStatement(
Location location,
Rvalue condition,
BlockStatement thenStatement,
@Nullable BlockStatement elseStatement
) {
super(location);
(this.condition = condition).setEnclosingScope(this);
(this.thenStatement = thenStatement).setEnclosingScope(this);
this.elseStatement = elseStatement;
if (elseStatement != null) elseStatement.setEnclosingScope(this);
}
@Override public String
toString() { return this.elseStatement == null ? "if" : "if ... else"; }
// Compile time members:
@Override @Nullable public R
accept(Visitor.BlockStatementVisitor visitor) throws EX { return visitor.visitIfStatement(this); }
}
/**
* Representation of a JLS7 14.14.1 "basic FOR statement".
*/
public static final
class ForStatement extends ContinuableStatement {
/**
* The optional "init" part of the "basic FOR statement".
*/
@Nullable public final BlockStatement optionalInit;
/**
* The optional "condition" part of the "basic FOR statement".
*/
@Nullable public final Rvalue optionalCondition;
/**
* The optional "update" part of the "basic FOR statement".
*/
@Nullable public final Rvalue[] optionalUpdate;
public
ForStatement(
Location location,
@Nullable BlockStatement optionalInit,
@Nullable Rvalue optionalCondition,
@Nullable Rvalue[] optionalUpdate,
BlockStatement body
) {
super(location, body);
this.optionalInit = optionalInit;
if (optionalInit != null) optionalInit.setEnclosingScope(this);
this.optionalCondition = optionalCondition;
if (optionalCondition != null) optionalCondition.setEnclosingScope(this);
this.optionalUpdate = optionalUpdate;
if (optionalUpdate != null) for (Rvalue rv : optionalUpdate) rv.setEnclosingScope(this);
}
@Override public String
toString() { return "for (...; ...; ...) ..."; }
// Compile time members:
@Override @Nullable public R
accept(Visitor.BlockStatementVisitor visitor) throws EX { return visitor.visitForStatement(this); }
}
/**
* Representation of a JLS7 14.14.2 "enhanced FOR statement".
*/
public static final
class ForEachStatement extends ContinuableStatement {
/**
* The "current element local variable declaration" part of the "enhanced FOR statement".
*/
public final FormalParameter currentElement;
/**
* The "expression" part of the "enhanced FOR statement".
*/
public final Rvalue expression;
public
ForEachStatement(Location location, FormalParameter currentElement, Rvalue expression, BlockStatement body) {
super(location, body);
(this.currentElement = currentElement).type.setEnclosingScope(this);
(this.expression = expression).setEnclosingScope(this);
}
@Override public String
toString() { return "for (... : ...) ..."; }
// Compile time members:
@Override @Nullable public R
accept(Visitor.BlockStatementVisitor visitor) throws EX { return visitor.visitForEachStatement(this); }
}
/**
* Representation of the JLS7 14.2 WHILE statement.
*/
public static final
class WhileStatement extends ContinuableStatement {
/**
* The "condition" of the WHILE statement.
*/
public final Rvalue condition;
public
WhileStatement(Location location, Rvalue condition, BlockStatement body) {
super(location, body);
(this.condition = condition).setEnclosingScope(this);
}
@Override public String
toString() { return "while (" + this.condition + ") " + this.body + ';'; }
// Compile time members:
@Override @Nullable public R
accept(Visitor.BlockStatementVisitor visitor) throws EX { return visitor.visitWhileStatement(this); }
}
/**
* Representation of a JLS7 14.20 TRY statement.
*/
public static final
class TryStatement extends Statement {
/**
* Representation of a JLS9 14.20.2 "resource" in a TRY-with-resources statement.
*/
public abstract static
class Resource extends Located {
protected Resource(Location location) { super(location); }
/**
* Sets the enclosing scope for this object and all subordinate {@link Resource} objects.
*/
public abstract void setEnclosingTryStatement(TryStatement tryStatement);
/**
* Invokes the "{@code visit...()}" method of {@link TryStatementResourceVisitor} for the concrete {@link
* Resource} type.
*/
@Nullable public abstract R
accept(TryStatementResourceVisitor visitor) throws EX;
}
/**
* Representation of a JLS9 14.20.2 "local-variable-declarator resource" in a TRY-with-resources statement.
*/
public static
class LocalVariableDeclaratorResource extends Resource {
/**
* The resource variable modifiers (annotations and/or flags like FINAL).
*/
public final Modifier[] modifiers;
/**
* The declared type of the resource variable.
*/
public final Type type;
/**
* The "variable declarator" that follows the type.
*/
public final VariableDeclarator variableDeclarator;
/**
* @param modifiers Only {@code final} allowed
*/
public
LocalVariableDeclaratorResource(
Location location,
Modifier[] modifiers,
Type type,
VariableDeclarator variableDeclarator
) {
super(location);
this.modifiers = modifiers;
this.type = type;
this.variableDeclarator = variableDeclarator;
}
@Override public void
setEnclosingTryStatement(TryStatement ts) {
this.type.setEnclosingScope(ts);
this.variableDeclarator.setEnclosingScope(ts);
}
@Override@Nullable public R
accept(TryStatementResourceVisitor visitor) throws EX {
return visitor.visitLocalVariableDeclaratorResource(this);
}
@Override public String
toString() {
return (
new StringBuilder()
.append(Java.toString(this.modifiers))
.append(this.type)
.append(' ')
.append(this.variableDeclarator)
.toString()
);
}
}
/**
* Representation of a JLS9 14.20.2 "variable-access resource" in a TRY-with-resources statement.
*/
public static
class VariableAccessResource extends Resource {
/**
* The rvalue of this resource.
*/
public final Rvalue variableAccess;
public
VariableAccessResource(Location location, Rvalue variableAccess) {
super(location);
this.variableAccess = variableAccess;
}
@Override public void
setEnclosingTryStatement(TryStatement ts) {
this.variableAccess.setEnclosingScope(ts);
}
@Override@Nullable public R
accept(TryStatementResourceVisitor visitor) throws EX {
return visitor.visitVariableAccessResource(this);
}
@Override public String
toString() { return this.variableAccess.toString(); }
}
/**
* The "resources" managed by the TRY-with-resources statement.
*/
public final List resources;
/**
* The body of the TRY statement.
*/
public final BlockStatement body;
/**
* The list of catch clauses (including the "default" clause) of the TRY statement.
*/
public final List catchClauses;
/**
* The optional "finally" block of the TRY statement.
*/
@Nullable public final Block finallY;
/**
* A TRY statement with no resources and no FINALLY clause.
*/
public
TryStatement(Location location, BlockStatement body, List catchClauses) {
this(location, Collections.emptyList(), body, catchClauses, null);
}
/**
* A TRY statement without a FINALLY clause.
*/
public
TryStatement(
Location location,
List resources,
BlockStatement body,
List catchClauses
) { this(location, resources, body, catchClauses, null); }
public
TryStatement(
Location location,
List resources,
BlockStatement body,
List catchClauses,
@Nullable Block finallY
) {
super(location);
for (Resource r : (this.resources = resources)) r.setEnclosingTryStatement(this);
(this.body = body).setEnclosingScope(this);
for (CatchClause cc : (this.catchClauses = catchClauses)) cc.setEnclosingTryStatement(this);
this.finallY = finallY;
if (finallY != null) finallY.setEnclosingScope(this);
}
@SuppressWarnings("null") @Override public String
toString() {
return (
"try ... "
+ (this.catchClauses == null ? "???" : Integer.toString(this.catchClauses.size()))
+ (this.finallY == null ? " catches" : " catches ... finally")
);
}
// Compile time members:
@Override @Nullable public R
accept(Visitor.BlockStatementVisitor visitor) throws EX { return visitor.visitTryStatement(this); }
/**
* This one's created iff the TRY statement has a FINALLY clause when the compilation of the TRY statement
* begins.
*/
@Nullable CodeContext.Offset finallyOffset;
}
/**
* Representation of a JLS7 14.20.1 CATCH clause.
*/
public static
class CatchClause extends Located implements Scope {
/**
* Container for the types and the name of the caught exception.
*/
public final CatchParameter catchParameter;
/**
* Body of the CATCH clause.
*/
public final BlockStatement body;
/**
* Link to the enclosing TRY statement.
*/
@Nullable private TryStatement enclosingTryStatement;
// Compile time fields.
/**
* Flag for catch clause reachability analysis.
*/
public boolean reachable;
public
CatchClause(Location location, CatchParameter catchParameter, BlockStatement body) {
super(location);
(this.catchParameter = catchParameter).setEnclosingScope(this);
(this.body = body).setEnclosingScope(this);
}
/**
* Links this CATCH clause to the enclosing TRY statement.
*/
public void
setEnclosingTryStatement(TryStatement enclosingTryStatement) {
if (this.enclosingTryStatement != null && enclosingTryStatement != this.enclosingTryStatement) {
throw new InternalCompilerException(
"Enclosing TRY statement already set for catch clause "
+ this.toString()
+ " at "
+ this.getLocation()
);
}
this.enclosingTryStatement = enclosingTryStatement;
}
@Override public Scope
getEnclosingScope() { assert this.enclosingTryStatement != null; return this.enclosingTryStatement; }
@Override public String
toString() { return "catch (" + this.catchParameter + ") " + this.body; }
}
/**
* The JLS7 14.10 {@code switch} Statement.
*/
public static final
class SwitchStatement extends BreakableStatement {
/**
* The rvalue that is evaluated and matched with the CASE clauses.
*/
public final Rvalue condition;
/**
* The list of "switch block statement groups" that pose the body of the SWITCH statement.
*/
public final List sbsgs;
public
SwitchStatement(Location location, Rvalue condition, List sbsgs) {
super(location);
(this.condition = condition).setEnclosingScope(this);
for (SwitchBlockStatementGroup sbsg : (this.sbsgs = sbsgs)) {
for (Rvalue cl : sbsg.caseLabels) cl.setEnclosingScope(this);
for (BlockStatement bs : sbsg.blockStatements) bs.setEnclosingScope(this);
}
}
@SuppressWarnings("null") @Override public String
toString() {
return (
"switch ("
+ this.condition
+ ") { ("
+ (this.sbsgs == null ? "???" : Integer.toString(this.sbsgs.size()))
+ " statement groups) }"
);
}
/**
* Representation of a "switch block statement group" as defined in JLS7 14.11.
*/
public static
class SwitchBlockStatementGroup extends Java.Located {
/**
* The CASE labels at the top of the "switch block statement group".
*/
public final List caseLabels;
/**
* Whether this "switch block statement group" includes the DEFAULT label.
*/
public final boolean hasDefaultLabel;
/**
* The statements following the CASE labels.
*/
public final List blockStatements;
public
SwitchBlockStatementGroup(
Location location,
List caseLabels,
boolean hasDefaultLabel,
List blockStatements
) {
super(location);
this.caseLabels = caseLabels;
this.hasDefaultLabel = hasDefaultLabel;
this.blockStatements = blockStatements;
}
@Override public String
toString() {
return (
this.caseLabels.size()
+ (this.hasDefaultLabel ? " case label(s) plus DEFAULT" : " case label(s)")
);
}
}
// Compile time members:
@Override @Nullable public R
accept(Visitor.BlockStatementVisitor visitor) throws EX { return visitor.visitSwitchStatement(this); }
}
static
class Padder extends CodeContext.Inserter implements CodeContext.FixUp {
Padder(CodeContext codeContext) { codeContext.super(); }
@Override public void
fixUp() {
int x = this.offset % 4;
if (x != 0) {
CodeContext ca = this.getCodeContext();
ca.pushInserter(this);
ca.makeSpace(-1, 4 - x);
ca.popInserter();
}
}
}
/**
* Representation of a JLS7 14.9 SYNCHRONIZED statement.
*/
public static final
class SynchronizedStatement extends Statement {
/**
* The object reference on which the statement synchronizes.
*/
public final Rvalue expression;
/**
* The body of this SYNCHRONIZED statement.
*/
public final BlockStatement body;
public
SynchronizedStatement(Location location, Rvalue expression, BlockStatement body) {
super(location);
(this.expression = expression).setEnclosingScope(this);
(this.body = body).setEnclosingScope(this);
}
@Override public String
toString() { return "synchronized(" + this.expression + ") " + this.body; }
// Compile time members:
@Override @Nullable public R
accept(Visitor.BlockStatementVisitor visitor) throws EX {
return visitor.visitSynchronizedStatement(this);
}
/**
* The index of the local variable for the monitor object.
*/
short monitorLvIndex = -1;
}
/**
* Representation of a JLS7 14.13 DO statement.
*/
public static final
class DoStatement extends ContinuableStatement {
/**
* The condition in the WHILE clause of this DO statement.
*/
public final Rvalue condition;
public
DoStatement(Location location, BlockStatement body, Rvalue condition) {
super(location, body);
(this.condition = condition).setEnclosingScope(this);
}
@Override public String
toString() { return "do " + this.body + " while(" + this.condition + ");"; }
// Compile time members:
@Override @Nullable public R
accept(Visitor.BlockStatementVisitor visitor) throws EX { return visitor.visitDoStatement(this); }
}
/**
* Representation of a JLS7 14.4 "local variable declaration statement".
*/
public static final
class LocalVariableDeclarationStatement extends Statement {
/**
* The local variable modifiers (annotations and/or flags like FINAL).
*/
public final Modifier[] modifiers;
/**
* The declared type of the local variable.
*/
public final Type type;
/**
* The (one or more) "variable declarators" that follow the type.
*/
public final VariableDeclarator[] variableDeclarators;
/**
* @param modifiers Only {@code final} allowed
*/
public
LocalVariableDeclarationStatement(
Location location,
Modifier[] modifiers,
Type type,
VariableDeclarator[] variableDeclarators
) {
super(location);
this.modifiers = modifiers;
this.type = type;
this.variableDeclarators = variableDeclarators;
this.type.setEnclosingScope(this);
for (VariableDeclarator vd : variableDeclarators) vd.setEnclosingScope(this);
}
// Compile time members:
@Override @Nullable public R
accept(Visitor.BlockStatementVisitor visitor) throws EX {
return visitor.visitLocalVariableDeclarationStatement(this);
}
@Override public String
toString() {
StringBuilder sb = (
new StringBuilder()
.append(Java.toString(this.modifiers))
.append(this.type)
.append(' ')
.append(this.variableDeclarators[0])
);
for (int i = 1; i < this.variableDeclarators.length; ++i) {
sb.append(", ").append(this.variableDeclarators[i].toString());
}
return sb.append(';').toString();
}
public boolean
isFinal() { return Java.hasAccessModifier(this.modifiers, "final"); }
}
/**
* Representation of the JLS7 14.17 RETURN statement.
*/
public static final
class ReturnStatement extends Statement {
/**
* The optional rvalue that is returned.
*/
@Nullable public final Rvalue optionalReturnValue;
public
ReturnStatement(Location location, @Nullable Rvalue optionalReturnValue) {
super(location);
this.optionalReturnValue = optionalReturnValue;
if (optionalReturnValue != null) optionalReturnValue.setEnclosingScope(this);
}
@Override public String
toString() { return this.optionalReturnValue == null ? "return;" : "return " + this.optionalReturnValue + ';'; }
// Compile time members:
@Override @Nullable public R
accept(Visitor.BlockStatementVisitor visitor) throws EX { return visitor.visitReturnStatement(this); }
}
/**
* Representation of a JLS7 14.18 THROW statement.
*/
public static final
class ThrowStatement extends Statement {
/**
* The rvalue (of type {@link Throwable}) thrown by this THROW statement.
*/
public final Rvalue expression;
public
ThrowStatement(Location location, Rvalue expression) {
super(location);
(this.expression = expression).setEnclosingScope(this);
}
@Override public String
toString() { return "throw " + this.expression + ';'; }
// Compile time members:
@Override @Nullable public R
accept(Visitor.BlockStatementVisitor visitor) throws EX { return visitor.visitThrowStatement(this); }
}
/**
* Representation of the JLS7 14.15 BREAK statement.
*/
public static final
class BreakStatement extends Statement {
/**
* The optional label that this BREAK statement refers to.
*/
@Nullable public final String optionalLabel;
public
BreakStatement(Location location, @Nullable String optionalLabel) {
super(location);
this.optionalLabel = optionalLabel;
}
@Override public String
toString() { return this.optionalLabel == null ? "break;" : "break " + this.optionalLabel + ';'; }
// Compile time members:
@Override @Nullable public R
accept(Visitor.BlockStatementVisitor visitor) throws EX { return visitor.visitBreakStatement(this); }
}
/**
* Representation of the JLS7 14.16 CONTINUE statement.
*/
public static final
class ContinueStatement extends Statement {
/**
* The optional label that this CONTINUE statement refers to.
*/
@Nullable public final String optionalLabel;
public
ContinueStatement(Location location, @Nullable String optionalLabel) {
super(location);
this.optionalLabel = optionalLabel;
}
@Override public String
toString() { return this.optionalLabel == null ? "continue;" : "continue " + this.optionalLabel + ';'; }
// Compile time members:
@Override @Nullable public R
accept(Visitor.BlockStatementVisitor visitor) throws EX { return visitor.visitContinueStatement(this); }
}
/**
* Representation of the JLS7 14.10 ASSERT statement.
*/
public static final
class AssertStatement extends Statement {
/**
* The left-hand-side expression of this ASSERT statement.
*/
public final Rvalue expression1;
/**
* The optional right-hand-side expression of this ASSERT statement.
*/
@Nullable public final Rvalue optionalExpression2;
public
AssertStatement(Location location, Rvalue expression1, @Nullable Rvalue optionalExpression2) {
super(location);
this.expression1 = expression1;
this.optionalExpression2 = optionalExpression2;
this.expression1.setEnclosingScope(this);
if (this.optionalExpression2 != null) this.optionalExpression2.setEnclosingScope(this);
}
@Override public String
toString() {
return (
this.optionalExpression2 == null
? "assert " + this.expression1 + ';'
: "assert " + this.expression1 + " : " + this.optionalExpression2 + ';'
);
}
@Override @Nullable public R
accept(Visitor.BlockStatementVisitor visitor) throws EX { return visitor.visitAssertStatement(this); }
}
/**
* Representation of the "empty statement", i.e. the blank semicolon.
*/
public static final
class EmptyStatement extends Statement {
public
EmptyStatement(Location location) { super(location); }
@Override public String
toString() { return ";"; }
@Override @Nullable public R
accept(Visitor.BlockStatementVisitor visitor) throws EX { return visitor.visitEmptyStatement(this); }
}
/**
* Abstract base class for {@link Java.Type}, {@link Java.Rvalue}, {@link Java.Package} and {@link
* Java.ConstructorInvocation}.
*/
public abstract static
class Atom extends Located {
public
Atom(Location location) { super(location); }
/**
* @return This atom, converted to {@link Type}, or {@code null} if this atom is not a type
*/
@Nullable public Type toType() { return null; }
/**
* @return This atom, converted to {@link Rvalue}, or {@code null} if this atom is not an rvalue
*/
@Nullable public Rvalue toRvalue() { return null; }
/**
* @return This atom, converted to {@link Lvalue}, or {@code null} if this atom is not an lvalue
*/
@Nullable public Lvalue toLvalue() { return null; }
@Override public abstract String
toString();
// Parse time members:
/**
* @return This atom, converted to {@link Type}
* @throws CompileException This atom is not a {@link Type}
*/
public final Type
toTypeOrCompileException() throws CompileException {
Type result = this.toType();
if (result != null) return result;
throw new CompileException("Expression \"" + this.toString() + "\" is not a type", this.getLocation());
}
/**
* @return This atom, converted to an {@link Rvalue}
* @throws CompileException This atom is not an {@link Rvalue}
*/
public final Rvalue
toRvalueOrCompileException() throws CompileException {
Rvalue result = this.toRvalue();
if (result != null) return result;
throw new CompileException("Expression \"" + this.toString() + "\" is not an rvalue", this.getLocation());
}
/**
* @return This atom, converted to an {@link Lvalue}
* @throws CompileException This atom is not a {@link Lvalue}
*/
public final Lvalue
toLvalueOrCompileException() throws CompileException {
Lvalue result = this.toLvalue();
if (result != null) return result;
throw new CompileException("Expression \"" + this.toString() + "\" is not an lvalue", this.getLocation());
}
/**
* Invokes the "{@code visit...()}" method of {@link Visitor.AtomVisitor} for the concrete {@link Atom} type.
*/
@Nullable public abstract R
accept(Visitor.AtomVisitor visitor) throws EX;
}
/**
* Representation of a Java type.
*/
public abstract static
class Type extends Atom {
@Nullable private Scope enclosingScope;
protected
Type(Location location) { super(location); }
/**
* Sets the enclosing scope for this object and all subordinate {@link org.codehaus.janino.Java.Type} objects.
*/
public void
setEnclosingScope(final Scope enclosingScope) {
if (this.enclosingScope != null && enclosingScope != this.enclosingScope) {
// Catch 22: In the initializers, some statements have their enclosing scope already set!
if (
enclosingScope instanceof Java.MethodDeclarator
&& "".equals(((Java.MethodDeclarator) enclosingScope).name)
) return;
throw new InternalCompilerException(
"Enclosing scope already set for type \""
+ this.toString()
+ "\" at "
+ this.getLocation()
);
}
this.enclosingScope = enclosingScope;
}
/**
* @return The enclosing scope (as previously set by {@link #setEnclosingScope(Java.Scope)})
*/
public Scope
getEnclosingScope() { assert this.enclosingScope != null; return this.enclosingScope; }
@Override public Type
toType() { return this; }
/**
* Invokes the "{@code visit...()}" method of {@link Visitor.TypeVisitor} for the concrete {@link Type} type.
*/
@Nullable public abstract R
accept(Visitor.TypeVisitor visitor) throws EX;
}
/**
* This class is not used when code is parsed; it is intended for "programmatic" types.
*/
public static final
class SimpleType extends Type {
/**
* The {@link IClass} represented by this {@link Type}.
*/
public final IClass iClass;
public
SimpleType(Location location, IClass iClass) {
super(location);
this.iClass = iClass;
}
@Override public String
toString() { return this.iClass.toString(); }
// SUPPRESS CHECKSTYLE LineLength:2
@Override @Nullable public R accept(Visitor.AtomVisitor visitor) throws EX { return visitor.visitType(this); }
@Override @Nullable public R accept(Visitor.TypeVisitor visitor) throws EX { return visitor.visitSimpleType(this); }
}
/**
* Representation of a JLS7 4.2 "primitive type", i.e a primitive type "usage", which has a location.
*/
public static final
class PrimitiveType extends Type {
/**
* One of {@link Primitive#VOID}, {@link Primitive#BYTE} and consorts.
*/
public final Primitive primitive;
public
PrimitiveType(Location location, Primitive primitive) {
super(location);
this.primitive = primitive;
}
@Override public String
toString() { return this.primitive.toString(); }
// SUPPRESS CHECKSTYLE LineLength:2
@Override @Nullable public R accept(Visitor.TypeVisitor visitor) throws EX { return visitor.visitPrimitiveType(this); }
@Override @Nullable public R accept(Visitor.AtomVisitor visitor) throws EX { return visitor.visitType(this); }
}
/**
* Java's primitive types.
*/
public
enum Primitive {
// SUPPRESS CHECKSTYLE JavadocVariable:9
VOID,
BYTE,
SHORT,
CHAR,
INT,
LONG,
FLOAT,
DOUBLE,
BOOLEAN,
;
@Override public String
toString() { return this.name().toLowerCase(); }
}
/**
* Representation of a JLS7 4.3 reference type.
*/
public static final
class ReferenceType extends Type implements TypeArgument {
public final Annotation[] annotations;
/**
* The list of (dot-separated) identifiers that pose the reference type, e.g. "java", "util", "Map".
*/
public final String[] identifiers;
/**
* The optional type arguments of the reference type.
*/
@Nullable public final TypeArgument[] optionalTypeArguments;
public
ReferenceType(
Location location,
Annotation[] annotations,
String[] identifiers,
@Nullable TypeArgument[] optionalTypeArguments
) {
super(location);
assert annotations != null;
this.annotations = annotations;
assert identifiers != null;
this.identifiers = identifiers;
this.optionalTypeArguments = optionalTypeArguments;
}
@Override public String
toString() {
String s = Java.join(this.annotations, " ");
if (this.annotations.length >= 1) s += ' ';
s += Java.join(this.identifiers, ".");
if (this.optionalTypeArguments != null) s += '<' + Java.join(this.optionalTypeArguments, ", ") + ">";
return s;
}
// SUPPRESS CHECKSTYLE LineLength:3
@Override @Nullable public R accept(Visitor.AtomVisitor visitor) throws EX { return visitor.visitType(this); }
@Override @Nullable public R accept(Visitor.TypeVisitor visitor) throws EX { return visitor.visitReferenceType(this); }
@Override @Nullable public R accept(TypeArgumentVisitor visitor) throws EX { return visitor.visitReferenceType(this); }
}
/**
* Representation of a JLS7 4.5.1 type argument.
*/
public
interface TypeArgument {
/**
* Invokes the "{@code visit...()}" method of {@link Visitor.TypeArgumentVisitor} for the concrete {@link
* TypeArgument} type.
*/
@Nullable R
accept(Visitor.TypeArgumentVisitor visitor) throws EX;
}
/**
* Representation of the first part of a JLS7 15.9 "Qualified class instance creation expression": The "{@code
* a.new MyClass}" part of "{@code a.new MyClass(...)}" expression.
*/
public static final
class RvalueMemberType extends Type {
/**
* The expression that represents the outer instance required for the instantiation of the inner type.
*/
public final Rvalue rvalue;
/**
* The simple name of the inner type being instantiated.
*/
public final String identifier;
/**
* Notice: The rvalue is not a subordinate object!
*/
public
RvalueMemberType(Location location, Rvalue rvalue, String identifier) {
super(location);
this.rvalue = rvalue;
this.identifier = identifier;
}
@Override public String
toString() { return this.identifier; }
// SUPPRESS CHECKSTYLE LineLength:2
@Override @Nullable public R accept(Visitor.AtomVisitor visitor) throws EX { return visitor.visitType(this); }
@Override @Nullable public R accept(Visitor.TypeVisitor visitor) throws EX { return visitor.visitRvalueMemberType(this); }
}
/**
* Representation of a JLS7 10.1 "array type".
*/
public static final
class ArrayType extends Type implements TypeArgument {
/**
* The (declared) type of the array's components.
*/
public final Type componentType;
public
ArrayType(Type componentType) {
super(componentType.getLocation());
this.componentType = componentType;
}
@Override public void
setEnclosingScope(final Scope enclosingScope) {
super.setEnclosingScope(enclosingScope);
this.componentType.setEnclosingScope(enclosingScope);
}
@Override public String
toString() { return this.componentType.toString() + "[]"; }
// SUPPRESS CHECKSTYLE LineLength:3
@Override @Nullable public R accept(Visitor.AtomVisitor visitor) throws EX { return visitor.visitType(this); }
@Override @Nullable public R accept(Visitor.TypeVisitor visitor) throws EX { return visitor.visitArrayType(this); }
@Override @Nullable public R accept(TypeArgumentVisitor visitor) throws EX { return visitor.visitArrayType(this); }
}
/**
* Representation of an "rvalue", i.e. an expression that has a type and a value, but cannot be assigned to: An
* expression that can be the right-hand-side of an assignment.
*/
public abstract static
class Rvalue extends Atom implements ArrayInitializerOrRvalue, ElementValue {
@Nullable private Java.Scope enclosingScope;
protected
Rvalue(Location location) { super(location); }
@Override @Nullable public final R
accept(ElementValueVisitor visitor) throws EX { return visitor.visitRvalue(this); }
/**
* Sets the enclosing scope for this object and all subordinate {@link Java.Rvalue} objects.
*/
@Override
public final void
setEnclosingScope(final Java.Scope enclosingScope) {
new AbstractTraverser() {
@Override public void
traverseRvalue(Java.Rvalue rv) {
if (rv.enclosingScope != null && enclosingScope != rv.enclosingScope) {
throw new InternalCompilerException(
"Enclosing block statement for rvalue \""
+ rv
+ "\" at "
+ rv.getLocation()
+ " is already set"
);
}
rv.enclosingScope = enclosingScope;
super.traverseRvalue(rv);
}
@Override public void
traverseAnonymousClassDeclaration(Java.AnonymousClassDeclaration acd) {
acd.setEnclosingScope(enclosingScope);
;
}
@Override public void
traverseType(Java.Type t) {
if (t.enclosingScope != null && enclosingScope != t.enclosingScope) {
throw new InternalCompilerException(
"Enclosing scope already set for type \""
+ t.toString()
+ "\" at "
+ t.getLocation()
);
}
t.enclosingScope = enclosingScope;
// t.setEnclosingScope(enclosingScope);
super.traverseType(t);
}
}.visitAtom(this);
}
/**
* @return The enclosing scope, as set with {@link #setEnclosingScope(Java.Scope)}
*/
public Java.Scope
getEnclosingScope() {
assert this.enclosingScope != null;
return this.enclosingScope;
}
/**
* @return The enclosing scope, as set with {@link #setEnclosingScope(Java.Scope)}
*/
@Nullable public Java.Scope
getEnclosingScopeOrNull() { return this.enclosingScope; }
@Override @Nullable public Rvalue
toRvalue() { return this; }
/**
* The special value for the {@link #constantValue} field indicating that the constant value of this rvalue
* has not yet been determined.
*/
static final Object CONSTANT_VALUE_UNKNOWN = new Object() {
@Override public String
toString() { return "CONSTANT_VALUE_UNKNOWN"; }
};
/**
* The constant value of this rvalue, or {@link #CONSTANT_VALUE_UNKNOWN} iff the constant value of this rvalue
* has not yet been determined.
*/
@Nullable Object constantValue = Java.Rvalue.CONSTANT_VALUE_UNKNOWN;
/**
* Invokes the "{@code visit...()}" method of {@link Visitor.RvalueVisitor} for the concrete {@link Rvalue}
* type.
*/
@Nullable public abstract R
accept(Visitor.RvalueVisitor rvv) throws EX;
@Override @Nullable public final R
accept(Visitor.AtomVisitor visitor) throws EX {
return visitor.visitRvalue(this);
}
}
/**
* Base class for {@link Java.Rvalue}s that compile better as conditional branches.
*/
public abstract static
class BooleanRvalue extends Rvalue {
protected BooleanRvalue(Location location) { super(location); }
}
/**
* Representation of an "lvalue", i.e. an expression that has a type and a value, and can be assigned to: An
* expression that can be the left-hand-side of an assignment.
*/
public abstract static
class Lvalue extends Rvalue {
protected Lvalue(Location location) { super(location); }
@Override @Nullable public Lvalue
toLvalue() { return this; }
/**
* Invokes the "{@code visit...()}" method of {@link Visitor.LvalueVisitor} for the concrete {@link Lvalue}
* type.
*/
@Nullable public abstract R
accept(Visitor.LvalueVisitor lvv) throws EX;
@Override @Nullable public final R
accept(Visitor.RvalueVisitor visitor) throws EX {
return visitor.visitLvalue(this);
}
}
/**
* Representation of a JLS7 6.5.2 "ambiguous name".
*
* This class is special: It does not extend/implement the {@link Atom} subclasses, but overrides {@link Atom}'s
* "{@code to...()}" methods.
* R
accept(Visitor.LvalueVisitor visitor) throws EX { return visitor.visitAmbiguousName(this); }
}
/**
* Representation of a JLS7 6.5.2.1.5 "package name".
*/
public static final
class Package extends Atom {
/**
* The complete name of a package, e.g. "java" or "java.util".
*/
public final String name;
public
Package(Location location, String name) {
super(location);
this.name = name;
}
@Override public String
toString() { return this.name; }
@Override @Nullable public R
accept(Visitor.AtomVisitor visitor) throws EX { return visitor.visitPackage(this); }
}
/**
* Representation of a local variable access -- used during compilation.
*/
public static final
class LocalVariableAccess extends Lvalue {
/**
* The local variable that is accessed.
*/
public final LocalVariable localVariable;
public
LocalVariableAccess(Location location, LocalVariable localVariable) {
super(location);
this.localVariable = localVariable;
}
// Compile time members.
@Override public String
toString() {
return (
this.localVariable.slot != null ? (
this.localVariable.slot.name != null
? this.localVariable.slot.name
: "unnamed_lv"
) : "???"
);
}
@Override @Nullable public R
accept(Visitor.LvalueVisitor visitor) throws EX { return visitor.visitLocalVariableAccess(this); }
}
/**
* Representation of an access to a field of a class or an interface. (Does not implement the {@link ArrayLength},
* e.g. "myArray.length".)
*/
public static final
class FieldAccess extends Lvalue {
/**
* The left-hand-side of the field access - either a type or an rvalue (which includes all
* lvalues).
*/
public final Atom lhs;
/**
* The field within the class or instance identified by the {@link #lhs}.
*/
public final IClass.IField field;
public
FieldAccess(Location location, Atom lhs, IClass.IField field) {
super(location);
this.lhs = lhs;
this.field = field;
}
// Compile time members.
// Implement "Atom".
@Override public String
toString() { return this.lhs.toString() + '.' + this.field.getName(); }
@Override @Nullable public R
accept(Visitor.LvalueVisitor visitor) throws EX { return visitor.visitFieldAccess(this); }
}
/**
* Representation of the JLS7 10.7 array type "length" pseudo-member.
*/
public static final
class ArrayLength extends Rvalue {
/**
* The rvalue identifying the array to determine the length of.
*/
public final Rvalue lhs;
public
ArrayLength(Location location, Rvalue lhs) {
super(location);
this.lhs = lhs;
}
// Compile time members.
// Implement "Atom".
@Override public String
toString() { return this.lhs.toString() + ".length"; }
@Override @Nullable public R
accept(Visitor.RvalueVisitor