/* * Janino - An embedded Java[TM] compiler * * Copyright (c) 2001-2010, Arno Unkrig * 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. The name of the author may not be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.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.BlockStatementVisitor; import org.codehaus.janino.Visitor.ElementValueVisitor; import org.codehaus.janino.Visitor.TypeArgumentVisitor; import org.codehaus.janino.util.Traverser; 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. */ @SuppressWarnings({ "rawtypes", "unchecked" }) 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(); /** * Throw 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#parseCompilationUnit}. */ public static final class CompilationUnit implements Scope { /** A string that explains the 'file' (or similar resource) where this CU was loaded from. */ public final String optionalFileName; /** The package declaration at the very top of this CU (if any). */ public PackageDeclaration optionalPackageDeclaration; /** The IMPORT declarations in this CU. */ public final List importDeclarations = new ArrayList(); /** The top-level declarations in this CU. */ public final List packageMemberTypeDeclarations = new ArrayList(); public CompilationUnit(String optionalFileName) { this.optionalFileName = optionalFileName; } // Implement "Scope". @Override public Scope getEnclosingScope() { throw new JaninoRuntimeException("A compilation unit has no enclosing scope"); } /** Sets the package declaration of this CU. */ public void setPackageDeclaration(PackageDeclaration packageDeclaration) { this.optionalPackageDeclaration = packageDeclaration; } /** Adds one IMPORT declaration to this CU. */ public void addImportDeclaration(CompilationUnit.ImportDeclaration id) { // Conflicting imports are checked in UnitCompiler, not here. this.importDeclarations.add(id); } /** Adds one top-level type declaration to this CU. */ 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()] ); } /** * Return the package member class or interface declared with the given name. * @param name Declared (i.e. not the fully qualified) name * @return null if a package member type with that name is not declared in this compilation unit */ public PackageMemberTypeDeclaration getPackageMemberTypeDeclaration(String name) { for (PackageMemberTypeDeclaration pmtd : this.packageMemberTypeDeclarations) { if (pmtd.getName().equals(name)) return pmtd; } return null; } /** 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 public final void accept(Visitor.ImportVisitor visitor) { 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 public final void accept(Visitor.ImportVisitor visitor) { 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 public final void accept(Visitor.ImportVisitor visitor) { visitor.visitSingleStaticImportDeclaration(this); } } /** * Represents a static-import-on-demand declaration like
         *     import 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 public final void accept(Visitor.ImportVisitor visitor) { visitor.visitStaticImportOnDemandDeclaration(this); } } /** 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. */ public abstract void accept(Visitor.ImportVisitor visitor); } } /** Representation of a Java ™ annotation. */ public interface Annotation extends ElementValue { /** * Invokes the '{@code visit...()}' method of {@link Visitor.AnnotationVisitor} for the concrete {@link * Annotation} type. */ void accept(Visitor.AnnotationVisitor visitor); /** Sets the enclosing scope for this annotation. */ void setEnclosingScope(Scope enclosingScope); /** @return The type of this annotation */ Type getType(); } /** Repreentation of a 'marker annotation', i.e. an annotation without any elements in parentheses. */ public static final class MarkerAnnotation implements Annotation { /** The type of this marker annotation. */ public final Type type; public MarkerAnnotation(Type type) { this.type = type; } @Override public void setEnclosingScope(Scope enclosingScope) { this.type.setEnclosingScope(enclosingScope); } @Override public String toString() { return "@" + this.type; } @Override public Type getType() { return this.type; } @Override public void accept(Visitor.AnnotationVisitor visitor) { visitor.visitMarkerAnnotation(this); } @Override public void accept(Visitor.ElementValueVisitor visitor) { 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 implements Annotation { /** The type of this single-element annotation. */ public final Type type; /** The element value associated with this single-element annotation. */ public final ElementValue elementValue; public SingleElementAnnotation(Type type, ElementValue elementValue) { this.type = type; this.elementValue = elementValue; } @Override public void setEnclosingScope(Scope enclosingScope) { this.type.setEnclosingScope(enclosingScope); } @Override public String toString() { return "@" + this.type + '(' + this.elementValue + ')'; } @Override public Type getType() { return this.type; } @Override public void accept(Visitor.AnnotationVisitor visitor) { visitor.visitSingleElementAnnotation(this); } @Override public void accept(Visitor.ElementValueVisitor visitor) { visitor.visitSingleElementAnnotation(this); } } /** A 'normal annotation', i.e. an annotation with multiple elements in parentheses and curly braces. */ public static final class NormalAnnotation implements Annotation { /** The type of this normal annotation. */ public final Type type; /** The element-value-pairs associated with this annotation. */ public final ElementValuePair[] elementValuePairs; public NormalAnnotation(Type type, ElementValuePair[] elementValuePairs) { this.type = type; this.elementValuePairs = elementValuePairs; } @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 public void setEnclosingScope(Scope enclosingScope) { this.setEnclosingScope(enclosingScope); } @Override public void accept(Visitor.AnnotationVisitor visitor) { visitor.visitNormalAnnotation(this); } @Override public void accept(Visitor.ElementValueVisitor visitor) { visitor.visitNormalAnnotation(this); } } /** Representation of the modifier flags and annotations that are associated with a declaration. */ public static class Modifiers { /** The or'ed constants declared in {@link Mod}. */ public final short flags; /** The annotations. */ public final Annotation[] annotations; /** A 'blank' {@link Modifiers} object: No flags, no annotations. */ public Modifiers() { this.flags = Mod.NONE; this.annotations = new Annotation[0]; } public Modifiers(short modifiers) { this.flags = modifiers; this.annotations = new Annotation[0]; } public Modifiers(short modifiers, Annotation[] annotations) { this.flags = modifiers; this.annotations = annotations; } /** @return This object, with the given {@code modifiersToAdd} added. */ public Modifiers add(int modifiersToAdd) { return new Modifiers((short) (this.flags | modifiersToAdd), this.annotations); } /** @return This object, with the given {@code modifiersToRemove} removed. */ public Modifiers remove(int modifiersToRemove) { return new Modifiers((short) (this.flags & ~modifiersToRemove), this.annotations); } /** * @param newAccess One of {@link Mod#PUBLIC}, {@link Mod#PRIVATE}, {@link Mod#PROTECTED}, {@link Mod#PACKAGE} * @return This object, with the access changed to {@code newAccess} */ public Modifiers changeAccess(int newAccess) { return new Modifiers((short) (this.flags & ~Mod.PPP | newAccess), this.annotations); } } /** 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 { /** * Invokes the '{@code visit...()}' method of {@link Visitor.ElementValueVisitor} for the concrete {@link * ElementValue} type. */ void accept(Visitor.ElementValueVisitor visitor); } /** * An element value in the form of an array initializer, e.g. 'SuppressWarnings({ "null", "unchecked" * })'. */ public static class ElementValueArrayInitializer implements ElementValue { /** The element values in the body of the array initializer. */ public final ElementValue[] elementValues; public ElementValueArrayInitializer(ElementValue[] elementValues) { this.elementValues = elementValues; } @Override public String toString() { switch (this.elementValues.length) { case 0: return "{}"; case 1: return "{ " + this.elementValues[0] + " }"; default: return "{ " + this.elementValues[0] + ", ... }"; } } @Override public void accept(Visitor.ElementValueVisitor visitor) { 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 kinds of type declarations, e.g. top-level class, member interface, local class. */ public interface TypeDeclaration extends Locatable, Scope { /** @return The or'ed modifier flags of the type, as defined in {@link Mod} */ short getModifierFlags(); /** @return The annotations of this {@link TypeDeclaration} */ Annotation[] getAnnotations(); /** * Return the member type with the given name. * @return null if a member type with that name is not declared */ MemberTypeDeclaration getMemberTypeDeclaration(String name); /** @return The (possibly empty) set of member types declared inside this {@link TypeDeclaration} */ Collection getMemberTypeDeclarations(); /** * Return the first method declared with the given name. (Does not honor inherited methods.) * * @return null if a method with this name is not declared */ 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. */ void accept(Visitor.TypeDeclarationVisitor visitor); } /** * 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} */ String getDocComment(); /** * Returns true if the object has a doc comment and * the @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 CompilationUnit} in which this top-level type is declared. */ void setDeclaringCompilationUnit(CompilationUnit declaringCompilationUnit); /** @return The {@link CompilationUnit} in which this top-level type is declared. */ CompilationUnit getDeclaringCompilationUnit(); } /** * Represents a class or interface declaration where the immediately enclosing scope is * another class or interface declaration. */ public interface MemberTypeDeclaration extends NamedTypeDeclaration, TypeBodyDeclaration {} /** * 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 */ 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 TypeDeclaration { /** * Inner classes have zero or more synthetic fields that hold references to their enclosing * context: *
*
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. 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 this$0. *
*
val$local-variable-name
*
* (Allowed for local classes and anonymous classes; forbidden for member classes) * Hold copies of 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 Modifiers modifiers; private final List declaredMethods = new ArrayList(); private final List declaredClassesAndInterfaces = new ArrayList(); private Scope enclosingScope; /** Holds the resolved type during compilation. */ IClass resolvedType; public AbstractTypeDeclaration(Location location, Modifiers modifiers) { this.location = location; this.modifiers = modifiers; } @Override public short getModifierFlags() { return this.modifiers.flags; } @Override public Annotation[] getAnnotations() { return this.modifiers.annotations; } /** Sets the enclosing scope of this {@link TypeDeclaration}. */ public void setEnclosingScope(Scope enclosingScope) { if (this.enclosingScope != null && enclosingScope != this.enclosingScope) { throw new JaninoRuntimeException( "Enclosing scope is already set for type declaration \"" + this.toString() + "\" at " + this.getLocation() ); } this.enclosingScope = enclosingScope; } @Override public Scope getEnclosingScope() { 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 public MemberTypeDeclaration getMemberTypeDeclaration(String name) { for (MemberTypeDeclaration mtd : this.declaredClassesAndInterfaces) { if (mtd.getName().equals(name)) return mtd; } return null; } @Override 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 ClassDeclaration extends AbstractTypeDeclaration { /** 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 ClassDeclaration(Location location, Modifiers modifiers) { super(location, modifiers); } /** 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 JaninoRuntimeException(); IClass.IField if2 = (IClass.IField) this.syntheticFields.get(iField.getName()); if (if2 != null) { if (iField.getType() != if2.getType()) throw new JaninoRuntimeException(); return; } this.syntheticFields.put(iField.getName(), iField); } /** @return The declared constructors, or the default constructor */ ConstructorDeclarator[] getConstructors() { if (this.constructors.isEmpty()) { ConstructorDeclarator defaultConstructor = new ConstructorDeclarator( this.getLocation(), // location null, // optionalDocComment new Java.Modifiers(Mod.PUBLIC), // modifiers new FormalParameters(), // formalParameters new Type[0], // thrownExceptions null, // optionalExplicitConstructorInvocation Collections.EMPTY_LIST // optionalStatements ); defaultConstructor.setDeclaringType(this); return new ConstructorDeclarator[] { defaultConstructor }; } return (ConstructorDeclarator[]) this.constructors.toArray( new ConstructorDeclarator[this.constructors.size()] ); } /** 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 ClassDeclaration implements InnerClassDeclaration { /** Base class or interface. */ public final Type baseType; public AnonymousClassDeclaration(Location location, Type baseType) { super( location, // location new Modifiers((short) (Mod.PRIVATE | Mod.FINAL)) // modifiers ); (this.baseType = baseType).setEnclosingScope(new EnclosingScopeOfTypeDeclaration(this)); } @Override public void accept(Visitor.TypeDeclarationVisitor visitor) { visitor.visitAnonymousClassDeclaration(this); } // Implement TypeDeclaration. @Override public String getClassName() { if (this.myName == null) { Scope s = this.getEnclosingScope(); for (; !(s instanceof TypeDeclaration); s = s.getEnclosingScope()); this.myName = ((TypeDeclaration) s).createAnonymousClassName(); } return this.myName; } private String myName; @Override public String toString() { return this.getClassName(); } } /** Base for the various named class declarations. */ public abstract static class NamedClassDeclaration extends ClassDeclaration implements NamedTypeDeclaration, DocCommentable { private final String optionalDocComment; /** The simple name of this class. */ public final String name; /** The optional type parameters of this interface. */ public final TypeParameter[] optionalTypeParameters; /** The type of the extended class. */ public final Type optionalExtendedType; /** The types of the implemented interfaces. */ public final Type[] implementedTypes; public NamedClassDeclaration( Location location, String optionalDocComment, Modifiers modifiers, String name, TypeParameter[] optionalTypeParameters, Type optionalExtendedType, Type[] implementedTypes ) { super(location, modifiers); this.optionalDocComment = optionalDocComment; this.name = name; this.optionalTypeParameters = optionalTypeParameters; 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; } @Override public TypeParameter[] getOptionalTypeParameters() { return this.optionalTypeParameters; } // Implement DocCommentable. @Override public String getDocComment() { return this.optionalDocComment; } @Override public boolean hasDeprecatedDocTag() { return this.optionalDocComment != null && this.optionalDocComment.indexOf("@deprecated") != -1; } } /** 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 * declaration. */ public static final class MemberClassDeclaration extends NamedClassDeclaration implements MemberTypeDeclaration, InnerClassDeclaration { public MemberClassDeclaration( Location location, String optionalDocComment, Modifiers modifiers, String name, TypeParameter[] optionalTypeParameters, Type optionalExtendedType, Type[] implementedTypes ) { super( location, // location optionalDocComment, // optionalDocComment modifiers, // modifiers name, // name optionalTypeParameters, // optionalTypeParameters optionalExtendedType, // optionalExtendedType implementedTypes // implementedTypes ); } // Implement TypeBodyDeclaration. @Override public void setDeclaringType(TypeDeclaration declaringType) { this.setEnclosingScope(declaringType); } @Override public TypeDeclaration getDeclaringType() { return (TypeDeclaration) this.getEnclosingScope(); } @Override public boolean isStatic() { return Mod.isStatic(this.getModifierFlags()); } // Implement TypeDeclaration. @Override public String getClassName() { return this.getDeclaringType().getClassName() + '$' + this.getName(); } @Override public void accept(Visitor.TypeDeclarationVisitor visitor) { visitor.visitMemberClassDeclaration(this); } @Override public void accept(Visitor.TypeBodyDeclarationVisitor visitor) { visitor.visitMemberClassDeclaration(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, String optionalDocComment, Modifiers modifiers, String name, TypeParameter[] optionalTypeParameters, 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 public void accept(Visitor.TypeDeclarationVisitor visitor) { visitor.visitLocalClassDeclaration(this); } } /** Implementation of a 'package member class declaration', a.k.a. 'top-level class declaration'. */ public static final class PackageMemberClassDeclaration extends NamedClassDeclaration implements PackageMemberTypeDeclaration { public PackageMemberClassDeclaration( Location location, String optionalDocComment, Modifiers modifiers, String name, TypeParameter[] optionalTypeParameters, Type optionalExtendedType, Type[] implementedTypes ) throws CompileException { super( location, // location optionalDocComment, // optionalDocComment modifiers, // modifiers name, // name optionalTypeParameters, // optionalTypeParameters optionalExtendedType, // optionalExtendedType implementedTypes // implementedTypes ); // Check for forbidden modifiers (JLS7 7.6). if ((modifiers.flags & (Mod.PROTECTED | Mod.PRIVATE | Mod.STATIC)) != 0) { this.throwCompileException( "Modifiers \"protected\", \"private\" and \"static\" not allowed in package member class " + "declaration" ); } } // Implement PackageMemberTypeDeclaration. @Override public void setDeclaringCompilationUnit(CompilationUnit declaringCompilationUnit) { this.setEnclosingScope(declaringCompilationUnit); } @Override public CompilationUnit getDeclaringCompilationUnit() { return (CompilationUnit) this.getEnclosingScope(); } // Implement TypeDeclaration. @Override public String getClassName() { String className = this.getName(); CompilationUnit compilationUnit = (CompilationUnit) this.getEnclosingScope(); if (compilationUnit.optionalPackageDeclaration != null) { className = compilationUnit.optionalPackageDeclaration.packageName + '.' + className; } return className; } @Override public void accept(Visitor.TypeDeclarationVisitor visitor) { visitor.visitPackageMemberClassDeclaration(this); } } /** Base for the various interface declaration kinds. */ public abstract static class InterfaceDeclaration extends AbstractTypeDeclaration implements NamedTypeDeclaration, DocCommentable { private final String optionalDocComment; /** The simple name of the interface. */ public final String name; /** The optional type parameters of this interface. */ public final TypeParameter[] optionalTypeParameters; protected InterfaceDeclaration( Location location, String optionalDocComment, Modifiers modifiers, String name, TypeParameter[] optionalTypeParameters, Type[] extendedTypes ) { super(location, modifiers); this.optionalDocComment = optionalDocComment; this.name = name; this.optionalTypeParameters = optionalTypeParameters; 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()". */ IClass[] interfaces; // Implement NamedTypeDeclaration. @Override public String getName() { return this.name; } @Override public TypeParameter[] getOptionalTypeParameters() { return this.optionalTypeParameters; } // Implement DocCommentable. @Override 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 final class MemberInterfaceDeclaration extends InterfaceDeclaration implements MemberTypeDeclaration { public MemberInterfaceDeclaration( Location location, String optionalDocComment, Modifiers modifiers, String name, TypeParameter[] optionalTypeParameters, Type[] extendedTypes ) { super( location, // location optionalDocComment, // optionalDocComment modifiers, // modifiers name, // name optionalTypeParameters, // optionalTypeParameters extendedTypes // extendedTypes ); } // 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(); } @Override public boolean isStatic() { return Mod.isStatic(this.getModifierFlags()); } @Override public void accept(Visitor.TypeDeclarationVisitor visitor) { visitor.visitMemberInterfaceDeclaration(this); } @Override public void accept(Visitor.TypeBodyDeclarationVisitor visitor) { visitor.visitMemberInterfaceDeclaration(this); } } /** Representation of a 'package member interface declaration', a.k.a. 'top-level interface declaration'. */ public static final class PackageMemberInterfaceDeclaration extends InterfaceDeclaration implements PackageMemberTypeDeclaration { public PackageMemberInterfaceDeclaration( Location location, String optionalDocComment, Modifiers modifiers, String name, TypeParameter[] optionalTypeParameters, Type[] extendedTypes ) throws CompileException { super( location, // location optionalDocComment, // optionalDocComment modifiers, // modifiers name, // name optionalTypeParameters, // optionalTypeParameters extendedTypes // extendedTypes ); // Check for forbidden modifiers (JLS7 7.6). if ((modifiers.flags & (Mod.PROTECTED | Mod.PRIVATE | Mod.STATIC)) != 0) { this.throwCompileException( "Modifiers \"protected\", \"private\" and \"static\" not allowed in package member interface " + "declaration" ); } } // Implement PackageMemberTypeDeclaration. @Override public void setDeclaringCompilationUnit(CompilationUnit declaringCompilationUnit) { this.setEnclosingScope(declaringCompilationUnit); } @Override public CompilationUnit getDeclaringCompilationUnit() { return (CompilationUnit) this.getEnclosingScope(); } // Implement TypeDeclaration. @Override public String getClassName() { String className = this.getName(); CompilationUnit compilationUnit = (CompilationUnit) this.getEnclosingScope(); if (compilationUnit.optionalPackageDeclaration != null) { className = compilationUnit.optionalPackageDeclaration.packageName + '.' + className; } return className; } @Override public void accept(Visitor.TypeDeclarationVisitor visitor) { visitor.visitPackageMemberInterfaceDeclaration(this); } } /** 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. */ public final ReferenceType[] optionalBound; public TypeParameter(String name, ReferenceType[] optionalBound) { assert name != null; this.name = name; this.optionalBound = optionalBound; } @Override public String toString() { return ( this.optionalBound == null ? this.name : this.name + " extends " + Java.join(this.optionalBound, " & ") ); } } /** * Representation of a "ClassBodyDeclaration" or an "InterfaceMemberDeclaration". These are: *

*/ 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(); /** @return Whether this declaration has the STATIC modifier */ boolean isStatic(); /** * Invokes the '{@code visit...()}' method of {@link Visitor.TypeBodyDeclarationVisitor} for the concrete * {@link TypeBodyDeclaration} type. */ void accept(Visitor.TypeBodyDeclarationVisitor visitor); } /** Abstract implementation of {@link TypeBodyDeclaration}. */ public abstract static class AbstractTypeBodyDeclaration extends Located implements TypeBodyDeclaration { private TypeDeclaration declaringType; /** Whether this declaration has the STATIC modifier */ public final boolean statiC; protected AbstractTypeBodyDeclaration(Location location, boolean statiC) { super(location); this.statiC = statiC; } // Implement TypeBodyDeclaration. @Override public void setDeclaringType(TypeDeclaration declaringType) { if (this.declaringType != null && declaringType != null) { throw new JaninoRuntimeException( "Declaring type for type body declaration \"" + this.toString() + "\"at " + this.getLocation() + " is already set" ); } this.declaringType = declaringType; } @Override public TypeDeclaration getDeclaringType() { return this.declaringType; } @Override public boolean isStatic() { return this.statiC; } /** Forward-implements {@link BlockStatement#setEnclosingScope(Java.Scope)}. */ public void setEnclosingScope(Scope enclosingScope) { this.declaringType = (TypeDeclaration) enclosingScope; } // Implement 'Scope'. @Override public Scope getEnclosingScope() { 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, boolean statiC, Block block) { super(location, statiC); (this.block = block).setEnclosingScope(this); } @Override public String toString() { return this.statiC ? "static " + this.block : this.block.toString(); } // Implement BlockStatement. @Override public void accept(Visitor.TypeBodyDeclarationVisitor visitor) { visitor.visitInitializer(this); } @Override public void accept(Visitor.BlockStatementVisitor visitor) { visitor.visitInitializer(this); } @Override 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 DocCommentable { private final String optionalDocComment; /** The {@link Modifiers} of this declarator. */ public final Modifiers modifiers; /** The return type of the function (VOID for constructors). */ public final Type type; /** The name of the function ("" 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. */ public final List optionalStatements; public FunctionDeclarator( Location location, String optionalDocComment, Modifiers modifiers, Type type, String name, FormalParameters parameters, Type[] thrownExceptions, List optionalStatements ) { super(location, Mod.isStatic(modifiers.flags)); this.optionalDocComment = optionalDocComment; this.modifiers = parameters.variableArity ? modifiers.add(Mod.VARARGS) : modifiers; this.type = type; this.name = name; this.formalParameters = parameters; this.thrownExceptions = thrownExceptions; this.optionalStatements = optionalStatements; this.type.setEnclosingScope(this); for (FormalParameter fp : parameters.parameters) fp.type.setEnclosingScope(this); for (Type te : thrownExceptions) te.setEnclosingScope(this); if (optionalStatements != null) { for (Java.BlockStatement bs : optionalStatements) { // Catch 22: In the initializers, some statement have their enclosing already // set! if (("".equals(name) || "".equals(name)) && bs.getEnclosingScope() != null) continue; bs.setEnclosingScope(this); } } } /** @return The annotations of this function */ public Annotation[] getAnnotations() { return this.modifiers.annotations; } // Implement "FunctionDeclarator". /** * Invokes the '{@code visit...()}' method of {@link Visitor.FunctionDeclaratorVisitor} for the concrete * {@link FunctionDeclarator} type. */ public abstract void accept(Visitor.FunctionDeclaratorVisitor visitor); // Override "AbstractTypeBodyDeclaration" @Override public void setDeclaringType(TypeDeclaration declaringType) { super.setDeclaringType(declaringType); for (Annotation a : this.modifiers.annotations) a.setEnclosingScope(declaringType); } // Implement "Scope". @Override public Scope getEnclosingScope() { return this.getDeclaringType(); } /** Set by "compile()". */ IClass returnType; // Implement DocCommentable. @Override 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() { this(null, 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 { /** Whether the parameter is declared FINAL. */ public final boolean finaL; /** The type of the parameter. */ public final Type type; /** The name of the parameter. */ public final String name; public FormalParameter(Location location, boolean finaL, Type type, String name) { super(location); this.finaL = finaL; this.type = type; this.name = name; } /** * @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. */ public Java.LocalVariable localVariable; } // Compile time members /** Mapping of variable names to {@link LocalVariable}s. */ public Map localVariables; } /** Representation of a constructor declarator. */ public static final class ConstructorDeclarator extends FunctionDeclarator { /** The resolved {@link IClass.IConstructor}. */ IClass.IConstructor iConstructor; /** The {@link AlternateConstructorInvocation} or {@link SuperConstructorInvocation}, if any. */ public final ConstructorInvocation optionalConstructorInvocation; public ConstructorDeclarator( Location location, String optionalDocComment, Modifiers modifiers, FormalParameters parameters, Type[] thrownExceptions, ConstructorInvocation optionalConstructorInvocation, List statements ) { super( location, // location optionalDocComment, // optionalDocComment modifiers, // modifiers new BasicType(location, BasicType.VOID), // type "", // name parameters, // parameters thrownExceptions, // thrownExceptions statements // optionalStatements ); this.optionalConstructorInvocation = optionalConstructorInvocation; if (optionalConstructorInvocation != null) optionalConstructorInvocation.setEnclosingScope(this); } /** @return The {@link ClassDeclaration} where this {@link ConstructorDeclarator} appears */ public ClassDeclaration getDeclaringClass() { return (ClassDeclaration) 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 public void accept(Visitor.TypeBodyDeclarationVisitor visitor) { visitor.visitConstructorDeclarator(this); } @Override public void accept(Visitor.FunctionDeclaratorVisitor visitor) { visitor.visitConstructorDeclarator(this); } } /** Representation of a method declarator. */ public static final class MethodDeclarator extends FunctionDeclarator { public MethodDeclarator( Location location, String optionalDocComment, Java.Modifiers modifiers, Type type, String name, FormalParameters parameters, Type[] thrownExceptions, List optionalStatements ) { super( location, // location optionalDocComment, // optionalDocComment modifiers, // modifiers type, // type name, // name parameters, // parameters thrownExceptions, // thrownExceptions optionalStatements // optionalStatements ); } @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 public void accept(Visitor.TypeBodyDeclarationVisitor visitor) { visitor.visitMethodDeclarator(this); } @Override public void accept(Visitor.FunctionDeclaratorVisitor visitor) { visitor.visitMethodDeclarator(this); } /** The resolved {@link IMethod}. */ IClass.IMethod iMethod; } /** * 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 TypeBodyDeclaration, DocCommentable { private final String optionalDocComment; /** The modifiers of this field declaration. */ public final Modifiers 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, String optionalDocComment, Modifiers 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) { if (vd.optionalInitializer != null) Java.setEnclosingBlockStatement(vd.optionalInitializer, this); } } /** @return The annotations of this field */ public Annotation[] getAnnotations() { return this.modifiers.annotations; } // Implement TypeBodyDeclaration. @Override public void setDeclaringType(TypeDeclaration declaringType) { this.setEnclosingScope(declaringType); } @Override public TypeDeclaration getDeclaringType() { return (TypeDeclaration) this.getEnclosingScope(); } @Override public boolean isStatic() { return Mod.isStatic(this.modifiers.flags); } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append(Mod.shortToString(this.modifiers.flags)).append(' ').append(this.type); sb.append(' ').append(this.variableDeclarators[0]); for (int i = 1; i < this.variableDeclarators.length; ++i) { sb.append(", ").append(this.variableDeclarators[i]); } return sb.toString(); } @Override public void accept(Visitor.TypeBodyDeclarationVisitor visitor) { visitor.visitFieldDeclaration(this); } @Override public void accept(Visitor.BlockStatementVisitor visitor) { visitor.visitFieldDeclaration(this); } // Implement DocCommentable. @Override public String getDocComment() { return this.optionalDocComment; } @Override public boolean hasDeprecatedDocTag() { return this.optionalDocComment != null && this.optionalDocComment.indexOf("@deprecated") != -1; } } private static void setEnclosingBlockStatement(ArrayInitializerOrRvalue aiorv, BlockStatement enclosingBlockStatement) { if (aiorv instanceof Rvalue) { ((Rvalue) aiorv).setEnclosingBlockStatement(enclosingBlockStatement); } else if (aiorv instanceof ArrayInitializer) { for (ArrayInitializerOrRvalue v : ((ArrayInitializer) aiorv).values) { Java.setEnclosingBlockStatement(v, enclosingBlockStatement); } } else { throw new JaninoRuntimeException("Unexpected array or initializer class " + aiorv.getClass().getName()); } } /** 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. */ public final ArrayInitializerOrRvalue optionalInitializer; public VariableDeclarator(Location location, String name, int brackets, 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. } @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. */ 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. */ void accept(Visitor.BlockStatementVisitor visitor); /** @return The local variable with the given {@code name} */ 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 mis-named; according to JLS7 8.8.7 and 14.2, its name should be 'BlockStatement'. */ public abstract static class Statement extends Located implements BlockStatement { private Scope enclosingScope; protected Statement(Location location) { super(location); } // Implement "BlockStatement". @Override public void setEnclosingScope(Scope enclosingScope) { if (this.enclosingScope != null && enclosingScope != this.enclosingScope) { throw new JaninoRuntimeException( "Enclosing scope is already set for statement \"" + this.toString() + "\" at " + this.getLocation() ); } this.enclosingScope = enclosingScope; } @Override public Scope getEnclosingScope() { return this.enclosingScope; } // Compile time members /** The map of currently visible local variables. */ public Map localVariables; @Override public Java.LocalVariable findLocalVariable(String name) { if (this.localVariables == null) { return null; } return (LocalVariable) this.localVariables.get(name); } } /** Representation of a JLS7 14.7 'labeled statement'. */ public static final class LabeledStatement extends BreakableStatement { /** The lael 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 public void accept(Visitor.BlockStatementVisitor visitor) { 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 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 public void accept(Visitor.BlockStatementVisitor visitor) { visitor.visitBlock(this); } @Override public String toString() { return "{ ... }"; } } /** * Base class for statements that can be terminated abnormally with a "break" statement. *

* According JLS7 14.15, statements that can be terminated abnormally with a "break" statement are *

    *
  • {@link ContinuableStatement}s ("for", "do" and "while") *
  • Labeled statements *
  • "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. */ CodeContext.Offset whereToBreak; } /** * Base class for statements that support the 'continue' statement. *

* According to the JLS7 14.16, these are "for", "do" and "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. */ 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).setEnclosingBlockStatement(this); } @Override public String toString() { return this.rvalue.toString() + ';'; } // Compile time members: @Override public void accept(Visitor.BlockStatementVisitor visitor) { 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 public void accept(Visitor.BlockStatementVisitor visitor) { 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. */ public final BlockStatement optionalElseStatement; /** * Notice that the elseStatement is mandatory; for an if statement without * an "else" clause, a dummy {@link Java.EmptyStatement} should be passed. */ public IfStatement( Location location, Rvalue condition, BlockStatement thenStatement, BlockStatement optionalElseStatement ) { super(location); (this.condition = condition).setEnclosingBlockStatement(this); (this.thenStatement = thenStatement).setEnclosingScope(this); this.optionalElseStatement = optionalElseStatement; if (optionalElseStatement != null) optionalElseStatement.setEnclosingScope(this); } @Override public String toString() { return this.optionalElseStatement == null ? "if" : "if ... else"; } // Compile time members: @Override public void accept(Visitor.BlockStatementVisitor visitor) { 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'. */ public final BlockStatement optionalInit; /** The optional 'condition' part of the 'basic FOR statement'. */ public final Rvalue optionalCondition; /** The optional 'update' part of the 'basic FOR statement'. */ public final Rvalue[] optionalUpdate; public ForStatement( Location location, BlockStatement optionalInit, Rvalue optionalCondition, Rvalue[] optionalUpdate, BlockStatement body ) { super(location, body); this.optionalInit = optionalInit; if (optionalInit != null) optionalInit.setEnclosingScope(this); this.optionalCondition = optionalCondition; if (optionalCondition != null) optionalCondition.setEnclosingBlockStatement(this); this.optionalUpdate = optionalUpdate; if (optionalUpdate != null) for (Rvalue rv : optionalUpdate) rv.setEnclosingBlockStatement(this); } @Override public String toString() { return "for (...; ...; ...) ..."; } // Compile time members: @Override public void accept(Visitor.BlockStatementVisitor visitor) { 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).setEnclosingBlockStatement(this); } @Override public String toString() { return "for (... : ...) ..."; } // Compile time members: @Override public void accept(Visitor.BlockStatementVisitor visitor) { 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).setEnclosingBlockStatement(this); } @Override public String toString() { return "while (" + this.condition + ") " + this.body + ';'; } // Compile time members: @Override public void accept(Visitor.BlockStatementVisitor visitor) { visitor.visitWhileStatement(this); } } /** Representation of a JLS7 14.20 TRY statement. */ public static final class TryStatement extends Statement { /** 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. */ public final Block optionalFinally; public TryStatement( Location location, BlockStatement body, List catchClauses, Block optionalFinally ) { super(location); (this.body = body).setEnclosingScope(this); for (CatchClause cc : (this.catchClauses = catchClauses)) cc.setEnclosingTryStatement(this); this.optionalFinally = optionalFinally; if (optionalFinally != null) optionalFinally.setEnclosingScope(this); } @Override public String toString() { return ( "try ... " + this.catchClauses.size() + (this.optionalFinally == null ? " catches" : " catches ... finally") ); } // Compile time members: @Override public void accept(Visitor.BlockStatementVisitor visitor) { visitor.visitTryStatement(this); } /** * This one's created iff the TRY statement has a FINALLY clause when the compilation of the TRY statement * begins. */ CodeContext.Offset finallyOffset; } /** Representation of a JLS7 14.20.1 CATCH clause. */ public static class CatchClause extends Located implements Scope { /** Container for the type and the name of the caught exception. */ public final FormalParameter caughtException; /** Body of the CATCH clause. */ public final Block body; /** Link to the enclosing TRY statement. */ private TryStatement enclosingTryStatement; // Compile time fields. /** Flag for catch clause reachability analysis. */ public boolean reachable; public CatchClause(Location location, FormalParameter caughtException, Block body) { super(location); (this.caughtException = caughtException).type.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 JaninoRuntimeException( "Enclosing TRY statement already set for catch clause " + this.toString() + " at " + this.getLocation() ); } this.enclosingTryStatement = enclosingTryStatement; } @Override public Scope getEnclosingScope() { return this.enclosingTryStatement; } @Override public String toString() { return "catch (" + this.caughtException + ") " + this.body; } } /** The JLS7 14.10 "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).setEnclosingBlockStatement(this); for (SwitchBlockStatementGroup sbsg : (this.sbsgs = sbsgs)) { for (Rvalue cl : sbsg.caseLabels) cl.setEnclosingBlockStatement(this); for (BlockStatement bs : sbsg.blockStatements) bs.setEnclosingScope(this); } } @Override public String toString() { return "switch (" + this.condition + ") { (" + 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 public void accept(Visitor.BlockStatementVisitor visitor) { visitor.visitSwitchStatement(this); } } static class Padder extends CodeContext.Inserter implements CodeContext.FixUp { public 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((short) -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).setEnclosingBlockStatement(this); (this.body = body).setEnclosingScope(this); } @Override public String toString() { return "synchronized(" + this.expression + ") " + this.body; } // Compile time members: @Override public void accept(Visitor.BlockStatementVisitor visitor) { 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).setEnclosingBlockStatement(this); } @Override public String toString() { return "do " + this.body + " while(" + this.condition + ");"; } // Compile time members: @Override public void accept(Visitor.BlockStatementVisitor visitor) { 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 Modifiers 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 "final" allowed */ public LocalVariableDeclarationStatement( Location location, Modifiers modifiers, Type type, VariableDeclarator[] variableDeclarators ) { super(location); this.modifiers = modifiers; this.type = type; this.variableDeclarators = variableDeclarators; this.type.setEnclosingScope(this); for (VariableDeclarator vd : variableDeclarators) { if (vd.optionalInitializer != null) Java.setEnclosingBlockStatement(vd.optionalInitializer, this); } } // Compile time members: @Override public void accept(Visitor.BlockStatementVisitor visitor) { visitor.visitLocalVariableDeclarationStatement(this); } @Override public String toString() { StringBuilder sb = new StringBuilder(); if (this.modifiers.flags != Mod.NONE) { sb.append(Mod.shortToString(this.modifiers.flags)).append(' '); } sb.append(this.type).append(' ').append(this.variableDeclarators[0].toString()); for (int i = 1; i < this.variableDeclarators.length; ++i) { sb.append(", ").append(this.variableDeclarators[i].toString()); } return sb.append(';').toString(); } } /** Representation of the JLS7 14.17 RETURN statement. */ public static final class ReturnStatement extends Statement { /** The optional rvalue that is returned. */ public final Rvalue optionalReturnValue; public ReturnStatement(Location location, Rvalue optionalReturnValue) { super(location); this.optionalReturnValue = optionalReturnValue; if (optionalReturnValue != null) optionalReturnValue.setEnclosingBlockStatement(this); } @Override public String toString() { return this.optionalReturnValue == null ? "return;" : "return " + this.optionalReturnValue + ';'; } // Compile time members: @Override public void accept(Visitor.BlockStatementVisitor visitor) { 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).setEnclosingBlockStatement(this); } @Override public String toString() { return "throw " + this.expression + ';'; } // Compile time members: @Override public void accept(Visitor.BlockStatementVisitor visitor) { 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. */ public final String optionalLabel; public BreakStatement(Location location, String optionalLabel) { super(location); this.optionalLabel = optionalLabel; } @Override public String toString() { return this.optionalLabel == null ? "break;" : "break " + this.optionalLabel + ';'; } // Compile time members: @Override public void accept(Visitor.BlockStatementVisitor visitor) { 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. */ public final String optionalLabel; public ContinueStatement(Location location, String optionalLabel) { super(location); this.optionalLabel = optionalLabel; } @Override public String toString() { return this.optionalLabel == null ? "continue;" : "continue " + this.optionalLabel + ';'; } // Compile time members: @Override public void accept(Visitor.BlockStatementVisitor visitor) { 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. */ public final Rvalue optionalExpression2; public AssertStatement(Location location, Rvalue expression1, Rvalue optionalExpression2) { super(location); this.expression1 = expression1; this.optionalExpression2 = optionalExpression2; this.expression1.setEnclosingBlockStatement(this); if (this.optionalExpression2 != null) this.optionalExpression2.setEnclosingBlockStatement(this); } @Override public String toString() { return ( this.optionalExpression2 == null ? "assert " + this.expression1 + ';' : "assert " + this.expression1 + " : " + this.optionalExpression2 + ';' ); } @Override public void accept(BlockStatementVisitor visitor) { 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 public void accept(Visitor.BlockStatementVisitor visitor) { visitor.visitEmptyStatement(this); } } /** Abstract base class for {@link Java.Type}, {@link Java.Rvalue} and {@link Java.Lvalue}. */ 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 */ public Type toType() { return null; } /** @return This atom, converted to {@link Rvalue}, or {@code null} if this atom is not an rvalue */ public Rvalue toRvalue() { return null; } /** @return This atom, converted to {@link Lvalue}, or {@code null} if this atom is not an lvalue */ 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) this.throwCompileException("Expression \"" + this.toString() + "\" is not a type"); return result; } /** * @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) this.throwCompileException("Expression \"" + this.toString() + "\" is not an rvalue"); return result; } /** * @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) this.throwCompileException("Expression \"" + this.toString() + "\" is not an lvalue"); return result; } /** * Invokes the '{@code visit...()}' method of {@link Visitor.AtomVisitor} for the concrete {@link Atom} type. */ public abstract void accept(Visitor.AtomVisitor visitor); } /** Representation of a Java™ type. */ public abstract static class Type extends Atom { 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) { throw new JaninoRuntimeException( "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() { return this.enclosingScope; } @Override public Type toType() { return this; } /** * Invokes the '{@code visit...()}' method of {@link Visitor.TypeVisitor} for the concrete {@link Type} type. */ public abstract void accept(Visitor.TypeVisitor visitor); } /** 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(); } @Override public void accept(Visitor.AtomVisitor visitor) { visitor.visitSimpleType(this); } @Override public void accept(Visitor.TypeVisitor visitor) { visitor.visitSimpleType(this); } } /** Representation of a JLS7 18 "basic type" (obviously equivalent to a JLS7 4.2 "primitive type"). */ public static final class BasicType extends Type { /** One of {@link #VOID}, {@link #BYTE} and consorts. */ public final int index; public BasicType(Location location, int index) { super(location); this.index = index; } @Override public String toString() { switch (this.index) { case BasicType.VOID: return "void"; case BasicType.BYTE: return "byte"; case BasicType.SHORT: return "short"; case BasicType.CHAR: return "char"; case BasicType.INT: return "int"; case BasicType.LONG: return "long"; case BasicType.FLOAT: return "float"; case BasicType.DOUBLE: return "double"; case BasicType.BOOLEAN: return "boolean"; default: throw new JaninoRuntimeException("Invalid index " + this.index); } } @Override public void accept(Visitor.TypeVisitor visitor) { visitor.visitBasicType(this); } @Override public void accept(Visitor.AtomVisitor visitor) { visitor.visitBasicType(this); } /** Value representing the VOID type. */ public static final int VOID = 0; /** Value representing the BYTE type. */ public static final int BYTE = 1; /** Value representing the SHORT type. */ public static final int SHORT = 2; /** Value representing the CHAR type. */ public static final int CHAR = 3; /** Value representing the INT type. */ public static final int INT = 4; /** Value representing the LONG type. */ public static final int LONG = 5; /** Value representing the FLOAT type. */ public static final int FLOAT = 6; /** Value representing the DOUBLE type. */ public static final int DOUBLE = 7; /** Value representing the BOOLEAN type. */ public static final int BOOLEAN = 8; } /** representation of a JLS7 4.3 reference type. */ public static final class ReferenceType extends Type implements TypeArgument { /** 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. */ public final TypeArgument[] optionalTypeArguments; public ReferenceType(Location location, String[] identifiers, TypeArgument[] optionalTypeArguments) { super(location); assert identifiers != null; this.identifiers = identifiers; this.optionalTypeArguments = optionalTypeArguments; } @Override public String toString() { String s = Java.join(this.identifiers, "."); if (this.optionalTypeArguments != null) s += '<' + Java.join(this.optionalTypeArguments, ", ") + ">"; return s; } @Override public void accept(Visitor.AtomVisitor visitor) { visitor.visitReferenceType(this); } @Override public void accept(Visitor.TypeVisitor visitor) { visitor.visitReferenceType(this); } @Override public void accept(TypeArgumentVisitor visitor) { 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. */ void accept(Visitor.TypeArgumentVisitor visitor); } /** * Representation of the first part of a JLS7 15.9 'Qualified class instance creation expression': The 'a.new * MyClass' part of 'a.new MyClass(...)'. */ 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 {@code 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; } @Override public void accept(Visitor.AtomVisitor visitor) { visitor.visitRvalueMemberType(this); } @Override public void accept(Visitor.TypeVisitor visitor) { 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() + "[]"; } @Override public void accept(Visitor.AtomVisitor visitor) { visitor.visitArrayType(this); } @Override public void accept(Visitor.TypeVisitor visitor) { visitor.visitArrayType(this); } @Override public void accept(TypeArgumentVisitor visitor) { 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 { private Java.BlockStatement enclosingBlockStatement; protected Rvalue(Location location) { super(location); } /** Sets enclosing block statement for this object and all subordinate {@link Java.Rvalue} objects. */ public final void setEnclosingBlockStatement(final Java.BlockStatement enclosingBlockStatement) { this.accept((Visitor.RvalueVisitor) new Traverser() { @Override public void traverseRvalue(Java.Rvalue rv) { if (rv.enclosingBlockStatement != null && enclosingBlockStatement != rv.enclosingBlockStatement) { throw new JaninoRuntimeException( "Enclosing block statement for rvalue \"" + rv + "\" at " + rv.getLocation() + " is already set" ); } rv.enclosingBlockStatement = enclosingBlockStatement; super.traverseRvalue(rv); } @Override public void traverseAnonymousClassDeclaration(Java.AnonymousClassDeclaration acd) { acd.setEnclosingScope(enclosingBlockStatement); ; } @Override public void traverseType(Java.Type t) { if (t.enclosingScope != null && enclosingBlockStatement != t.enclosingScope) { throw new JaninoRuntimeException( "Enclosing scope already set for type \"" + this.toString() + "\" at " + t.getLocation() ); } t.enclosingScope = enclosingBlockStatement; // t.setEnclosingScope(enclosingBlockStatement); super.traverseType(t); } }.comprehensiveVisitor()); } /** * @return The enclosing block statement, as set with {@link #setEnclosingBlockStatement(Java.BlockStatement)} */ public Java.BlockStatement getEnclosingBlockStatement() { return this.enclosingBlockStatement; } @Override public Rvalue toRvalue() { return this; } /** * The special value for the {@link #constantValue} field indicating that this rvalue does not have a * constant value. */ 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 this rvalue does not have a * constant value. */ Object constantValue = Java.Rvalue.CONSTANT_VALUE_UNKNOWN; /** * Invokes the '{@code visit...()}' method of {@link Visitor.RvalueVisitor} for the concrete {@link Rvalue} * type. */ public abstract void accept(Visitor.RvalueVisitor rvv); } /** 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 public Lvalue toLvalue() { return this; } /** * Invokes the '{@code visit...()}' method of {@link Visitor.LvalueVisitor} for the concrete {@link Lvalue} * type. */ public abstract void accept(Visitor.LvalueVisitor lvv); } /** * 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. */ public static final class AmbiguousName extends Lvalue { /** The first {@link #n} of these identifiers comprise this ambiguous name. */ public final String[] identifiers; /** @see #identifiers */ public final int n; public AmbiguousName(Location location, String[] identifiers) { this(location, identifiers, identifiers.length); } public AmbiguousName(Location location, String[] identifiers, int n) { super(location); this.identifiers = identifiers; this.n = n; } // Override "Atom.toType()". private Type type; @Override public Type toType() { if (this.type == null) { String[] is = new String[this.n]; System.arraycopy(this.identifiers, 0, is, 0, this.n); this.type = new ReferenceType(this.getLocation(), is, null); this.type.setEnclosingScope(this.getEnclosingBlockStatement()); } return this.type; } // Compile time members. @Override public String toString() { return Java.join(this.identifiers, ".", 0, this.n); } @Override public Lvalue toLvalue() { if (this.reclassified != null) { return this.reclassified.toLvalue(); } return this; } @Override public Rvalue toRvalue() { if (this.reclassified != null) { return this.reclassified.toRvalue(); } return this; } /** The result of 'ambiguous name resolution' furing compilation. */ Atom reclassified; @Override public void accept(Visitor.AtomVisitor visitor) { visitor.visitAmbiguousName(this); } @Override public void accept(Visitor.RvalueVisitor visitor) { visitor.visitAmbiguousName(this); } @Override public void accept(Visitor.LvalueVisitor visitor) { visitor.visitAmbiguousName(this); } @Override public void accept(Visitor.ElementValueVisitor visitor) { 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 public void accept(Visitor.AtomVisitor visitor) { 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.toString(); } @Override public void accept(Visitor.LvalueVisitor visitor) { visitor.visitLocalVariableAccess(this); } @Override public void accept(Visitor.RvalueVisitor visitor) { visitor.visitLocalVariableAccess(this); } @Override public void accept(Visitor.AtomVisitor visitor) { visitor.visitLocalVariableAccess(this); } @Override public void accept(ElementValueVisitor visitor) { 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 public void accept(Visitor.AtomVisitor visitor) { visitor.visitFieldAccess(this); } @Override public void accept(Visitor.RvalueVisitor visitor) { visitor.visitFieldAccess(this); } @Override public void accept(Visitor.LvalueVisitor visitor) { visitor.visitFieldAccess(this); } @Override public void accept(ElementValueVisitor visitor) { 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 public void accept(Visitor.AtomVisitor visitor) { visitor.visitArrayLength(this); } @Override public void accept(Visitor.RvalueVisitor visitor) { visitor.visitArrayLength(this); } @Override public void accept(ElementValueVisitor visitor) { visitor.visitArrayLength(this); } } /** Representation of an JLS7 15.8.3 access to the innermost enclosing instance. */ public static final class ThisReference extends Rvalue { public ThisReference(Location location) { super(location); } // Compile time members. /** A cache for the type of the instance that 'this' refers to. */ IClass iClass; // Implement "Atom". @Override public String toString() { return "this"; } @Override public void accept(Visitor.AtomVisitor visitor) { visitor.visitThisReference(this); } @Override public void accept(Visitor.RvalueVisitor visitor) { visitor.visitThisReference(this); } @Override public void accept(ElementValueVisitor visitor) { visitor.visitThisReference(this); } } /** Representation of an JLS7 15.8.4 access to the current object or an enclosing instance. */ public static final class QualifiedThisReference extends Rvalue { /** The qualification left from the 'this' keyword. */ public final Type qualification; public QualifiedThisReference(Location location, Type qualification) { super(location); if (qualification == null) throw new NullPointerException(); this.qualification = qualification; } // Compile time members. /** The innermost enclosing class declaration. */ ClassDeclaration declaringClass; /** * The innermost 'type body declaration' enclosing this 'qualified this reference', i.e. the method, * type initializer or field initializer. */ TypeBodyDeclaration declaringTypeBodyDeclaration; /** The resolved {@link #qualification}. */ IClass targetIClass; // Implement "Atom". @Override public String toString() { return this.qualification.toString() + ".this"; } @Override public void accept(Visitor.AtomVisitor visitor) { visitor.visitQualifiedThisReference(this); } @Override public void accept(Visitor.RvalueVisitor visitor) { visitor.visitQualifiedThisReference(this); } @Override public void accept(ElementValueVisitor visitor) { visitor.visitQualifiedThisReference(this); } } /** Representation of a JLS7 15.8.2 'class literal'. */ public static final class ClassLiteral extends Rvalue { /** The type left of the '.class' suffix. */ public final Type type; public ClassLiteral(Location location, Type type) { super(location); this.type = type; } // Implement "Atom". @Override public String toString() { return this.type.toString() + ".class"; } @Override public void accept(Visitor.AtomVisitor visitor) { visitor.visitClassLiteral(this); } @Override public void accept(Visitor.RvalueVisitor visitor) { visitor.visitClassLiteral(this); } @Override public void accept(ElementValueVisitor visitor) { visitor.visitClassLiteral(this); } } /** Representation of all JLS7 15.26 assignments. */ public static final class Assignment extends Rvalue { /** The lvalue to assign to. */ public final Lvalue lhs; /** * The assignment operator; either the 'simple assignment operator ('=', JLS7 15.26.1) or one of the 'compound * assignment operators (JLS7 15.26.2). */ public final String operator; /** The rvalue that is assigned. */ public final Rvalue rhs; public Assignment(Location location, Lvalue lhs, String operator, Rvalue rhs) { super(location); this.lhs = lhs; this.operator = operator; this.rhs = rhs; } // Compile time members. // Implement "Atom". @Override public String toString() { return this.lhs.toString() + ' ' + this.operator + ' ' + this.rhs.toString(); } @Override public void accept(Visitor.AtomVisitor visitor) { visitor.visitAssignment(this); } @Override public void accept(Visitor.RvalueVisitor visitor) { visitor.visitAssignment(this); } @Override public void accept(ElementValueVisitor visitor) { visitor.visitAssignment(this); } } /** Representation of a JLS7 15.25 'conditional operation'. */ public static final class ConditionalExpression extends Rvalue { /** Left-hand side of this conditional operation. */ public final Rvalue lhs; /** Middle-hand side of this conditional operation. */ public final Rvalue mhs; /** Right-hand side of this conditional operation. */ public final Rvalue rhs; public ConditionalExpression(Location location, Rvalue lhs, Rvalue mhs, Rvalue rhs) { super(location); this.lhs = lhs; this.mhs = mhs; this.rhs = rhs; } // Implement "Atom". @Override public String toString() { return this.lhs.toString() + " ? " + this.mhs.toString() + " : " + this.rhs.toString(); } @Override public void accept(Visitor.AtomVisitor visitor) { visitor.visitConditionalExpression(this); } @Override public void accept(Visitor.RvalueVisitor visitor) { visitor.visitConditionalExpression(this); } @Override public void accept(ElementValueVisitor visitor) { visitor.visitConditionalExpression(this); } } /** * Representation of a JLS7 15.14.2 'postfix increment operation', a JLS7 15.14.3 'postfix decrement operation', a * JLS7 15.15.1 'prefix increment operation' or a JLS7 15.15.2 'prefix decrement operation'. */ public static final class Crement extends Rvalue { /** Whether this operation is 'pre' (TRUE) or 'post' (FALSE). */ public final boolean pre; /** The operator; either "++" or "--". */ public final String operator; /** The lvalue to operate upon. */ public final Lvalue operand; public Crement(Location location, String operator, Lvalue operand) { super(location); this.pre = true; this.operator = operator; this.operand = operand; } public Crement(Location location, Lvalue operand, String operator) { super(location); this.pre = false; this.operator = operator; this.operand = operand; } // Compile time members. // Implement "Atom". @Override public String toString() { return this.pre ? this.operator + this.operand : this.operand + this.operator; } @Override public void accept(Visitor.AtomVisitor visitor) { visitor.visitCrement(this); } @Override public void accept(Visitor.RvalueVisitor visitor) { visitor.visitCrement(this); } @Override public void accept(ElementValueVisitor visitor) { visitor.visitCrement(this); } } /** Representation of a JLS7 15.13 'array access expression'. */ public static final class ArrayAccessExpression extends Lvalue { /** The array to access (must be an {@link Lvalue} if the access is modifying). */ public final Rvalue lhs; /** The index value to use. */ public final Rvalue index; public ArrayAccessExpression(Location location, Rvalue lhs, Rvalue index) { super(location); this.lhs = lhs; this.index = index; } // Compile time members: // Implement "Atom". @Override public String toString() { return this.lhs.toString() + '[' + this.index + ']'; } @Override public void accept(Visitor.AtomVisitor visitor) { visitor.visitArrayAccessExpression(this); } @Override public void accept(Visitor.RvalueVisitor visitor) { visitor.visitArrayAccessExpression(this); } @Override public void accept(Visitor.LvalueVisitor visitor) { visitor.visitArrayAccessExpression(this); } @Override public void accept(ElementValueVisitor visitor) { visitor.visitArrayAccessExpression(this); } } /** Representation of a JLS7 15.11 'field access expression', including the "array length" pseudo field access. */ public static final class FieldAccessExpression extends Lvalue { /** {@link Type}, {@link Rvalue} or {@link Lvalue} to operate upon. */ public final Atom lhs; /** Name of the field within the {@link #lhs} to access. */ public final String fieldName; public FieldAccessExpression(Location location, Atom lhs, String fieldName) { super(location); this.lhs = lhs; this.fieldName = fieldName; } // Compile time members: // Implement "Atom". @Override public String toString() { return this.lhs.toString() + '.' + this.fieldName; } @Override public void accept(Visitor.AtomVisitor visitor) { visitor.visitFieldAccessExpression(this); } @Override public void accept(Visitor.RvalueVisitor visitor) { visitor.visitFieldAccessExpression(this); } @Override public void accept(Visitor.LvalueVisitor visitor) { visitor.visitFieldAccessExpression(this); } @Override public void accept(ElementValueVisitor visitor) { visitor.visitFieldAccessExpression(this); } /** The {@link ArrayLength} or {@link FieldAccess} resulting from this 'field access expression'. */ Rvalue value; } /** Representation of an JLS7 'superclass field access expression', e.g. "super.fld" and "Type.super.fld". */ public static final class SuperclassFieldAccessExpression extends Lvalue { /** The optional qualification before '.super.fld'. */ public final Type optionalQualification; /** The name of the field to access. */ public final String fieldName; public SuperclassFieldAccessExpression(Location location, Type optionalQualification, String fieldName) { super(location); this.optionalQualification = optionalQualification; this.fieldName = fieldName; } // Compile time members. // Implement "Atom". @Override public String toString() { return ( this.optionalQualification == null ? "super." : this.optionalQualification.toString() + ".super." ) + this.fieldName; } @Override public void accept(Visitor.AtomVisitor visitor) { visitor.visitSuperclassFieldAccessExpression(this); } @Override public void accept(Visitor.RvalueVisitor visitor) { visitor.visitSuperclassFieldAccessExpression(this); } @Override public void accept(Visitor.LvalueVisitor visitor) { visitor.visitSuperclassFieldAccessExpression(this); } @Override public void accept(ElementValueVisitor visitor) { visitor.visitSuperclassFieldAccessExpression(this); } /** The {@link FieldAccess} that implements this {@link FieldAccessExpression}. */ Rvalue value; } /** * Representation of a JLS7 15.15.3 'unary plus operator', a JLS7 15.15.4 'unary minus operator', a JLS7 15.15.5 * 'bitwise complement operator' or a JLS7 15.15.6 'logical complement operator'. */ public static final class UnaryOperation extends BooleanRvalue { /** The operator (either "+", "-", "~" or "!"). */ public final String operator; /** The rvalue to operate upon. */ public final Rvalue operand; public UnaryOperation(Location location, String operator, Rvalue operand) { super(location); this.operator = operator; this.operand = operand; } // Implement "Atom". @Override public String toString() { return this.operator + this.operand.toString(); } @Override public void accept(Visitor.AtomVisitor visitor) { visitor.visitUnaryOperation(this); } @Override public void accept(Visitor.RvalueVisitor visitor) { visitor.visitUnaryOperation(this); } @Override public void accept(ElementValueVisitor visitor) { visitor.visitUnaryOperation(this); } } /** Representation of a JLS7 15.20.2 'type comparison operation'. */ public static final class Instanceof extends Rvalue { /** The rvalue who's type is to be compared. */ public final Rvalue lhs; /** The type that the {@link #lhs} is checked against. */ public final Type rhs; public Instanceof(Location location, Rvalue lhs, Type rhs) { super(location); this.lhs = lhs; this.rhs = rhs; } // Compile time members. // Implement "Atom". @Override public String toString() { return this.lhs.toString() + " instanceof " + this.rhs.toString(); } @Override public void accept(Visitor.AtomVisitor visitor) { visitor.visitInstanceof(this); } @Override public void accept(Visitor.RvalueVisitor visitor) { visitor.visitInstanceof(this); } @Override public void accept(ElementValueVisitor visitor) { visitor.visitInstanceof(this); } } /** * Representation of all non-operand-modifying binary operations. *

* Operations with boolean result: *

*
|| *
JLS7 15.24 'conditional or operation' *
&& *
JLS7 15.23 'conditional and operation' *
== *
JLS7 15.21 'equality operation' *
!= *
JLS7 15.22 'non-equality operation' *
< > <= >= *
JLS7 15.20.1 'numerical comparison operations' *
* Operations with non-boolean result: *
*
| *
JLS7 15.22.1 'integer bitwise OR operation' and JLS7 15.22.2 'boolean logical OR operation' *
^ *
JLS7 15.22.1 'integer bitwise XOR operation' and JLS7 15.22.2 'boolean logical XOR operation' *
& *
JLS7 15.22.1 'integer bitwise AND operation' and JLS7 15.22.2 'boolean logical AND operation' *
* / % *
JLS7 15.17 'multiplicative operations' *
+ - *
JLS7 15.18 'additive operations' *
<< >> >>> *
JLS7 15.19 'shift operations' *
*/ public static final class BinaryOperation extends BooleanRvalue { /** The left hand side operand. */ public final Rvalue lhs; /** The operator; one of thos described in {@link BinaryOperation}. */ public final String op; /** The right hand side operand. */ public final Rvalue rhs; public BinaryOperation(Location location, Rvalue lhs, String op, Rvalue rhs) { super(location); this.lhs = lhs; this.op = op; this.rhs = rhs; } // Compile time members. // Implement "Atom". @Override public String toString() { return this.lhs.toString() + ' ' + this.op + ' ' + this.rhs.toString(); } /** Returns an {@link Iterator} over a left-to-right sequence of {@link Java.Rvalue}s. */ public Iterator unrollLeftAssociation() { List operands = new ArrayList(); BinaryOperation bo = this; for (;;) { operands.add(bo.rhs); Rvalue lhs = bo.lhs; if (lhs instanceof BinaryOperation && ((BinaryOperation) lhs).op == this.op) { bo = (BinaryOperation) lhs; } else { operands.add(lhs); break; } } return new ReverseListIterator(operands.listIterator(operands.size())); } @Override public void accept(Visitor.AtomVisitor visitor) { visitor.visitBinaryOperation(this); } @Override public void accept(Visitor.RvalueVisitor visitor) { visitor.visitBinaryOperation(this); } @Override public void accept(ElementValueVisitor visitor) { visitor.visitBinaryOperation(this); } } /** Representation of a JLS7 15.16 'cast expression'. */ public static final class Cast extends Rvalue { /** The type to convert to. */ public final Type targetType; /** The rvalue to convert. */ public final Rvalue value; public Cast(Location location, Type targetType, Rvalue value) { super(location); this.targetType = targetType; this.value = value; } // Compile time members. // Implement "Atom". @Override public String toString() { return '(' + this.targetType.toString() + ") " + this.value.toString(); } @Override public void accept(Visitor.AtomVisitor visitor) { visitor.visitCast(this); } @Override public void accept(Visitor.RvalueVisitor visitor) { visitor.visitCast(this); } @Override public void accept(ElementValueVisitor visitor) { visitor.visitCast(this); } } /** Representation of a JLS7 15.8.5 'parenthesized expression'. */ public static final class ParenthesizedExpression extends Lvalue { /** The rvalue in parentheses. */ public final Rvalue value; public ParenthesizedExpression(Location location, Rvalue value) { super(location); this.value = value; } // Implement 'Atom'. @Override public String toString() { return '(' + this.value.toString() + ')'; } @Override public void accept(Visitor.AtomVisitor visitor) { visitor.visitParenthesizedExpression(this); } @Override public void accept(Visitor.RvalueVisitor visitor) { visitor.visitParenthesizedExpression(this); } @Override public void accept(Visitor.LvalueVisitor visitor) { visitor.visitParenthesizedExpression(this); } @Override public void accept(ElementValueVisitor visitor) { visitor.visitParenthesizedExpression(this); } } /** Abstract bas class for {@link SuperConstructorInvocation} and {@link AlternateConstructorInvocation}. */ public abstract static class ConstructorInvocation extends Atom implements BlockStatement { /** The arguments to pass to the constructor. */ public final Rvalue[] arguments; private Scope enclosingScope; protected ConstructorInvocation(Location location, Rvalue[] arguments) { super(location); this.arguments = arguments; for (Rvalue a : arguments) a.setEnclosingBlockStatement(this); } // Implement BlockStatement @Override public void setEnclosingScope(Scope enclosingScope) { if (this.enclosingScope != null && enclosingScope != null) { throw new JaninoRuntimeException( "Enclosing scope is already set for statement \"" + this.toString() + "\" at " + this.getLocation() ); } this.enclosingScope = enclosingScope; } @Override public Scope getEnclosingScope() { return this.enclosingScope; } /** The local variables that are accessible during the compilation of the constructor invocation. */ public Map localVariables; @Override public Java.LocalVariable findLocalVariable(String name) { if (this.localVariables == null) { return null; } return (LocalVariable) this.localVariables.get(name); } } /** Representation of a JLS7 8.8.7.1. 'alternate constructor invocation'. */ public static final class AlternateConstructorInvocation extends ConstructorInvocation { public AlternateConstructorInvocation(Location location, Rvalue[] arguments) { super(location, arguments); } // Implement Atom. @Override public String toString() { return "this()"; } @Override public void accept(Visitor.AtomVisitor visitor) { ((Visitor.BlockStatementVisitor) visitor).visitAlternateConstructorInvocation(this); } // Implement BlockStatement. @Override public void accept(Visitor.BlockStatementVisitor visitor) { visitor.visitAlternateConstructorInvocation(this); } } /** Representation of a JLS7 8.8.7.1. 'superclass constructor invocation'. */ public static final class SuperConstructorInvocation extends ConstructorInvocation { /** * The qualification for this 'qualified superclass constructor invocation', or {@code null} iff this is an * 'unqualified superclass constructor invocation'. */ public final Rvalue optionalQualification; public SuperConstructorInvocation(Location location, Rvalue optionalQualification, Rvalue[] arguments) { super(location, arguments); this.optionalQualification = optionalQualification; if (optionalQualification != null) optionalQualification.setEnclosingBlockStatement(this); } // Implement Atom. @Override public String toString() { return "super()"; } @Override public void accept(Visitor.AtomVisitor visitor) { ((Visitor.BlockStatementVisitor) visitor).visitSuperConstructorInvocation(this); } // Implement BlockStatement. @Override public void accept(Visitor.BlockStatementVisitor visitor) { visitor.visitSuperConstructorInvocation(this); } } /** Representation of a JLS7 15.12 'method invocation expression'. */ public static final class MethodInvocation extends Invocation { /** The optional type or rvalue that qualifies this method invocation. */ public final Atom optionalTarget; public MethodInvocation(Location location, Atom optionalTarget, String methodName, Rvalue[] arguments) { super(location, methodName, arguments); this.optionalTarget = optionalTarget; } // Implement "Atom". /** The resolved {@link IMethod}. */ IClass.IMethod iMethod; @Override public String toString() { StringBuilder sb = new StringBuilder(); if (this.optionalTarget != null) sb.append(this.optionalTarget.toString()).append('.'); sb.append(this.methodName).append('('); for (int i = 0; i < this.arguments.length; ++i) { if (i > 0) sb.append(", "); sb.append(this.arguments[i].toString()); } sb.append(')'); return sb.toString(); } @Override public void accept(Visitor.AtomVisitor visitor) { visitor.visitMethodInvocation(this); } @Override public void accept(Visitor.RvalueVisitor visitor) { visitor.visitMethodInvocation(this); } @Override public void accept(ElementValueVisitor visitor) { visitor.visitMethodInvocation(this); } } /** Representation of a JLS7 15.12.1.1.3 'superclass method invocation'. */ public static final class SuperclassMethodInvocation extends Invocation { public SuperclassMethodInvocation(Location location, String methodName, Rvalue[] arguments) { super(location, methodName, arguments); } // Implement "Atom". @Override public String toString() { return "super." + this.methodName + "()"; } @Override public void accept(Visitor.AtomVisitor visitor) { visitor.visitSuperclassMethodInvocation(this); } @Override public void accept(Visitor.RvalueVisitor visitor) { visitor.visitSuperclassMethodInvocation(this); } @Override public void accept(ElementValueVisitor visitor) { visitor.visitSuperclassMethodInvocation(this); } } /** Abstract base class for {@link MethodInvocation} and {@link SuperclassMethodInvocation}. */ public abstract static class Invocation extends Rvalue { /** name of the invoked method. */ public final String methodName; /** Arguments to pass to the method. */ public final Rvalue[] arguments; protected Invocation(Location location, String methodName, Rvalue[] arguments) { super(location); this.methodName = methodName; this.arguments = arguments; } } /** Representation of a JLS7 'class instance creation expression'. */ public static final class NewClassInstance extends Rvalue { /** The qualification of this 'qualified class instance creation expression'. */ public final Rvalue optionalQualification; /** The type to instantiate. */ public final Type type; /** The arguments to pass to the constructor. */ public final Rvalue[] arguments; public NewClassInstance(Location location, Rvalue optionalQualification, Type type, Rvalue[] arguments) { super(location); this.optionalQualification = optionalQualification; this.type = type; this.arguments = arguments; } // Compile time members. /** The resolved {@link #type}. */ protected IClass iClass; public NewClassInstance(Location location, Rvalue optionalQualification, IClass iClass, Rvalue[] arguments) { super(location); this.optionalQualification = optionalQualification; this.type = null; this.arguments = arguments; this.iClass = iClass; } // Implement "Atom". @Override public String toString() { StringBuilder sb = new StringBuilder(); if (this.optionalQualification != null) sb.append(this.optionalQualification.toString()).append('.'); sb.append("new "); if (this.type != null) { sb.append(this.type.toString()); } else if (this.iClass != null) { sb.append(this.iClass.toString()); } else { sb.append("???"); } sb.append('('); for (int i = 0; i < this.arguments.length; ++i) { if (i > 0) sb.append(", "); sb.append(this.arguments[i].toString()); } sb.append(')'); return sb.toString(); } @Override public void accept(Visitor.AtomVisitor visitor) { visitor.visitNewClassInstance(this); } @Override public void accept(Visitor.RvalueVisitor visitor) { visitor.visitNewClassInstance(this); } @Override public void accept(ElementValueVisitor visitor) { visitor.visitNewClassInstance(this); } } /** Representation of a JLS7 15.9 'anonymous class instance creation expression'. */ public static final class NewAnonymousClassInstance extends Rvalue { /** The qualification iff this a 'qualified anonymous class instance creation expression'. */ public final Rvalue optionalQualification; /** The declaration of the anonymous class to instantiate. */ public final AnonymousClassDeclaration anonymousClassDeclaration; /** The arguments to pass to the constructor. */ public final Rvalue[] arguments; public NewAnonymousClassInstance( Location location, Rvalue optionalQualification, AnonymousClassDeclaration anonymousClassDeclaration, Rvalue[] arguments ) { super(location); this.optionalQualification = optionalQualification; this.anonymousClassDeclaration = anonymousClassDeclaration; this.arguments = arguments; } // Implement "Atom". @Override public String toString() { StringBuilder sb = new StringBuilder(); if (this.optionalQualification != null) sb.append(this.optionalQualification.toString()).append('.'); sb.append("new ").append(this.anonymousClassDeclaration.baseType.toString()).append("() { ... }"); return sb.toString(); } @Override public void accept(Visitor.AtomVisitor visitor) { visitor.visitNewAnonymousClassInstance(this); } @Override public void accept(Visitor.RvalueVisitor visitor) { visitor.visitNewAnonymousClassInstance(this); } @Override public void accept(ElementValueVisitor visitor) { visitor.visitNewAnonymousClassInstance(this); } } /** 'Artificial' operation for accessing the parameters of the synthetic constructor of an anonymous class. */ public static final class ParameterAccess extends Rvalue { /** The parameter to access. */ public final FormalParameter formalParameter; public ParameterAccess(Location location, FormalParameter formalParameter) { super(location); this.formalParameter = formalParameter; } // Implement Atom @Override public String toString() { return this.formalParameter.name; } @Override public void accept(Visitor.AtomVisitor visitor) { visitor.visitParameterAccess(this); } @Override public void accept(Visitor.RvalueVisitor visitor) { visitor.visitParameterAccess(this); } @Override public void accept(ElementValueVisitor visitor) { visitor.visitParameterAccess(this); } } /** Representation of a JLS7 15.10 'array creation expression'. */ public static final class NewArray extends Rvalue { /** * The component type of the ({@link #dimExprs}{@code .length + }{@link #dims})-dimensional array to * instantiate. */ public final Type type; /** The sizes of the first dimensions to instantiate. */ public final Rvalue[] dimExprs; /** The count of additional dimensions that the array should have. */ public final int dims; /** * Create a new array with dimension dimExprs.length + dims *

* e.g. byte[12][][] is created with *

         *     new NewArray(
         *         null,
         *         Java.BasicType(NULL, Java.BasicType.BYTE),
         *         new Rvalue[] { new Java.Literal(null, Integer.valueOf(12) },
         *         2
         *     )
         * 
* * @param location the location of this element * @param type the base type of the array * @param dimExprs sizes for dimensions being allocated with specific sizes * @param dims the number of dimensions that are not yet allocated */ public NewArray(Location location, Type type, Rvalue[] dimExprs, int dims) { super(location); this.type = type; this.dimExprs = dimExprs; this.dims = dims; } // Implement "Atom". @Override public String toString() { return "new " + this.type.toString() + "[]..."; } @Override public void accept(Visitor.AtomVisitor visitor) { visitor.visitNewArray(this); } // Implement "Rvalue". @Override public void accept(Visitor.RvalueVisitor visitor) { visitor.visitNewArray(this); } @Override public void accept(ElementValueVisitor visitor) { visitor.visitNewArray(this); } } /** Representation of a JLS7 15.10 'array creation expression'. */ public static final class NewInitializedArray extends Rvalue { /** The array type to be instantiated. */ public final ArrayType arrayType; /** The (mandatory) initializer for the array. */ public final ArrayInitializer arrayInitializer; /** The resolved {@link #arrayType}. */ public final IClass arrayIClass; public NewInitializedArray(Location location, ArrayType arrayType, ArrayInitializer arrayInitializer) { super(location); this.arrayType = arrayType; this.arrayInitializer = arrayInitializer; this.arrayIClass = null; } NewInitializedArray(Location location, IClass arrayIClass, ArrayInitializer arrayInitializer) { super(location); this.arrayType = null; this.arrayInitializer = arrayInitializer; this.arrayIClass = arrayIClass; } // Implement "Atom". @Override public String toString() { return "new " + this.arrayType.toString() + " { ... }"; } @Override public void accept(Visitor.AtomVisitor visitor) { visitor.visitNewInitializedArray(this); } // Implement "Rvalue". @Override public void accept(Visitor.RvalueVisitor visitor) { visitor.visitNewInitializedArray(this); } @Override public void accept(ElementValueVisitor visitor) { visitor.visitNewInitializedArray(this); } } /** * Representation of a JLS7 10.6 'array initializer'. *

* Allocates an array and initializes its members with (not necessarily * constant) values. */ public static final class ArrayInitializer extends Located implements ArrayInitializerOrRvalue { /** The values to assign to the array elements. */ public final ArrayInitializerOrRvalue[] values; public ArrayInitializer(Location location, ArrayInitializerOrRvalue[] values) { super(location); this.values = values; } @Override public String toString() { return " { (" + this.values.length + " values) }"; } } /** The union of {@link ArrayInitializer} and {@link Rvalue}. */ public interface ArrayInitializerOrRvalue extends Locatable { } /** Abstract base class for the various Java™ literals; see JLS7 3.10. */ public abstract static class Literal extends Rvalue { /** The text of the literal token, as in the source code. */ public final String value; /** @param value The text of the literal token, as in the source code */ public Literal(Location location, String value) { super(location); this.value = value; } // Implement "Atom". @Override public String toString() { return this.value; } } /** Representation of an "integer literal" (JLS7 3.10.1) (types {@code int} and {@code long}). */ public static final class IntegerLiteral extends Literal { public IntegerLiteral(Location location, String value) { super(location, value); } @Override public void accept(Visitor.AtomVisitor visitor) { visitor.visitIntegerLiteral(this); } @Override public void accept(Visitor.RvalueVisitor visitor) { visitor.visitIntegerLiteral(this); } @Override public void accept(ElementValueVisitor visitor) { visitor.visitIntegerLiteral(this); } } /** Representation of a "floating-point literal" (JLS7 3.10.2) (types {@code float} and {@code double}). */ public static final class FloatingPointLiteral extends Literal { public FloatingPointLiteral(Location location, String value) { super(location, value); } @Override public void accept(Visitor.AtomVisitor visitor) { visitor.visitFloatingPointLiteral(this); } @Override public void accept(Visitor.RvalueVisitor visitor) { visitor.visitFloatingPointLiteral(this); } @Override public void accept(ElementValueVisitor visitor) { visitor.visitFloatingPointLiteral(this); } } /** Representation of a "boolean literal" (JLS7 3.10.3) (type {@code boolean}). */ public static final class BooleanLiteral extends Literal { public BooleanLiteral(Location location, String value) { super(location, value); } @Override public void accept(Visitor.AtomVisitor visitor) { visitor.visitBooleanLiteral(this); } @Override public void accept(Visitor.RvalueVisitor visitor) { visitor.visitBooleanLiteral(this); } @Override public void accept(ElementValueVisitor visitor) { visitor.visitBooleanLiteral(this); } } /** Representation of a "character literal" (JLS7 3.10.4) (type {@code char}). */ public static final class CharacterLiteral extends Literal { public CharacterLiteral(Location location, String value) { super(location, value); } @Override public void accept(Visitor.AtomVisitor visitor) { visitor.visitCharacterLiteral(this); } @Override public void accept(Visitor.RvalueVisitor visitor) { visitor.visitCharacterLiteral(this); } @Override public void accept(ElementValueVisitor visitor) { visitor.visitCharacterLiteral(this); } } /** Representation of a "string literal" (JLS7 3.10.5) (type {@link String}). */ public static final class StringLiteral extends Literal { public StringLiteral(Location location, String value) { super(location, value); } @Override public void accept(Visitor.AtomVisitor visitor) { visitor.visitStringLiteral(this); } @Override public void accept(Visitor.RvalueVisitor visitor) { visitor.visitStringLiteral(this); } @Override public void accept(ElementValueVisitor visitor) { visitor.visitStringLiteral(this); } } /** Representation of a "null literal" (JLS7 3.10.7). */ public static final class NullLiteral extends Literal { public NullLiteral(Location location, String value) { super(location, value); } @Override public void accept(Visitor.AtomVisitor visitor) { visitor.visitNullLiteral(this); } @Override public void accept(Visitor.RvalueVisitor visitor) { visitor.visitNullLiteral(this); } @Override public void accept(ElementValueVisitor visitor) { visitor.visitNullLiteral(this); } } /** This class is not used when code is parsed; it is intended for "programmatic" literals. */ public static final class SimpleConstant extends Rvalue { /** * The value represented by this constant; either {@code null} (representing the {@code null} literal), a * {@link Byte}, {@link Short}, {@link Integer}, {@link Long}, {@link Float}, {@link Double}, {@link * Character}, {@link Boolean} or {@link String}. * * @see #SimpleConstant(Location) * @see #SimpleConstant(Location,byte) * @see #SimpleConstant(Location,short) * @see #SimpleConstant(Location,int) * @see #SimpleConstant(Location,long) * @see #SimpleConstant(Location,float) * @see #SimpleConstant(Location,double) * @see #SimpleConstant(Location,char) * @see #SimpleConstant(Location,boolean) * @see #SimpleConstant(Location,String) */ final Object value; /** Equivalent of the {@code null} literal. */ public SimpleConstant(Location location) { super(location); this.value = null; } /** Equivalent of an literal, casted to {@code byte}. */ public SimpleConstant(Location location, byte value) { super(location); this.value = value; } /** Equivalent of an literal, casted to {@code short}. */ public SimpleConstant(Location location, short value) { super(location); this.value = value; } /** Equivalent of an {@link IntegerLiteral} with type {@code int}. */ public SimpleConstant(Location location, int value) { super(location); this.value = value; } /** Equivalent of an {@link IntegerLiteral} with type {@code long}. */ public SimpleConstant(Location location, long value) { super(location); this.value = value; } /** * Equivalent of a {@link FloatingPointLiteral} with type {@code float}. * Notice that this class supports the special values {@link Float#NaN}, {@link Float#NEGATIVE_INFINITY} and * {@link Float#POSITIVE_INFINITY}, which can not be represented with a {@link FloatingPointLiteral}. */ public SimpleConstant(Location location, float value) { super(location); this.value = value; } /** * Equivalent of a {@link FloatingPointLiteral} with type {@code double}. * Notice that this class supports the special values {@link Double#NaN}, {@link Double#NEGATIVE_INFINITY} and * {@link Double#POSITIVE_INFINITY}, which can not be represented with a {@link FloatingPointLiteral}. */ public SimpleConstant(Location location, double value) { super(location); this.value = value; } /** Equivalent of a {@link CharacterLiteral}. */ public SimpleConstant(Location location, char value) { super(location); this.value = value; } /** Equivalent of a {@link BooleanLiteral}. */ public SimpleConstant(Location location, boolean value) { super(location); this.value = value; } /** * Equivalent of a {@link StringLiteral}, or, if {@code value} is null, the equivalent of a {@link * NullLiteral}. */ public SimpleConstant(Location location, String value) { super(location); this.value = value; } @Override public void accept(Visitor.AtomVisitor visitor) { visitor.visitSimpleConstant(this); } @Override public void accept(Visitor.RvalueVisitor visitor) { visitor.visitSimpleConstant(this); } @Override public void accept(ElementValueVisitor visitor) { visitor.visitSimpleConstant(this); } @Override public String toString() { return "[" + this.value + ']'; } } /** * All local variables have a slot number; local variables that get written into the 'localvariabletable' * also have a start and end offset that defines the variable's extent in the bytecode. If the name is null, * or variable debugging is not on, then the variable won't be written into the localvariabletable and the * offsets can be ignored. */ public static class LocalVariableSlot { private short slotIndex = -1; private String name; private final IClass type; private Offset start, end; public LocalVariableSlot(String name, short slotNumber, IClass type) { this.name = name; this.slotIndex = slotNumber; this.type = type; } @Override public String toString() { StringBuilder buf = new StringBuilder("local var(").append(this.name).append(", ").append(this.slotIndex); if (this.name != null) { buf.append(", ").append(this.type); buf.append(", ").append(this.start.offset); buf.append(", ").append(this.end.offset); } buf.append(")"); return buf.toString(); } /** @return The 'local variable index' associated with this local variable */ public short getSlotIndex() { return this.slotIndex; } /** @param slotIndex The 'local variable index' to associate with this local variable */ public void setSlotIndex(short slotIndex) { this.slotIndex = slotIndex; } /** @return The name of this local variable */ public String getName() { return this.name; } /** @param name The name of this local variable */ public void setName(String name) { this.name = name; } /** @return The {@link Offset} from which this local variable is visible */ public Offset getStart() { return this.start; } /** @param start The {@link Offset} from which this local variable is visible */ public void setStart(Offset start) { this.start = start; } /** @return The {@link Offset} up to which this local variable is visible */ public Offset getEnd() { return this.end; } /** @param end The {@link Offset} up to which this local variable is visible */ public void setEnd(Offset end) { this.end = end; } /** @return the resolved type of this local variable */ public IClass getType() { return this.type; } } /** Representation of a local variable while it is in scope during compilation. */ public static class LocalVariable { /** Whether this local variable has the FINAL modifier flag. */ public final boolean finaL; /** The type of this local variable. */ public final IClass type; /** The slot reserved for this local variable. */ public LocalVariableSlot slot; public LocalVariable(boolean finaL, IClass type) { this.finaL = finaL; this.type = type; } @Override public String toString() { StringBuilder sb = new StringBuilder(); if (this.finaL) sb.append("final "); sb.append(this.type).append(" "); return sb.toString(); } /** @param slot The slot to reserve for this local variable */ public void setSlot(LocalVariableSlot slot) { this.slot = slot; } /** @return The slot reserved for this local variable */ public short getSlotIndex() { if (this.slot == null) return -1; return this.slot.getSlotIndex(); } } /** Representation of a JLS7 4.5.1 'wildcard'. */ public static class Wildcard implements TypeArgument { /** * Value for {@link #bounds} indicating that this wildcard has no bounds; {@link #referenceType} is irrelevant * in this case. */ public static final int BOUNDS_NONE = 0; /** Value for {@link #bounds} indicating that this wildcard has 'extends' bounds. */ public static final int BOUNDS_EXTENDS = 1; /** Value for {@link #bounds} indicating that this wildcard has 'super' bounds. */ public static final int BOUNDS_SUPER = 2; /** * The kind of bounds that this wildcard has. * * @see #BOUNDS_NONE * @see #BOUNDS_EXTENDS * @see #BOUNDS_SUPER */ public final int bounds; /** The reference type of this wildcard's EXTENDS or SUPER bounds. */ public final ReferenceType referenceType; public Wildcard() { this.bounds = Wildcard.BOUNDS_NONE; this.referenceType = null; } public Wildcard(int bounds, ReferenceType referenceType) { assert bounds == Wildcard.BOUNDS_EXTENDS || bounds == Wildcard.BOUNDS_SUPER; this.bounds = bounds; assert referenceType != null; this.referenceType = referenceType; } @Override public void accept(TypeArgumentVisitor visitor) { visitor.visitWildcard(this); } @Override public String toString() { return ( this.bounds == Wildcard.BOUNDS_EXTENDS ? "? extends " + this.referenceType : this.bounds == Wildcard.BOUNDS_SUPER ? "? super " + this.referenceType : "?" ); } } /** * @return {@code null} iff {@code a == null}, or "" iff {@code a.length == 0}, or the elements of {@code a}, * converted to strings concatenated and separated with the {@code separator} */ public static String join(Object[] a, String separator) { return Java.join(a, separator, 0, a.length); } /** * @return {@code null} iff {@code a == null}, or "" iff {@code off >= len}, or element {@code off ... len-1} of * {@code a}, converted to strings concatenated and separated with the {@code separator} */ public static String join(Object[] a, String separator, int off, int len) { if (a == null) return ("(null)"); if (off >= len) return ""; StringBuilder sb = new StringBuilder(a[off].toString()); for (++off; off < len; ++off) { sb.append(separator); sb.append(a[off]); } return sb.toString(); } }